@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.js CHANGED
@@ -233,6 +233,11 @@ function useFloatingPanel(anchorRef, isOpen, {
233
233
 
234
234
  // src/hooks/useTableState.ts
235
235
  import { useCallback as useCallback4, useMemo as useMemo2, useState as useState4 } from "react";
236
+ var isEmptyFilterValue = (value) => {
237
+ if (value === void 0 || value === null || value === "") return true;
238
+ if (Array.isArray(value)) return value[0] == null && value[1] == null;
239
+ return false;
240
+ };
236
241
  function useTableState({
237
242
  defaultItemsPerPage = 10,
238
243
  initialSort = null
@@ -257,7 +262,7 @@ function useTableState({
257
262
  const handleFilterChange = useCallback4(
258
263
  (key, value) => {
259
264
  setFilters((prev) => {
260
- if (value === void 0 || value === null || value === "") {
265
+ if (isEmptyFilterValue(value)) {
261
266
  const next = { ...prev };
262
267
  delete next[key];
263
268
  return next;
@@ -3595,9 +3600,9 @@ function useVirtualRows({
3595
3600
  }
3596
3601
 
3597
3602
  // src/components/organisms/data-table/dataTable.tsx
3598
- import clsx21 from "clsx";
3599
- import { useState as useState17, useEffect as useEffect7, useCallback as useCallback7, useRef as useRef11 } from "react";
3600
- import { FaCheck as FaCheck2, FaSpinner, FaTimes as FaTimes4, FaTable, FaThLarge } from "react-icons/fa";
3603
+ import clsx23 from "clsx";
3604
+ import React6, { useState as useState19, useEffect as useEffect9, useCallback as useCallback7, useRef as useRef13 } from "react";
3605
+ import { FaCheck as FaCheck2, FaSpinner, FaTimes as FaTimes5, FaTable, FaThLarge } from "react-icons/fa";
3601
3606
  import { MdOutlineSwapVert } from "react-icons/md";
3602
3607
 
3603
3608
  // src/components/molecules/pagination/pagination.tsx
@@ -3890,445 +3895,240 @@ function ITPagination({
3890
3895
  return /* @__PURE__ */ jsx20("nav", { "aria-label": "Pagination", className: clsx20("inline-flex", className), children: renderPaginationControls() });
3891
3896
  }
3892
3897
 
3893
- // src/utils/table.utils.ts
3894
- var formatCurrencyMX = (value) => {
3895
- return value.toLocaleString("es-MX", {
3896
- style: "currency",
3897
- currency: "MXN"
3898
- });
3899
- };
3900
- var getNestedValue = (obj, path) => {
3901
- return path.split(".").reduce((acc, part) => acc && acc[part], obj);
3902
- };
3903
- var ROW_CLICK_IGNORE_SELECTOR = 'button, a, input, select, textarea, [role="button"], [role="link"], [data-row-click-ignore]';
3904
- function isInteractiveTarget(target, boundary = null) {
3905
- if (!(target instanceof Element)) return false;
3906
- const interactive = target.closest(ROW_CLICK_IGNORE_SELECTOR);
3907
- if (!interactive) return false;
3908
- if (boundary instanceof Node && interactive === boundary) return false;
3909
- return true;
3910
- }
3911
-
3912
- // src/components/organisms/data-table/dataTable.tsx
3913
- import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
3914
- var getNestedValue2 = (obj, path) => {
3915
- return path.split(".").reduce((acc, part) => acc && acc[part], obj);
3916
- };
3917
- var EMPTY_OBJECT = {};
3918
- function ITDataTable({
3919
- columns,
3920
- fetchData,
3921
- debounceMs = 500,
3922
- externalFilters = EMPTY_OBJECT,
3923
- loadingIndicator,
3924
- fetchOnMount = true,
3925
- reloadTrigger,
3926
- containerClassName,
3898
+ // src/components/molecules/search-select/search-select.tsx
3899
+ import { useState as useState17, useEffect as useEffect7, useRef as useRef11, useMemo as useMemo7 } from "react";
3900
+ import { createPortal as createPortal3 } from "react-dom";
3901
+ import clsx21 from "clsx";
3902
+ import { FaSearch as FaSearch2, FaTimes as FaTimes4 } from "react-icons/fa";
3903
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
3904
+ function ITSearchSelect({
3905
+ name,
3906
+ options = [],
3907
+ label,
3908
+ placeholder = "Selecciona una opci\xF3n",
3909
+ valueField = "value",
3910
+ labelField = "label",
3911
+ value,
3912
+ onChange,
3913
+ onBlur,
3914
+ disabled = false,
3927
3915
  className,
3928
- variant = "default",
3916
+ touched,
3917
+ required,
3918
+ error,
3919
+ readOnly = false,
3920
+ onSearch,
3921
+ isLoading = false,
3922
+ noResultsMessage = "No se encontraron resultados",
3929
3923
  size = "md",
3930
- itemsPerPageOptions = [5, 10, 20],
3931
- defaultItemsPerPage = 10,
3932
- title,
3933
- renderCard,
3934
- defaultView,
3935
- showVerticalBorder = true,
3936
- verticalBorderClassname,
3937
- onRowClick,
3938
- layout = "auto",
3939
- density = "normal",
3940
- autoCardBreakpoint = 0,
3941
- virtualized = false,
3942
- virtualizedMaxHeight = 400,
3943
- rowHeight,
3944
- overscan = 5,
3945
- stickyHeader = false
3924
+ renderOption,
3925
+ clearable = true,
3926
+ onClear
3946
3927
  }) {
3947
- const [viewMode, setViewMode] = useState17(defaultView || "table");
3948
- const { ref: rootRef, width: containerWidth } = useElementSize();
3949
- const [data, setData] = useState17([]);
3950
- const [totalItems, setTotalItems] = useState17(0);
3951
- const [isLoading, setIsLoading] = useState17(fetchOnMount);
3952
- const isFixed = layout === "fixed";
3953
- const forcedCards = autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
3954
- const effectiveView = forcedCards ? "cards" : viewMode;
3955
- const hasColumnWidths = columns.some((col) => col.width != null);
3956
- 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";
3957
- const isTableVirtual = virtualized && effectiveView === "table";
3958
- const isStickyHeader = stickyHeader && isTableVirtual;
3959
- const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
3960
- const columnCount = columns.length;
3961
- const scrollOuterClass = isTableVirtual ? "relative min-h-[200px]" : "overflow-x-auto relative min-h-[200px]";
3962
- const {
3963
- currentPage,
3964
- itemsPerPage,
3965
- filters,
3966
- sortConfig,
3967
- goToPage,
3968
- handleFilterChange,
3969
- handleSort,
3970
- handleItemsPerPageChange
3971
- } = useTableState({ defaultItemsPerPage });
3972
- const {
3973
- scrollRef,
3974
- startIndex,
3975
- endIndex,
3976
- topSpacerHeight,
3977
- bottomSpacerHeight
3978
- } = useVirtualRows({
3979
- count: data.length,
3980
- rowHeight: resolvedRowHeight,
3981
- overscan,
3982
- enabled: isTableVirtual,
3983
- resetKey: `${currentPage}-${itemsPerPage}`
3928
+ const [isOpen, setIsOpen] = useState17(false);
3929
+ const [searchTerm, setSearchTerm] = useState17("");
3930
+ const [isFocused, setIsFocused] = useState17(false);
3931
+ const [localTouched, setLocalTouched] = useState17(false);
3932
+ const containerRef = useRef11(null);
3933
+ const inputWrapperRef = useRef11(null);
3934
+ const timeoutRef = useRef11(null);
3935
+ const { panelRef, style: panelStyle } = useFloatingPanel(inputWrapperRef, isOpen, {
3936
+ estimatedHeight: 260,
3937
+ matchWidth: true
3984
3938
  });
3985
- const windowData = isTableVirtual ? data.slice(startIndex, endIndex + 1) : data;
3986
- const debounceTimerRef = useRef11(null);
3987
- const hasFetchedRef = useRef11(false);
3988
- const fetchDataRef = useRef11(fetchData);
3989
- fetchDataRef.current = fetchData;
3990
- const externalFiltersRef = useRef11(externalFilters);
3991
- externalFiltersRef.current = externalFilters;
3992
- const externalKey = JSON.stringify(externalFilters);
3993
- const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
3994
- const performFetch = useCallback7(async () => {
3995
- setIsLoading(true);
3996
- try {
3997
- const response = await fetchDataRef.current({
3998
- page: currentPage,
3999
- limit: itemsPerPage,
4000
- filters: { ...filters, ...externalFiltersRef.current },
4001
- sort: sortConfig || void 0
4002
- });
4003
- setData(response.data || []);
4004
- setTotalItems(response.total || 0);
4005
- hasFetchedRef.current = true;
4006
- } catch (error) {
4007
- console.error("ITDataTable: Error fetching data", error);
4008
- setData([]);
4009
- setTotalItems(0);
4010
- hasFetchedRef.current = true;
4011
- } finally {
4012
- setIsLoading(false);
4013
- }
4014
- }, [currentPage, itemsPerPage, filters, sortConfig]);
4015
- const performFetchRef = useRef11(performFetch);
4016
- performFetchRef.current = performFetch;
3939
+ const selectedOption = useMemo7(() => {
3940
+ return options.find((opt) => opt[valueField] === value);
3941
+ }, [options, value, valueField]);
4017
3942
  useEffect7(() => {
4018
- if (!fetchOnMount && !hasFetchedRef.current) return;
4019
- if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4020
- debounceTimerRef.current = setTimeout(() => {
4021
- performFetchRef.current();
4022
- }, debounceMs);
4023
- return () => {
4024
- if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4025
- };
4026
- }, [currentPage, itemsPerPage, sortConfig, filters, externalKey, reloadTrigger, fetchOnMount, debounceMs]);
4027
- const renderFilterInput = (col) => {
4028
- if (!col.filter) return null;
4029
- if (col.type === "boolean") {
4030
- const currentValue = filters[col.key];
4031
- const nextValue = currentValue === void 0 ? true : currentValue === true ? false : void 0;
4032
- const getToggleLabel = () => {
4033
- if (currentValue === void 0) return "Mostrar todos";
4034
- if (currentValue === true) return "Filtrar solo verdaderos";
4035
- return "Filtrar solo falsos";
4036
- };
4037
- return /* @__PURE__ */ jsx21(
4038
- "button",
4039
- {
4040
- 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",
4041
- onClick: () => handleFilterChange(col.key, nextValue),
4042
- "aria-label": `${getToggleLabel()} para ${col.label}`,
4043
- title: `${getToggleLabel()} para ${col.label}`,
4044
- disabled: isLoading,
4045
- children: /* @__PURE__ */ jsx21("div", { className: "relative w-10 h-5 bg-secondary-300 rounded-full", children: /* @__PURE__ */ jsx21(
4046
- "div",
4047
- {
4048
- className: clsx21(
4049
- "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
4050
- {
4051
- "left-0.5 bg-secondary-400": currentValue === void 0,
4052
- "left-5 bg-slate-500": currentValue === true,
4053
- "left-0.5 bg-secondary-500": currentValue === false
4054
- }
4055
- )
4056
- }
4057
- ) })
4058
- }
4059
- );
3943
+ if (!isFocused) {
3944
+ setSearchTerm(selectedOption ? String(selectedOption[labelField]) : "");
4060
3945
  }
4061
- if (col.filter === "catalog" && col.catalogOptions) {
4062
- if (col.catalogOptions.loading) {
4063
- return /* @__PURE__ */ jsx21(FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4064
- }
4065
- if (col.catalogOptions.error) {
4066
- return /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
3946
+ }, [selectedOption, isFocused, labelField]);
3947
+ useEffect7(() => {
3948
+ function handleClickOutside(event) {
3949
+ const target = event.target;
3950
+ const inContainer = containerRef.current?.contains(target);
3951
+ const inPanel = panelRef.current?.contains(target);
3952
+ if (!inContainer && !inPanel) {
3953
+ setIsOpen(false);
4067
3954
  }
4068
- return /* @__PURE__ */ jsx21(
4069
- ITSelect,
4070
- {
4071
- name: `filter-${col.key}`,
4072
- options: [
4073
- { value: "", label: "Todos" },
4074
- ...col.catalogOptions.data.map((item) => ({
4075
- value: String(item.id),
4076
- label: item.name
4077
- }))
4078
- ],
4079
- value: String(filters[col.key] || ""),
4080
- onChange: (e) => {
4081
- const value = e.target.value === "" ? void 0 : e.target.value;
4082
- handleFilterChange(col.key, value);
4083
- },
4084
- onBlur: () => {
4085
- },
4086
- className: "w-full text-xs",
4087
- disabled: isLoading
4088
- }
4089
- );
4090
3955
  }
4091
- return /* @__PURE__ */ jsx21(
4092
- ITInput,
4093
- {
4094
- name: `filter-${col.key}`,
4095
- className: "w-full text-xs",
4096
- placeholder: "Buscar...",
4097
- value: String(filters[col.key] || ""),
4098
- onChange: (e) => handleFilterChange(col.key, e.target.value),
4099
- onBlur: () => {
4100
- },
4101
- disabled: isLoading
4102
- }
3956
+ document.addEventListener("mousedown", handleClickOutside);
3957
+ return () => document.removeEventListener("mousedown", handleClickOutside);
3958
+ }, []);
3959
+ const selectedLabel = selectedOption ? String(selectedOption[labelField]) : "";
3960
+ const filteredOptions = useMemo7(() => {
3961
+ if (onSearch) return options;
3962
+ if (!searchTerm || !isFocused || searchTerm === selectedLabel) return options;
3963
+ return options.filter(
3964
+ (opt) => String(opt[labelField]).toLowerCase().includes(searchTerm.toLowerCase())
4103
3965
  );
3966
+ }, [options, searchTerm, selectedLabel, onSearch, labelField, isFocused]);
3967
+ const handleInputChange = (e) => {
3968
+ const query = e.target.value;
3969
+ setSearchTerm(query);
3970
+ setIsOpen(true);
3971
+ if (onSearch) {
3972
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
3973
+ timeoutRef.current = setTimeout(() => {
3974
+ onSearch(query);
3975
+ }, 500);
3976
+ }
4104
3977
  };
4105
- const renderCellContent = (col, row) => {
4106
- const value = getNestedValue2(row, col.key);
4107
- if (col.render) return col.render(row);
4108
- switch (col.type) {
4109
- case "number":
4110
- return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
4111
- case "boolean":
4112
- return value ? /* @__PURE__ */ jsx21(FaCheck2, { className: "text-success-500", "aria-label": "Verdadero", title: "Verdadero" }) : /* @__PURE__ */ jsx21(FaTimes4, { className: "text-danger-500", "aria-label": "Falso", title: "Falso" });
4113
- case "actions":
4114
- return col.actions ? col.actions(row) : null;
4115
- case "catalog":
4116
- if (col.catalogOptions) {
4117
- const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
4118
- return catalogItem?.name || value;
4119
- }
4120
- return value;
4121
- default:
4122
- return value;
3978
+ const handleSelect = (option) => {
3979
+ if (onChange) {
3980
+ onChange(option[valueField], option);
4123
3981
  }
3982
+ setSearchTerm(String(option[labelField]));
3983
+ setIsOpen(false);
4124
3984
  };
4125
- const renderDefaultCard = (row) => {
4126
- const dataCols = columns.filter((c) => c.type !== "actions");
4127
- const actionCol = columns.find((c) => c.type === "actions");
4128
- return /* @__PURE__ */ jsxs18("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: [
4129
- dataCols.map((col) => /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between gap-2", children: [
4130
- /* @__PURE__ */ jsx21("span", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 whitespace-nowrap flex-shrink-0 min-w-[70px]", children: col.label }),
4131
- /* @__PURE__ */ jsx21("span", { className: "text-sm font-medium text-slate-800 dark:text-white text-right truncate", children: renderCellContent(col, row) })
4132
- ] }, col.key)),
4133
- actionCol?.actions && /* @__PURE__ */ jsx21("div", { className: "flex items-center justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-700", children: actionCol.actions(row) })
4134
- ] });
3985
+ const handleClear = () => {
3986
+ setSearchTerm("");
3987
+ setIsOpen(true);
3988
+ if (onSearch) onSearch("");
3989
+ if (value !== void 0 && value !== null && value !== "") {
3990
+ onChange?.("", void 0);
3991
+ }
3992
+ onClear?.();
4135
3993
  };
4136
- 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"}`;
4137
- const handleRowClick = (row) => (event) => {
4138
- if (!onRowClick || isLoading || isInteractiveTarget(event.target, event.currentTarget)) return;
4139
- onRowClick(row, event);
3994
+ const handleFocus = () => {
3995
+ if (disabled || readOnly) return;
3996
+ setIsFocused(true);
3997
+ setIsOpen(true);
4140
3998
  };
4141
- const handleRowKeyDown = (row) => (event) => {
4142
- if (!onRowClick || isLoading) return;
4143
- if (event.target !== event.currentTarget) return;
4144
- if (event.key !== "Enter" && event.key !== " ") return;
4145
- event.preventDefault();
4146
- onRowClick(row, event);
3999
+ const handleInputBlur = (e) => {
4000
+ setTimeout(() => {
4001
+ setIsFocused(false);
4002
+ setLocalTouched(true);
4003
+ onBlur?.(e);
4004
+ }, 200);
4147
4005
  };
4148
- const tableEl = /* @__PURE__ */ jsxs18(
4149
- "table",
4150
- {
4151
- className: clsx21(
4152
- tableLayoutClass,
4153
- showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
4154
- showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
4155
- isLoading ? "opacity-50" : "opacity-100",
4156
- variantStyles[variant],
4157
- sizeStyles[size],
4158
- className
4159
- ),
4160
- style: isFixed ? { tableLayout: "fixed" } : void 0,
4161
- "aria-rowcount": isTableVirtual ? data.length + 1 : void 0,
4162
- children: [
4163
- hasColumnWidths && /* @__PURE__ */ jsx21("colgroup", { children: columns.map((col) => /* @__PURE__ */ jsx21(
4164
- "col",
4165
- {
4166
- style: col.width != null ? { width: typeof col.width === "number" ? `${col.width}px` : col.width } : void 0
4167
- },
4168
- col.key
4169
- )) }),
4170
- /* @__PURE__ */ jsx21("thead", { children: /* @__PURE__ */ jsx21(
4171
- "tr",
4006
+ const inputTheme = theme.input || {};
4007
+ const isTouched = touched !== void 0 ? touched : localTouched;
4008
+ const isEmpty = value === void 0 || value === null || String(value).trim() === "";
4009
+ const effectiveError = error !== void 0 && error !== false ? error === true ? "Este campo es requerido" : error : required && isEmpty ? "Este campo es requerido" : void 0;
4010
+ const hasError = isTouched && !!effectiveError;
4011
+ const errorMessage = typeof effectiveError === "string" ? effectiveError : "Este campo es requerido";
4012
+ const showClearButton = clearable && !disabled && !readOnly && (searchTerm.length > 0 || !isEmpty);
4013
+ const getInputStyle = () => {
4014
+ const sizeConfig = inputSizeTokens[size] ?? inputSizeTokens.md;
4015
+ const style = {
4016
+ backgroundColor: inputTheme.backgroundColor || "#ffffff",
4017
+ borderColor: inputTheme.borderColor || "var(--color-secondary-300)",
4018
+ borderRadius: inputTheme.borderRadius || "0.5rem",
4019
+ padding: sizeConfig.padding,
4020
+ fontSize: sizeConfig.fontSize,
4021
+ borderWidth: "1px",
4022
+ borderStyle: "solid",
4023
+ transition: "all 0.2s",
4024
+ color: "var(--it-input-text-color, var(--color-secondary-900))",
4025
+ width: "100%"
4026
+ };
4027
+ if (disabled) {
4028
+ style.backgroundColor = inputTheme.disabled?.backgroundColor || "var(--color-secondary-100)";
4029
+ style.borderColor = inputTheme.disabled?.borderColor || "var(--color-secondary-200)";
4030
+ style.opacity = 0.7;
4031
+ style.cursor = "not-allowed";
4032
+ }
4033
+ if (hasError) {
4034
+ style.borderColor = inputTheme.error?.borderColor || "red";
4035
+ if (isFocused) {
4036
+ style.boxShadow = inputTheme.error?.ring;
4037
+ }
4038
+ } else if (isFocused && !readOnly) {
4039
+ style.boxShadow = inputTheme.focus?.ring;
4040
+ style.borderColor = inputTheme.focus?.borderColor;
4041
+ }
4042
+ return style;
4043
+ };
4044
+ return /* @__PURE__ */ jsxs18("div", { className: clsx21("w-full flex flex-col gap-1.5", className, isOpen && "relative z-30"), ref: containerRef, children: [
4045
+ label && /* @__PURE__ */ jsxs18(
4046
+ ITText,
4047
+ {
4048
+ as: "label",
4049
+ className: clsx21("text-sm font-medium text-secondary-700 dark:text-slate-300", {
4050
+ "text-danger-500": hasError
4051
+ }),
4052
+ children: [
4053
+ /* @__PURE__ */ jsx21(ITText, { as: "span", children: label }),
4054
+ required && /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-danger-500 ml-1", children: "*" })
4055
+ ]
4056
+ }
4057
+ ),
4058
+ /* @__PURE__ */ jsxs18("div", { className: "relative", children: [
4059
+ /* @__PURE__ */ jsxs18("div", { ref: inputWrapperRef, className: "relative flex items-center", children: [
4060
+ /* @__PURE__ */ jsx21(
4061
+ "input",
4172
4062
  {
4173
- className: clsx21(tableHeaderRow, "dark:text-slate-200"),
4174
- "aria-rowindex": isTableVirtual ? 1 : void 0,
4175
- children: columns.map((col) => /* @__PURE__ */ jsx21(
4176
- "th",
4177
- {
4178
- scope: "col",
4179
- className: clsx21(
4180
- tableHeaderCell(col.className, density),
4181
- col.align && tableAlignClasses[col.align],
4182
- isStickyHeader && "sticky top-0 z-10 bg-secondary-50"
4183
- ),
4184
- style: col.minWidth != null || isStickyHeader ? {
4185
- ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4186
- ...isStickyHeader ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {}
4187
- } : void 0,
4188
- children: /* @__PURE__ */ jsxs18("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
4189
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center justify-between gap-2", children: [
4190
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
4191
- col.sortable && col.type !== "actions" && /* @__PURE__ */ jsx21(
4192
- "button",
4193
- {
4194
- onClick: () => handleSort(col.key),
4195
- disabled: isLoading,
4196
- 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`,
4197
- title: `Ordenar por ${col.label}`,
4198
- children: /* @__PURE__ */ jsx21(MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
4199
- }
4200
- )
4201
- ] }),
4202
- /* @__PURE__ */ jsx21("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
4203
- ] })
4204
- },
4205
- col.key
4206
- ))
4063
+ type: "text",
4064
+ name,
4065
+ value: searchTerm,
4066
+ onChange: handleInputChange,
4067
+ onFocus: handleFocus,
4068
+ onBlur: handleInputBlur,
4069
+ disabled,
4070
+ readOnly,
4071
+ placeholder,
4072
+ className: "outline-none pr-10",
4073
+ style: getInputStyle(),
4074
+ autoComplete: "off"
4207
4075
  }
4208
- ) }),
4209
- /* @__PURE__ */ jsx21("tbody", { className: clsx21(tableBody, "dark:divide-slate-700/30"), children: data.length > 0 ? /* @__PURE__ */ jsxs18(Fragment4, { children: [
4210
- isTableVirtual && topSpacerHeight > 0 && /* @__PURE__ */ jsx21("tr", { "aria-hidden": "true", style: { height: topSpacerHeight }, children: /* @__PURE__ */ jsx21("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) }),
4211
- windowData.map((row, windowIndex) => {
4212
- const absoluteIndex = isTableVirtual ? startIndex + windowIndex : windowIndex;
4213
- return /* @__PURE__ */ jsx21(
4214
- "tr",
4215
- {
4216
- "aria-rowindex": isTableVirtual ? absoluteIndex + 2 : void 0,
4217
- className: clsx21(
4218
- tableRow,
4219
- variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
4220
- onRowClick && !isLoading && tableRowClickable
4221
- ),
4222
- tabIndex: onRowClick && !isLoading ? 0 : void 0,
4223
- onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4224
- onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4225
- children: columns.map((col) => {
4226
- const rawValue = getNestedValue2(row, col.key);
4227
- const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
4228
- return /* @__PURE__ */ jsx21(
4229
- "td",
4230
- {
4231
- className: clsx21(
4232
- tableCell(col.className, density),
4233
- col.align && tableAlignClasses[col.align]
4234
- ),
4235
- style: col.minWidth != null ? { minWidth: `${col.minWidth}px` } : void 0,
4236
- title: truncateTitle,
4237
- children: col.type === "actions" ? /* @__PURE__ */ jsx21("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ jsx21("div", { className: clsx21(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
4238
- },
4239
- `${absoluteIndex}-${col.key}`
4240
- );
4241
- })
4076
+ ),
4077
+ /* @__PURE__ */ jsxs18("div", { className: "absolute right-3 flex items-center gap-2 text-secondary-400", children: [
4078
+ isLoading && /* @__PURE__ */ jsx21("div", { className: "pointer-events-none animate-spin h-4 w-4 border-2 border-primary-500 border-t-transparent rounded-full" }),
4079
+ !isLoading && showClearButton && /* @__PURE__ */ jsx21(
4080
+ "button",
4081
+ {
4082
+ type: "button",
4083
+ "aria-label": "Limpiar",
4084
+ title: "Limpiar",
4085
+ onMouseDown: (e) => {
4086
+ e.preventDefault();
4087
+ handleClear();
4242
4088
  },
4243
- absoluteIndex
4244
- );
4245
- }),
4246
- isTableVirtual && bottomSpacerHeight > 0 && /* @__PURE__ */ jsx21("tr", { "aria-hidden": "true", style: { height: bottomSpacerHeight }, children: /* @__PURE__ */ jsx21("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) })
4247
- ] }) : /* @__PURE__ */ jsx21("tr", { children: /* @__PURE__ */ jsx21("td", { colSpan: columns.length, className: "px-6 py-12 text-center", children: !isLoading && /* @__PURE__ */ jsxs18("div", { className: tableEmptyContent, children: [
4248
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4249
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4250
- ] }) }) }) })
4251
- ]
4252
- }
4253
- );
4254
- return /* @__PURE__ */ jsxs18("div", { ref: rootRef, className: clsx21("space-y-4 w-full relative", containerClassName), children: [
4255
- /* @__PURE__ */ jsxs18("div", { className: tableContainer, style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4256
- title && /* @__PURE__ */ jsxs18("div", { className: "px-6 py-5 flex items-center justify-between", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4257
- /* @__PURE__ */ jsx21(ITText, { as: "h2", className: "text-xl font-bold text-secondary-900 leading-tight", children: title }),
4258
- /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-3", children: [
4259
- isLoading && /* @__PURE__ */ jsx21("div", { className: "text-secondary-400", children: loadingIndicator || /* @__PURE__ */ jsx21(FaSpinner, { className: "animate-spin text-primary-500 text-xl" }) }),
4260
- /* @__PURE__ */ jsxs18("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: [
4261
- /* @__PURE__ */ jsxs18("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4262
- /* @__PURE__ */ jsx21(FaTable, { size: 11 }),
4263
- "Table"
4264
- ] }),
4265
- /* @__PURE__ */ jsxs18("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4266
- /* @__PURE__ */ jsx21(FaThLarge, { size: 11 }),
4267
- "Cards"
4268
- ] })
4269
- ] })
4089
+ 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",
4090
+ children: /* @__PURE__ */ jsx21(FaTimes4, { size: 14 })
4091
+ }
4092
+ ),
4093
+ !isLoading && !showClearButton && /* @__PURE__ */ jsx21(FaSearch2, { size: 14, className: clsx21("pointer-events-none", { "text-primary-500": isFocused }) })
4270
4094
  ] })
4271
4095
  ] }),
4272
- !title && /* @__PURE__ */ jsx21("div", { className: "flex justify-end px-4 pt-3", children: /* @__PURE__ */ jsxs18("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: [
4273
- /* @__PURE__ */ jsxs18("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4274
- /* @__PURE__ */ jsx21(FaTable, { size: 11 }),
4275
- "Table"
4276
- ] }),
4277
- /* @__PURE__ */ jsxs18("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4278
- /* @__PURE__ */ jsx21(FaThLarge, { size: 11 }),
4279
- "Cards"
4280
- ] })
4281
- ] }) }),
4282
- /* @__PURE__ */ jsxs18("div", { className: scrollOuterClass, children: [
4283
- isLoading && /* @__PURE__ */ jsx21("div", { className: "absolute inset-0 z-20 flex items-center justify-center bg-white/40 backdrop-blur-[2px] transition-all duration-300", children: /* @__PURE__ */ jsx21("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__ */ jsxs18(Fragment4, { children: [
4284
- /* @__PURE__ */ jsx21(FaSpinner, { className: "animate-spin text-primary-500 text-4xl" }),
4285
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-sm font-semibold text-secondary-600 animate-pulse", children: "Cargando datos..." })
4286
- ] }) }) }),
4287
- effectiveView === "cards" ? /* @__PURE__ */ jsx21("div", { className: "p-4 space-y-3 max-h-[400px] overflow-y-auto", children: data.length > 0 ? data.map((row, i) => /* @__PURE__ */ jsx21(
4288
- "div",
4289
- {
4290
- className: clsx21(tableCardHover, onRowClick && !isLoading && tableCardClickable),
4291
- role: onRowClick && !isLoading ? "button" : void 0,
4292
- tabIndex: onRowClick && !isLoading ? 0 : void 0,
4293
- onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4294
- onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4295
- children: renderCard ? renderCard(row) : renderDefaultCard(row)
4296
- },
4297
- i
4298
- )) : !isLoading && /* @__PURE__ */ jsxs18("div", { className: clsx21(tableEmptyContent, "py-12"), children: [
4299
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4300
- /* @__PURE__ */ jsx21(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4301
- ] }) }) : isTableVirtual ? /* @__PURE__ */ jsx21(
4096
+ isOpen && createPortal3(
4097
+ /* @__PURE__ */ jsx21(
4302
4098
  "div",
4303
4099
  {
4304
- ref: scrollRef,
4305
- className: "overflow-x-auto overflow-y-auto",
4306
- style: { maxHeight: virtualizedMaxHeight },
4307
- children: tableEl
4100
+ ref: panelRef,
4101
+ style: panelStyle,
4102
+ 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",
4103
+ children: /* @__PURE__ */ jsx21("div", { className: "max-h-60 overflow-y-auto", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
4104
+ const isSelected = value === option[valueField];
4105
+ return /* @__PURE__ */ jsx21(
4106
+ ITText,
4107
+ {
4108
+ as: "div",
4109
+ onClick: () => handleSelect(option),
4110
+ className: clsx21(
4111
+ "px-4 py-2 text-sm cursor-pointer transition-colors",
4112
+ 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"
4113
+ ),
4114
+ children: renderOption ? renderOption(option, { isSelected, searchTerm }) : /* @__PURE__ */ jsx21(ITText, { as: "span", children: option[labelField] })
4115
+ },
4116
+ option[valueField]
4117
+ );
4118
+ }) : /* @__PURE__ */ jsx21(ITText, { as: "div", className: "px-4 py-6 text-sm text-center text-secondary-500 italic", children: isLoading ? "Cargando..." : noResultsMessage }) })
4308
4119
  }
4309
- ) : tableEl
4310
- ] })
4120
+ ),
4121
+ document.body
4122
+ )
4311
4123
  ] }),
4312
- /* @__PURE__ */ jsx21("div", { className: "rounded-b-xl px-6 py-4", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: /* @__PURE__ */ jsx21(
4313
- ITPagination,
4314
- {
4315
- currentPage,
4316
- totalPages: computedTotalPages,
4317
- onPageChange: goToPage,
4318
- color: "primary",
4319
- itemsPerPageOptions,
4320
- itemsPerPage,
4321
- onItemsPerPageChange: handleItemsPerPageChange,
4322
- totalItems
4323
- }
4324
- ) })
4124
+ hasError && /* @__PURE__ */ jsx21(ITText, { as: "p", className: "text-danger-500 text-xs mt-1", children: errorMessage })
4325
4125
  ] });
4326
4126
  }
4327
4127
 
4328
4128
  // src/components/molecules/date-picker/datePicker.tsx
4329
4129
  import clsx22 from "clsx";
4330
4130
  import React5, { useEffect as useEffect8, useRef as useRef12, useState as useState18 } from "react";
4331
- import { createPortal as createPortal3 } from "react-dom";
4131
+ import { createPortal as createPortal4 } from "react-dom";
4332
4132
  import { FaCalendarAlt } from "react-icons/fa";
4333
4133
  import { isBefore as isBefore2 } from "date-fns";
4334
4134
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
@@ -4538,7 +4338,7 @@ function ITDatePicker({
4538
4338
  onClick: handleIconClick
4539
4339
  }
4540
4340
  ),
4541
- isOpen && createPortal3(
4341
+ isOpen && createPortal4(
4542
4342
  /* @__PURE__ */ jsx22(
4543
4343
  "div",
4544
4344
  {
@@ -4578,27 +4378,570 @@ function ITDatePicker({
4578
4378
  ] });
4579
4379
  }
4580
4380
 
4581
- // src/components/organisms/dialog/dialog.tsx
4582
- import { createPortal as createPortal4 } from "react-dom";
4583
- import { useEffect as useEffect9, useRef as useRef13 } from "react";
4584
- import { FaRegTimesCircle } from "react-icons/fa";
4585
-
4586
- // src/components/molecules/form-header/form-header.tsx
4587
- import { FaTimes as FaTimes5 } from "react-icons/fa";
4588
-
4589
- // src/theme/theme-context.ts
4590
- import { createContext, useContext } from "react";
4591
- var ITThemeContext = createContext(void 0);
4592
- var useITTheme = () => {
4593
- const context = useContext(ITThemeContext);
4594
- if (!context) {
4595
- throw new Error("useITTheme must be used within an ITThemeProvider");
4596
- }
4597
- return context;
4598
- };
4599
- var useITThemeSafe = () => {
4600
- return useContext(ITThemeContext);
4601
- };
4381
+ // src/utils/table.utils.ts
4382
+ var formatCurrencyMX = (value) => {
4383
+ return value.toLocaleString("es-MX", {
4384
+ style: "currency",
4385
+ currency: "MXN"
4386
+ });
4387
+ };
4388
+ var getNestedValue = (obj, path) => {
4389
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4390
+ };
4391
+ var ROW_CLICK_IGNORE_SELECTOR = 'button, a, input, select, textarea, [role="button"], [role="link"], [data-row-click-ignore]';
4392
+ function isInteractiveTarget(target, boundary = null) {
4393
+ if (!(target instanceof Element)) return false;
4394
+ const interactive = target.closest(ROW_CLICK_IGNORE_SELECTOR);
4395
+ if (!interactive) return false;
4396
+ if (boundary instanceof Node && interactive === boundary) return false;
4397
+ return true;
4398
+ }
4399
+ function pinnedColumnWidth(col) {
4400
+ if (typeof col.width === "number") return col.width;
4401
+ if (typeof col.width === "string" && /^\d+(\.\d+)?px$/.test(col.width.trim())) {
4402
+ return parseFloat(col.width);
4403
+ }
4404
+ return col.minWidth ?? 0;
4405
+ }
4406
+ function getPinnedColumnMeta(columns) {
4407
+ const meta = {};
4408
+ let leftOffset = 0;
4409
+ for (const col of columns) {
4410
+ if (col.pinned === "left") {
4411
+ meta[col.key] = { side: "left", offset: leftOffset };
4412
+ leftOffset += pinnedColumnWidth(col);
4413
+ }
4414
+ }
4415
+ let rightOffset = 0;
4416
+ for (let i = columns.length - 1; i >= 0; i--) {
4417
+ const col = columns[i];
4418
+ if (col.pinned === "right") {
4419
+ meta[col.key] = { side: "right", offset: rightOffset };
4420
+ rightOffset += pinnedColumnWidth(col);
4421
+ }
4422
+ }
4423
+ return meta;
4424
+ }
4425
+
4426
+ // src/components/organisms/data-table/dataTable.tsx
4427
+ import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
4428
+ var getNestedValue2 = (obj, path) => {
4429
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4430
+ };
4431
+ var EMPTY_OBJECT = {};
4432
+ function ITDataTable({
4433
+ columns,
4434
+ fetchData,
4435
+ debounceMs = 500,
4436
+ externalFilters = EMPTY_OBJECT,
4437
+ loadingIndicator,
4438
+ fetchOnMount = true,
4439
+ reloadTrigger,
4440
+ containerClassName,
4441
+ className,
4442
+ variant = "default",
4443
+ size = "md",
4444
+ itemsPerPageOptions = [5, 10, 20],
4445
+ defaultItemsPerPage = 10,
4446
+ title,
4447
+ renderCard,
4448
+ defaultView,
4449
+ showVerticalBorder = true,
4450
+ verticalBorderClassname,
4451
+ onRowClick,
4452
+ layout = "auto",
4453
+ density = "normal",
4454
+ autoCardBreakpoint = 0,
4455
+ virtualized = false,
4456
+ virtualizedMaxHeight = 400,
4457
+ rowHeight,
4458
+ overscan = 5,
4459
+ stickyHeader = false
4460
+ }) {
4461
+ const [viewMode, setViewMode] = useState19(defaultView || "table");
4462
+ const { ref: rootRef, width: containerWidth } = useElementSize();
4463
+ const [data, setData] = useState19([]);
4464
+ const [totalItems, setTotalItems] = useState19(0);
4465
+ const [isLoading, setIsLoading] = useState19(fetchOnMount);
4466
+ const isFixed = layout === "fixed";
4467
+ const forcedCards = autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
4468
+ const effectiveView = forcedCards ? "cards" : viewMode;
4469
+ const hasColumnWidths = columns.some((col) => col.width != null);
4470
+ 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";
4471
+ const isTableVirtual = virtualized && effectiveView === "table";
4472
+ const isStickyHeader = stickyHeader && isTableVirtual;
4473
+ const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
4474
+ const columnCount = columns.length;
4475
+ const pinnedMeta = React6.useMemo(() => getPinnedColumnMeta(columns), [columns]);
4476
+ const scrollOuterClass = isTableVirtual ? "relative min-h-[200px]" : "overflow-x-auto relative min-h-[200px]";
4477
+ const {
4478
+ currentPage,
4479
+ itemsPerPage,
4480
+ filters,
4481
+ sortConfig,
4482
+ goToPage,
4483
+ handleFilterChange,
4484
+ handleSort,
4485
+ handleItemsPerPageChange
4486
+ } = useTableState({ defaultItemsPerPage });
4487
+ const {
4488
+ scrollRef,
4489
+ startIndex,
4490
+ endIndex,
4491
+ topSpacerHeight,
4492
+ bottomSpacerHeight
4493
+ } = useVirtualRows({
4494
+ count: data.length,
4495
+ rowHeight: resolvedRowHeight,
4496
+ overscan,
4497
+ enabled: isTableVirtual,
4498
+ resetKey: `${currentPage}-${itemsPerPage}`
4499
+ });
4500
+ const windowData = isTableVirtual ? data.slice(startIndex, endIndex + 1) : data;
4501
+ const debounceTimerRef = useRef13(null);
4502
+ const hasFetchedRef = useRef13(false);
4503
+ const fetchDataRef = useRef13(fetchData);
4504
+ fetchDataRef.current = fetchData;
4505
+ const externalFiltersRef = useRef13(externalFilters);
4506
+ externalFiltersRef.current = externalFilters;
4507
+ const externalKey = JSON.stringify(externalFilters);
4508
+ const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
4509
+ const performFetch = useCallback7(async () => {
4510
+ setIsLoading(true);
4511
+ try {
4512
+ const response = await fetchDataRef.current({
4513
+ page: currentPage,
4514
+ limit: itemsPerPage,
4515
+ filters: { ...filters, ...externalFiltersRef.current },
4516
+ sort: sortConfig || void 0
4517
+ });
4518
+ setData(response.data || []);
4519
+ setTotalItems(response.total || 0);
4520
+ hasFetchedRef.current = true;
4521
+ } catch (error) {
4522
+ console.error("ITDataTable: Error fetching data", error);
4523
+ setData([]);
4524
+ setTotalItems(0);
4525
+ hasFetchedRef.current = true;
4526
+ } finally {
4527
+ setIsLoading(false);
4528
+ }
4529
+ }, [currentPage, itemsPerPage, filters, sortConfig]);
4530
+ const performFetchRef = useRef13(performFetch);
4531
+ performFetchRef.current = performFetch;
4532
+ useEffect9(() => {
4533
+ if (!fetchOnMount && !hasFetchedRef.current) return;
4534
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4535
+ debounceTimerRef.current = setTimeout(() => {
4536
+ performFetchRef.current();
4537
+ }, debounceMs);
4538
+ return () => {
4539
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4540
+ };
4541
+ }, [currentPage, itemsPerPage, sortConfig, filters, externalKey, reloadTrigger, fetchOnMount, debounceMs]);
4542
+ const renderFilterInput = (col) => {
4543
+ if (!col.filter) return null;
4544
+ if (col.type === "boolean") {
4545
+ const currentValue = filters[col.key];
4546
+ const nextValue = currentValue === void 0 ? true : currentValue === true ? false : void 0;
4547
+ const getToggleLabel = () => {
4548
+ if (currentValue === void 0) return "Mostrar todos";
4549
+ if (currentValue === true) return "Filtrar solo verdaderos";
4550
+ return "Filtrar solo falsos";
4551
+ };
4552
+ return /* @__PURE__ */ jsx23(
4553
+ "button",
4554
+ {
4555
+ 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",
4556
+ onClick: () => handleFilterChange(col.key, nextValue),
4557
+ "aria-label": `${getToggleLabel()} para ${col.label}`,
4558
+ title: `${getToggleLabel()} para ${col.label}`,
4559
+ disabled: isLoading,
4560
+ children: /* @__PURE__ */ jsx23("div", { className: "relative w-10 h-5 bg-secondary-300 rounded-full", children: /* @__PURE__ */ jsx23(
4561
+ "div",
4562
+ {
4563
+ className: clsx23(
4564
+ "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
4565
+ {
4566
+ "left-0.5 bg-secondary-400": currentValue === void 0,
4567
+ "left-5 bg-slate-500": currentValue === true,
4568
+ "left-0.5 bg-secondary-500": currentValue === false
4569
+ }
4570
+ )
4571
+ }
4572
+ ) })
4573
+ }
4574
+ );
4575
+ }
4576
+ if (col.filter === "catalog" && col.catalogOptions) {
4577
+ if (col.catalogOptions.loading) {
4578
+ return /* @__PURE__ */ jsx23(FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4579
+ }
4580
+ if (col.catalogOptions.error) {
4581
+ return /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4582
+ }
4583
+ return /* @__PURE__ */ jsx23(
4584
+ ITSelect,
4585
+ {
4586
+ name: `filter-${col.key}`,
4587
+ options: [
4588
+ { value: "", label: "Todos" },
4589
+ ...col.catalogOptions.data.map((item) => ({
4590
+ value: String(item.id),
4591
+ label: item.name
4592
+ }))
4593
+ ],
4594
+ value: String(filters[col.key] || ""),
4595
+ onChange: (e) => {
4596
+ const value = e.target.value === "" ? void 0 : e.target.value;
4597
+ handleFilterChange(col.key, value);
4598
+ },
4599
+ onBlur: () => {
4600
+ },
4601
+ className: "w-full text-xs",
4602
+ disabled: isLoading
4603
+ }
4604
+ );
4605
+ }
4606
+ if (col.filter === "search" && col.catalogOptions) {
4607
+ if (col.catalogOptions.loading) {
4608
+ return /* @__PURE__ */ jsx23(FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4609
+ }
4610
+ if (col.catalogOptions.error) {
4611
+ return /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4612
+ }
4613
+ const searchValue = filters[col.key];
4614
+ return /* @__PURE__ */ jsx23(
4615
+ ITSearchSelect,
4616
+ {
4617
+ name: `filter-${col.key}`,
4618
+ options: col.catalogOptions.data.map((item) => ({
4619
+ value: item.id,
4620
+ label: item.name
4621
+ })),
4622
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
4623
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
4624
+ onSearch: col.catalogOptions.onSearch,
4625
+ isLoading: col.catalogOptions.loading,
4626
+ size: "sm",
4627
+ placeholder: "Buscar...",
4628
+ clearable: true,
4629
+ className: "w-full",
4630
+ onBlur: () => {
4631
+ },
4632
+ disabled: isLoading
4633
+ }
4634
+ );
4635
+ }
4636
+ if (col.filter === "date") {
4637
+ const dateValue = filters[col.key];
4638
+ return /* @__PURE__ */ jsx23(
4639
+ ITDatePicker,
4640
+ {
4641
+ name: `filter-${col.key}`,
4642
+ value: dateValue instanceof Date ? dateValue : void 0,
4643
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4644
+ minDate: col.dateFilterOptions?.minDate,
4645
+ maxDate: col.dateFilterOptions?.maxDate,
4646
+ size: "sm",
4647
+ placeholder: "dd/mm/aaaa",
4648
+ className: "w-full",
4649
+ disabled: isLoading
4650
+ }
4651
+ );
4652
+ }
4653
+ if (col.filter === "date-range") {
4654
+ const rangeValue = filters[col.key];
4655
+ return /* @__PURE__ */ jsx23(
4656
+ ITDatePicker,
4657
+ {
4658
+ name: `filter-${col.key}`,
4659
+ range: true,
4660
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
4661
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4662
+ minDate: col.dateFilterOptions?.minDate,
4663
+ maxDate: col.dateFilterOptions?.maxDate,
4664
+ size: "sm",
4665
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
4666
+ className: "w-full",
4667
+ disabled: isLoading
4668
+ }
4669
+ );
4670
+ }
4671
+ return /* @__PURE__ */ jsx23(
4672
+ ITInput,
4673
+ {
4674
+ name: `filter-${col.key}`,
4675
+ className: "w-full text-xs",
4676
+ placeholder: "Buscar...",
4677
+ value: String(filters[col.key] || ""),
4678
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4679
+ onBlur: () => {
4680
+ },
4681
+ disabled: isLoading
4682
+ }
4683
+ );
4684
+ };
4685
+ const renderCellContent = (col, row) => {
4686
+ const value = getNestedValue2(row, col.key);
4687
+ if (col.render) return col.render(row);
4688
+ switch (col.type) {
4689
+ case "number":
4690
+ return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
4691
+ case "boolean":
4692
+ return value ? /* @__PURE__ */ jsx23(FaCheck2, { className: "text-success-500", "aria-label": "Verdadero", title: "Verdadero" }) : /* @__PURE__ */ jsx23(FaTimes5, { className: "text-danger-500", "aria-label": "Falso", title: "Falso" });
4693
+ case "actions":
4694
+ return col.actions ? col.actions(row) : null;
4695
+ case "catalog":
4696
+ if (col.catalogOptions) {
4697
+ const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
4698
+ return catalogItem?.name || value;
4699
+ }
4700
+ return value;
4701
+ default:
4702
+ return value;
4703
+ }
4704
+ };
4705
+ const renderDefaultCard = (row) => {
4706
+ const dataCols = columns.filter((c) => c.type !== "actions");
4707
+ const actionCol = columns.find((c) => c.type === "actions");
4708
+ return /* @__PURE__ */ jsxs20("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: [
4709
+ dataCols.map((col) => /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between gap-2", children: [
4710
+ /* @__PURE__ */ jsx23("span", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 whitespace-nowrap flex-shrink-0 min-w-[70px]", children: col.label }),
4711
+ /* @__PURE__ */ jsx23("span", { className: "text-sm font-medium text-slate-800 dark:text-white text-right truncate", children: renderCellContent(col, row) })
4712
+ ] }, col.key)),
4713
+ actionCol?.actions && /* @__PURE__ */ jsx23("div", { className: "flex items-center justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-700", children: actionCol.actions(row) })
4714
+ ] });
4715
+ };
4716
+ 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"}`;
4717
+ const handleRowClick = (row) => (event) => {
4718
+ if (!onRowClick || isLoading || isInteractiveTarget(event.target, event.currentTarget)) return;
4719
+ onRowClick(row, event);
4720
+ };
4721
+ const handleRowKeyDown = (row) => (event) => {
4722
+ if (!onRowClick || isLoading) return;
4723
+ if (event.target !== event.currentTarget) return;
4724
+ if (event.key !== "Enter" && event.key !== " ") return;
4725
+ event.preventDefault();
4726
+ onRowClick(row, event);
4727
+ };
4728
+ const tableEl = /* @__PURE__ */ jsxs20(
4729
+ "table",
4730
+ {
4731
+ className: clsx23(
4732
+ tableLayoutClass,
4733
+ showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
4734
+ showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
4735
+ isLoading ? "opacity-50" : "opacity-100",
4736
+ variantStyles[variant],
4737
+ sizeStyles[size],
4738
+ className
4739
+ ),
4740
+ style: isFixed ? { tableLayout: "fixed" } : void 0,
4741
+ "aria-rowcount": isTableVirtual ? data.length + 1 : void 0,
4742
+ children: [
4743
+ hasColumnWidths && /* @__PURE__ */ jsx23("colgroup", { children: columns.map((col) => /* @__PURE__ */ jsx23(
4744
+ "col",
4745
+ {
4746
+ style: col.width != null ? { width: typeof col.width === "number" ? `${col.width}px` : col.width } : void 0
4747
+ },
4748
+ col.key
4749
+ )) }),
4750
+ /* @__PURE__ */ jsx23("thead", { children: /* @__PURE__ */ jsx23(
4751
+ "tr",
4752
+ {
4753
+ className: clsx23(tableHeaderRow, "dark:text-slate-200"),
4754
+ "aria-rowindex": isTableVirtual ? 1 : void 0,
4755
+ children: columns.map((col) => {
4756
+ const pin = pinnedMeta[col.key];
4757
+ const isPinned = pin != null;
4758
+ return /* @__PURE__ */ jsx23(
4759
+ "th",
4760
+ {
4761
+ scope: "col",
4762
+ className: clsx23(
4763
+ tableHeaderCell(col.className, density),
4764
+ col.align && tableAlignClasses[col.align],
4765
+ isPinned && "sticky",
4766
+ isStickyHeader && "sticky top-0 bg-secondary-50",
4767
+ isPinned ? "z-[15]" : isStickyHeader && "z-10",
4768
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right")
4769
+ ),
4770
+ style: col.minWidth != null || isStickyHeader || isPinned ? {
4771
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4772
+ ...isStickyHeader || isPinned ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {},
4773
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
4774
+ } : void 0,
4775
+ children: /* @__PURE__ */ jsxs20("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
4776
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center justify-between gap-2", children: [
4777
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
4778
+ col.sortable && col.type !== "actions" && /* @__PURE__ */ jsx23(
4779
+ "button",
4780
+ {
4781
+ onClick: () => handleSort(col.key),
4782
+ disabled: isLoading,
4783
+ 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`,
4784
+ title: `Ordenar por ${col.label}`,
4785
+ children: /* @__PURE__ */ jsx23(MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
4786
+ }
4787
+ )
4788
+ ] }),
4789
+ /* @__PURE__ */ jsx23("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
4790
+ ] })
4791
+ },
4792
+ col.key
4793
+ );
4794
+ })
4795
+ }
4796
+ ) }),
4797
+ /* @__PURE__ */ jsx23("tbody", { className: clsx23(tableBody, "dark:divide-slate-700/30"), children: data.length > 0 ? /* @__PURE__ */ jsxs20(Fragment4, { children: [
4798
+ isTableVirtual && topSpacerHeight > 0 && /* @__PURE__ */ jsx23("tr", { "aria-hidden": "true", style: { height: topSpacerHeight }, children: /* @__PURE__ */ jsx23("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) }),
4799
+ windowData.map((row, windowIndex) => {
4800
+ const absoluteIndex = isTableVirtual ? startIndex + windowIndex : windowIndex;
4801
+ return /* @__PURE__ */ jsx23(
4802
+ "tr",
4803
+ {
4804
+ "aria-rowindex": isTableVirtual ? absoluteIndex + 2 : void 0,
4805
+ className: clsx23(
4806
+ tableRow,
4807
+ variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
4808
+ onRowClick && !isLoading && tableRowClickable
4809
+ ),
4810
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4811
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4812
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4813
+ children: columns.map((col) => {
4814
+ const rawValue = getNestedValue2(row, col.key);
4815
+ const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
4816
+ const pin = pinnedMeta[col.key];
4817
+ const isPinned = pin != null;
4818
+ return /* @__PURE__ */ jsx23(
4819
+ "td",
4820
+ {
4821
+ className: clsx23(
4822
+ tableCell(col.className, density),
4823
+ col.align && tableAlignClasses[col.align],
4824
+ isPinned && "sticky bg-[var(--color-table-rowBg,white)] group-hover:bg-[var(--color-table-rowHover,var(--color-secondary-50))]",
4825
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
4826
+ isPinned && "z-[1]"
4827
+ ),
4828
+ style: col.minWidth != null || isPinned ? {
4829
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4830
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
4831
+ } : void 0,
4832
+ title: truncateTitle,
4833
+ children: col.type === "actions" ? /* @__PURE__ */ jsx23("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ jsx23("div", { className: clsx23(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
4834
+ },
4835
+ `${absoluteIndex}-${col.key}`
4836
+ );
4837
+ })
4838
+ },
4839
+ absoluteIndex
4840
+ );
4841
+ }),
4842
+ isTableVirtual && bottomSpacerHeight > 0 && /* @__PURE__ */ jsx23("tr", { "aria-hidden": "true", style: { height: bottomSpacerHeight }, children: /* @__PURE__ */ jsx23("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) })
4843
+ ] }) : /* @__PURE__ */ jsx23("tr", { children: /* @__PURE__ */ jsx23("td", { colSpan: columns.length, className: "px-6 py-12 text-center", children: !isLoading && /* @__PURE__ */ jsxs20("div", { className: tableEmptyContent, children: [
4844
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4845
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4846
+ ] }) }) }) })
4847
+ ]
4848
+ }
4849
+ );
4850
+ return /* @__PURE__ */ jsxs20("div", { ref: rootRef, className: clsx23("space-y-4 w-full relative", containerClassName), children: [
4851
+ /* @__PURE__ */ jsxs20("div", { className: tableContainer, style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4852
+ title && /* @__PURE__ */ jsxs20("div", { className: "px-6 py-5 flex items-center justify-between", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4853
+ /* @__PURE__ */ jsx23(ITText, { as: "h2", className: "text-xl font-bold text-secondary-900 leading-tight", children: title }),
4854
+ /* @__PURE__ */ jsxs20("div", { className: "flex items-center gap-3", children: [
4855
+ isLoading && /* @__PURE__ */ jsx23("div", { className: "text-secondary-400", children: loadingIndicator || /* @__PURE__ */ jsx23(FaSpinner, { className: "animate-spin text-primary-500 text-xl" }) }),
4856
+ /* @__PURE__ */ jsxs20("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: [
4857
+ /* @__PURE__ */ jsxs20("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4858
+ /* @__PURE__ */ jsx23(FaTable, { size: 11 }),
4859
+ "Table"
4860
+ ] }),
4861
+ /* @__PURE__ */ jsxs20("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4862
+ /* @__PURE__ */ jsx23(FaThLarge, { size: 11 }),
4863
+ "Cards"
4864
+ ] })
4865
+ ] })
4866
+ ] })
4867
+ ] }),
4868
+ !title && /* @__PURE__ */ jsx23("div", { className: "flex justify-end px-4 pt-3", children: /* @__PURE__ */ jsxs20("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: [
4869
+ /* @__PURE__ */ jsxs20("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4870
+ /* @__PURE__ */ jsx23(FaTable, { size: 11 }),
4871
+ "Table"
4872
+ ] }),
4873
+ /* @__PURE__ */ jsxs20("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4874
+ /* @__PURE__ */ jsx23(FaThLarge, { size: 11 }),
4875
+ "Cards"
4876
+ ] })
4877
+ ] }) }),
4878
+ /* @__PURE__ */ jsxs20("div", { className: scrollOuterClass, children: [
4879
+ isLoading && /* @__PURE__ */ jsx23("div", { className: "absolute inset-0 z-20 flex items-center justify-center bg-white/40 backdrop-blur-[2px] transition-all duration-300", children: /* @__PURE__ */ jsx23("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__ */ jsxs20(Fragment4, { children: [
4880
+ /* @__PURE__ */ jsx23(FaSpinner, { className: "animate-spin text-primary-500 text-4xl" }),
4881
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-sm font-semibold text-secondary-600 animate-pulse", children: "Cargando datos..." })
4882
+ ] }) }) }),
4883
+ effectiveView === "cards" ? /* @__PURE__ */ jsx23("div", { className: "p-4 space-y-3 max-h-[400px] overflow-y-auto", children: data.length > 0 ? data.map((row, i) => /* @__PURE__ */ jsx23(
4884
+ "div",
4885
+ {
4886
+ className: clsx23(tableCardHover, onRowClick && !isLoading && tableCardClickable),
4887
+ role: onRowClick && !isLoading ? "button" : void 0,
4888
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4889
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4890
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4891
+ children: renderCard ? renderCard(row) : renderDefaultCard(row)
4892
+ },
4893
+ i
4894
+ )) : !isLoading && /* @__PURE__ */ jsxs20("div", { className: clsx23(tableEmptyContent, "py-12"), children: [
4895
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4896
+ /* @__PURE__ */ jsx23(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4897
+ ] }) }) : isTableVirtual ? /* @__PURE__ */ jsx23(
4898
+ "div",
4899
+ {
4900
+ ref: scrollRef,
4901
+ className: "overflow-x-auto overflow-y-auto",
4902
+ style: { maxHeight: virtualizedMaxHeight },
4903
+ children: tableEl
4904
+ }
4905
+ ) : tableEl
4906
+ ] })
4907
+ ] }),
4908
+ /* @__PURE__ */ jsx23("div", { className: "rounded-b-xl px-6 py-4", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: /* @__PURE__ */ jsx23(
4909
+ ITPagination,
4910
+ {
4911
+ currentPage,
4912
+ totalPages: computedTotalPages,
4913
+ onPageChange: goToPage,
4914
+ color: "primary",
4915
+ itemsPerPageOptions,
4916
+ itemsPerPage,
4917
+ onItemsPerPageChange: handleItemsPerPageChange,
4918
+ totalItems
4919
+ }
4920
+ ) })
4921
+ ] });
4922
+ }
4923
+
4924
+ // src/components/organisms/dialog/dialog.tsx
4925
+ import { createPortal as createPortal5 } from "react-dom";
4926
+ import { useEffect as useEffect10, useRef as useRef14 } from "react";
4927
+ import { FaRegTimesCircle } from "react-icons/fa";
4928
+
4929
+ // src/components/molecules/form-header/form-header.tsx
4930
+ import { FaTimes as FaTimes6 } from "react-icons/fa";
4931
+
4932
+ // src/theme/theme-context.ts
4933
+ import { createContext, useContext } from "react";
4934
+ var ITThemeContext = createContext(void 0);
4935
+ var useITTheme = () => {
4936
+ const context = useContext(ITThemeContext);
4937
+ if (!context) {
4938
+ throw new Error("useITTheme must be used within an ITThemeProvider");
4939
+ }
4940
+ return context;
4941
+ };
4942
+ var useITThemeSafe = () => {
4943
+ return useContext(ITThemeContext);
4944
+ };
4602
4945
 
4603
4946
  // src/utils/color.utils.ts
4604
4947
  var isLightColor = (hex) => {
@@ -4677,7 +5020,7 @@ var getContrastTextColor = (bgColor, palette2, isDarkMode) => {
4677
5020
  };
4678
5021
 
4679
5022
  // src/components/molecules/form-header/form-header.tsx
4680
- import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
5023
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
4681
5024
  function ITFormHeader({
4682
5025
  title,
4683
5026
  onClose,
@@ -4691,23 +5034,23 @@ function ITFormHeader({
4691
5034
  palette2,
4692
5035
  isDarkMode
4693
5036
  );
4694
- return /* @__PURE__ */ jsxs20("div", { className: `bg-primary-500 ${textColorClass} px-6 py-4 rounded-t-lg flex justify-center items-center relative ${className}`, children: [
4695
- /* @__PURE__ */ jsx23(ITText, { as: "h2", className: "text-lg font-semibold text-center", style: { color: "inherit" }, children: title }),
4696
- onClose && /* @__PURE__ */ jsx23(
5037
+ return /* @__PURE__ */ jsxs21("div", { className: `bg-primary-500 ${textColorClass} px-6 py-4 rounded-t-lg flex justify-center items-center relative ${className}`, children: [
5038
+ /* @__PURE__ */ jsx24(ITText, { as: "h2", className: "text-lg font-semibold text-center", style: { color: "inherit" }, children: title }),
5039
+ onClose && /* @__PURE__ */ jsx24(
4697
5040
  "button",
4698
5041
  {
4699
5042
  onClick: onClose,
4700
5043
  className: `absolute right-4 ${textColorClass} hover:opacity-80 transition-colors duration-200 p-1 rounded-full`,
4701
5044
  style: { color: "inherit" },
4702
5045
  "aria-label": "Cerrar",
4703
- children: /* @__PURE__ */ jsx23(FaTimes5, { className: "w-4 h-4" })
5046
+ children: /* @__PURE__ */ jsx24(FaTimes6, { className: "w-4 h-4" })
4704
5047
  }
4705
5048
  )
4706
5049
  ] });
4707
5050
  }
4708
5051
 
4709
5052
  // src/components/organisms/dialog/dialog.tsx
4710
- import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
5053
+ import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
4711
5054
  function ITDialog({
4712
5055
  isOpen,
4713
5056
  onClose,
@@ -4717,9 +5060,9 @@ function ITDialog({
4717
5060
  useFormHeader = false,
4718
5061
  fullScreen = false
4719
5062
  }) {
4720
- const modalRef = useRef13(null);
5063
+ const modalRef = useRef14(null);
4721
5064
  useClickOutside_default(modalRef, onClose);
4722
- useEffect9(() => {
5065
+ useEffect10(() => {
4723
5066
  const handleEscape = (event) => {
4724
5067
  if (event.key === "Escape") {
4725
5068
  onClose();
@@ -4734,12 +5077,12 @@ function ITDialog({
4734
5077
  }, [isOpen, onClose]);
4735
5078
  if (!isOpen) return null;
4736
5079
  if (typeof document === "undefined") return null;
4737
- const content = /* @__PURE__ */ jsx24(
5080
+ const content = /* @__PURE__ */ jsx25(
4738
5081
  "div",
4739
5082
  {
4740
5083
  "data-it-dialog": "true",
4741
5084
  className: `fixed inset-0 flex ${fullScreen ? "items-stretch" : "items-center justify-center"} bg-slate-900/50 z-[60]`,
4742
- children: /* @__PURE__ */ jsx24(
5085
+ children: /* @__PURE__ */ jsx25(
4743
5086
  "div",
4744
5087
  {
4745
5088
  ref: modalRef,
@@ -4752,41 +5095,41 @@ function ITDialog({
4752
5095
  borderColor: theme.card.borderColor,
4753
5096
  borderStyle: "solid"
4754
5097
  },
4755
- children: useFormHeader && title ? /* @__PURE__ */ jsxs21(Fragment5, { children: [
4756
- /* @__PURE__ */ jsx24(ITFormHeader, { title, onClose }),
4757
- /* @__PURE__ */ jsx24("div", { className: fullScreen ? "flex-1 overflow-auto p-6" : "p-6", children })
4758
- ] }) : /* @__PURE__ */ jsxs21(Fragment5, { children: [
4759
- /* @__PURE__ */ jsx24(
5098
+ children: useFormHeader && title ? /* @__PURE__ */ jsxs22(Fragment5, { children: [
5099
+ /* @__PURE__ */ jsx25(ITFormHeader, { title, onClose }),
5100
+ /* @__PURE__ */ jsx25("div", { className: fullScreen ? "flex-1 overflow-auto p-6" : "p-6", children })
5101
+ ] }) : /* @__PURE__ */ jsxs22(Fragment5, { children: [
5102
+ /* @__PURE__ */ jsx25(
4760
5103
  "button",
4761
5104
  {
4762
5105
  className: "absolute top-2 right-2 text-secondary-600 hover:text-secondary-900",
4763
5106
  onClick: onClose,
4764
- children: /* @__PURE__ */ jsx24(FaRegTimesCircle, {})
5107
+ children: /* @__PURE__ */ jsx25(FaRegTimesCircle, {})
4765
5108
  }
4766
5109
  ),
4767
- title && /* @__PURE__ */ jsx24(ITText, { as: "h2", className: "text-xl font-semibold mb-4", children: title }),
4768
- /* @__PURE__ */ jsx24("div", { children })
5110
+ title && /* @__PURE__ */ jsx25(ITText, { as: "h2", className: "text-xl font-semibold mb-4", children: title }),
5111
+ /* @__PURE__ */ jsx25("div", { children })
4769
5112
  ] })
4770
5113
  }
4771
5114
  )
4772
5115
  }
4773
5116
  );
4774
- return createPortal4(content, document.body);
5117
+ return createPortal5(content, document.body);
4775
5118
  }
4776
5119
 
4777
5120
  // src/components/atoms/divider/divider.tsx
4778
- import clsx23 from "clsx";
4779
- import { jsx as jsx25 } from "react/jsx-runtime";
5121
+ import clsx24 from "clsx";
5122
+ import { jsx as jsx26 } from "react/jsx-runtime";
4780
5123
  function ITDivider({
4781
5124
  orientation = "horizontal",
4782
5125
  className,
4783
5126
  color = "bg-slate-200 dark:bg-slate-700",
4784
5127
  thickness = orientation === "horizontal" ? "h-px" : "w-px"
4785
5128
  }) {
4786
- return /* @__PURE__ */ jsx25(
5129
+ return /* @__PURE__ */ jsx26(
4787
5130
  "div",
4788
5131
  {
4789
- className: clsx23(
5132
+ className: clsx24(
4790
5133
  "flex-shrink-0",
4791
5134
  orientation === "horizontal" ? "w-full" : "self-stretch",
4792
5135
  thickness,
@@ -4798,10 +5141,10 @@ function ITDivider({
4798
5141
  }
4799
5142
 
4800
5143
  // src/components/organisms/drawer/drawer.tsx
4801
- import clsx24 from "clsx";
4802
- import { FaTimes as FaTimes6 } from "react-icons/fa";
4803
- import { useRef as useRef14 } from "react";
4804
- import { Fragment as Fragment6, jsx as jsx26, jsxs as jsxs22 } from "react/jsx-runtime";
5144
+ import clsx25 from "clsx";
5145
+ import { FaTimes as FaTimes7 } from "react-icons/fa";
5146
+ import { useRef as useRef15 } from "react";
5147
+ import { Fragment as Fragment6, jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
4805
5148
  function ITDrawer({
4806
5149
  isOpen,
4807
5150
  onClose,
@@ -4812,15 +5155,15 @@ function ITDrawer({
4812
5155
  className,
4813
5156
  style
4814
5157
  }) {
4815
- const panelRef = useRef14(null);
5158
+ const panelRef = useRef15(null);
4816
5159
  useClickOutside_default(panelRef, onClose);
4817
- return /* @__PURE__ */ jsx26(Fragment6, { children: isOpen && /* @__PURE__ */ jsxs22("div", { className: "fixed inset-0 z-[50] flex", children: [
4818
- /* @__PURE__ */ jsx26("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" }),
4819
- /* @__PURE__ */ jsxs22(
5160
+ return /* @__PURE__ */ jsx27(Fragment6, { children: isOpen && /* @__PURE__ */ jsxs23("div", { className: "fixed inset-0 z-[50] flex", children: [
5161
+ /* @__PURE__ */ jsx27("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" }),
5162
+ /* @__PURE__ */ jsxs23(
4820
5163
  "div",
4821
5164
  {
4822
5165
  ref: panelRef,
4823
- className: clsx24(
5166
+ className: clsx25(
4824
5167
  "relative z-10 h-full bg-white dark:bg-slate-900 shadow-2xl flex flex-col transition-transform duration-300",
4825
5168
  position === "right" ? "ml-auto" : "mr-auto",
4826
5169
  size,
@@ -4828,18 +5171,18 @@ function ITDrawer({
4828
5171
  ),
4829
5172
  style,
4830
5173
  children: [
4831
- title && /* @__PURE__ */ jsxs22("div", { className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700", children: [
4832
- /* @__PURE__ */ jsx26(ITText, { as: "h2", className: "text-lg font-bold text-slate-800 dark:text-white", children: title }),
4833
- /* @__PURE__ */ jsx26(
5174
+ title && /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700", children: [
5175
+ /* @__PURE__ */ jsx27(ITText, { as: "h2", className: "text-lg font-bold text-slate-800 dark:text-white", children: title }),
5176
+ /* @__PURE__ */ jsx27(
4834
5177
  "button",
4835
5178
  {
4836
5179
  onClick: onClose,
4837
5180
  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",
4838
- children: /* @__PURE__ */ jsx26(FaTimes6, { size: 14 })
5181
+ children: /* @__PURE__ */ jsx27(FaTimes7, { size: 14 })
4839
5182
  }
4840
5183
  )
4841
5184
  ] }),
4842
- /* @__PURE__ */ jsx26("div", { className: "flex-1 overflow-y-auto p-5", children })
5185
+ /* @__PURE__ */ jsx27("div", { className: "flex-1 overflow-y-auto p-5", children })
4843
5186
  ]
4844
5187
  }
4845
5188
  )
@@ -4847,27 +5190,27 @@ function ITDrawer({
4847
5190
  }
4848
5191
 
4849
5192
  // src/components/molecules/empty-state/empty-state.tsx
4850
- import clsx25 from "clsx";
5193
+ import clsx26 from "clsx";
4851
5194
  import { FaInbox } from "react-icons/fa";
4852
- import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
5195
+ import { jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
4853
5196
  function ITEmptyState({
4854
- icon = /* @__PURE__ */ jsx27(FaInbox, { size: 40 }),
5197
+ icon = /* @__PURE__ */ jsx28(FaInbox, { size: 40 }),
4855
5198
  title,
4856
5199
  description,
4857
5200
  action,
4858
5201
  className
4859
5202
  }) {
4860
- return /* @__PURE__ */ jsxs23("div", { className: clsx25("flex flex-col items-center justify-center py-16 px-6 text-center", className), children: [
4861
- /* @__PURE__ */ jsx27("div", { className: "text-slate-300 dark:text-slate-600 mb-4", children: icon }),
4862
- /* @__PURE__ */ jsx27(ITText, { as: "h3", className: "text-lg font-bold text-slate-700 dark:text-slate-200 mb-1", children: title }),
4863
- description && /* @__PURE__ */ jsx27(ITText, { as: "p", className: "text-sm text-slate-400 dark:text-slate-500 max-w-sm mb-4", children: description }),
4864
- action && /* @__PURE__ */ jsx27("div", { children: action })
5203
+ return /* @__PURE__ */ jsxs24("div", { className: clsx26("flex flex-col items-center justify-center py-16 px-6 text-center", className), children: [
5204
+ /* @__PURE__ */ jsx28("div", { className: "text-slate-300 dark:text-slate-600 mb-4", children: icon }),
5205
+ /* @__PURE__ */ jsx28(ITText, { as: "h3", className: "text-lg font-bold text-slate-700 dark:text-slate-200 mb-1", children: title }),
5206
+ description && /* @__PURE__ */ jsx28(ITText, { as: "p", className: "text-sm text-slate-400 dark:text-slate-500 max-w-sm mb-4", children: description }),
5207
+ action && /* @__PURE__ */ jsx28("div", { children: action })
4865
5208
  ] });
4866
5209
  }
4867
5210
 
4868
5211
  // src/components/atoms/flex/flex.tsx
4869
- import clsx26 from "clsx";
4870
- import { jsx as jsx28 } from "react/jsx-runtime";
5212
+ import clsx27 from "clsx";
5213
+ import { jsx as jsx29 } from "react/jsx-runtime";
4871
5214
  var directionMap = {
4872
5215
  row: "flex-row",
4873
5216
  column: "flex-col",
@@ -4916,10 +5259,10 @@ function ITFlex({
4916
5259
  flexBasis: typeof basis === "number" ? `${basis * 0.25}rem` : basis,
4917
5260
  ...style
4918
5261
  };
4919
- return /* @__PURE__ */ jsx28(
5262
+ return /* @__PURE__ */ jsx29(
4920
5263
  Component,
4921
5264
  {
4922
- className: clsx26(
5265
+ className: clsx27(
4923
5266
  "flex",
4924
5267
  directionMap[direction],
4925
5268
  align && alignMap[align],
@@ -4938,33 +5281,33 @@ function ITFlex({
4938
5281
  import { useMemo as useMemo10 } from "react";
4939
5282
 
4940
5283
  // src/components/organisms/form-builder/formBuilder.context.tsx
4941
- import React6, { createContext as createContext2, useContext as useContext2, useState as useState19 } from "react";
4942
- import { jsx as jsx29 } from "react/jsx-runtime";
5284
+ import React7, { createContext as createContext2, useContext as useContext2, useState as useState20 } from "react";
5285
+ import { jsx as jsx30 } from "react/jsx-runtime";
4943
5286
  var ITFormBuilderContext = createContext2(void 0);
4944
5287
  var ITFormBuilderProvider = ({
4945
5288
  children,
4946
5289
  value
4947
5290
  }) => {
4948
- const [fieldRegistry, setFieldRegistry] = useState19({});
4949
- const registerField = React6.useCallback((name, config2) => {
5291
+ const [fieldRegistry, setFieldRegistry] = useState20({});
5292
+ const registerField = React7.useCallback((name, config2) => {
4950
5293
  setFieldRegistry((prev) => ({ ...prev, [name]: config2 }));
4951
5294
  }, []);
4952
- const unregisterField = React6.useCallback((name) => {
5295
+ const unregisterField = React7.useCallback((name) => {
4953
5296
  setFieldRegistry((prev) => {
4954
5297
  const next = { ...prev };
4955
5298
  delete next[name];
4956
5299
  return next;
4957
5300
  });
4958
5301
  }, []);
4959
- const getFieldConfig = React6.useCallback(
5302
+ const getFieldConfig = React7.useCallback(
4960
5303
  (name) => fieldRegistry[name],
4961
5304
  [fieldRegistry]
4962
5305
  );
4963
- const getAllFieldConfigs = React6.useCallback(
5306
+ const getAllFieldConfigs = React7.useCallback(
4964
5307
  () => Object.values(fieldRegistry),
4965
5308
  [fieldRegistry]
4966
5309
  );
4967
- const contextValue = React6.useMemo(
5310
+ const contextValue = React7.useMemo(
4968
5311
  () => ({
4969
5312
  ...value,
4970
5313
  registerField,
@@ -4974,7 +5317,7 @@ var ITFormBuilderProvider = ({
4974
5317
  }),
4975
5318
  [value, registerField, unregisterField, getFieldConfig, getAllFieldConfigs]
4976
5319
  );
4977
- return /* @__PURE__ */ jsx29(ITFormBuilderContext.Provider, { value: contextValue, children });
5320
+ return /* @__PURE__ */ jsx30(ITFormBuilderContext.Provider, { value: contextValue, children });
4978
5321
  };
4979
5322
  var useITFormBuilderContext = () => {
4980
5323
  const context = useContext2(ITFormBuilderContext);
@@ -4989,11 +5332,11 @@ import { memo, useCallback as useCallback8, useEffect as useEffect12, useMemo as
4989
5332
  import clsx29 from "clsx";
4990
5333
 
4991
5334
  // src/components/molecules/time-picker/timePicker.tsx
4992
- import clsx27 from "clsx";
4993
- import { useEffect as useEffect10, useRef as useRef15, useState as useState20 } from "react";
4994
- import { createPortal as createPortal5 } from "react-dom";
5335
+ import clsx28 from "clsx";
5336
+ import { useEffect as useEffect11, useRef as useRef16, useState as useState21 } from "react";
5337
+ import { createPortal as createPortal6 } from "react-dom";
4995
5338
  import { FaClock } from "react-icons/fa";
4996
- import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
5339
+ import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
4997
5340
  function ITTimePicker({
4998
5341
  name,
4999
5342
  value,
@@ -5010,12 +5353,12 @@ function ITTimePicker({
5010
5353
  variant = "primary",
5011
5354
  color = "primary"
5012
5355
  }) {
5013
- const [isOpen, setIsOpen] = useState20(false);
5014
- const [inputValue, setInputValue] = useState20(value || "");
5015
- const [isValidTime, setIsValidTime] = useState20(true);
5016
- const wrapperRef = useRef15(null);
5017
- const hoursRef = useRef15(null);
5018
- const minutesRef = useRef15(null);
5356
+ const [isOpen, setIsOpen] = useState21(false);
5357
+ const [inputValue, setInputValue] = useState21(value || "");
5358
+ const [isValidTime, setIsValidTime] = useState21(true);
5359
+ const wrapperRef = useRef16(null);
5360
+ const hoursRef = useRef16(null);
5361
+ const minutesRef = useRef16(null);
5019
5362
  const { panelRef: dropdownRef, style: panelStyle } = useFloatingPanel(
5020
5363
  wrapperRef,
5021
5364
  isOpen && !disabled,
@@ -5029,7 +5372,7 @@ function ITTimePicker({
5029
5372
  const isThemeColor = color in theme.colors;
5030
5373
  const highlightColor = isThemeColor ? theme.colors[color][50] : "#f3f4f6";
5031
5374
  const activeColor = isThemeColor ? theme.colors[color][100] : "#e5e7eb";
5032
- useEffect10(() => {
5375
+ useEffect11(() => {
5033
5376
  setInputValue(value || "");
5034
5377
  }, [value]);
5035
5378
  const validateTime = (timeString) => {
@@ -5038,7 +5381,7 @@ function ITTimePicker({
5038
5381
  };
5039
5382
  const currentHour = validateTime(inputValue) ? inputValue.split(":")[0] : null;
5040
5383
  const currentMinute = validateTime(inputValue) ? inputValue.split(":")[1] : null;
5041
- useEffect10(() => {
5384
+ useEffect11(() => {
5042
5385
  if (isOpen) {
5043
5386
  setTimeout(() => {
5044
5387
  if (hoursRef.current && currentHour) {
@@ -5108,8 +5451,8 @@ function ITTimePicker({
5108
5451
  { length: 60 },
5109
5452
  (_, i) => i.toString().padStart(2, "0")
5110
5453
  );
5111
- return /* @__PURE__ */ jsxs24("div", { ref: wrapperRef, className: clsx27("relative w-full", className), children: [
5112
- /* @__PURE__ */ jsx30(
5454
+ return /* @__PURE__ */ jsxs25("div", { ref: wrapperRef, className: clsx28("relative w-full", className), children: [
5455
+ /* @__PURE__ */ jsx31(
5113
5456
  ITInput,
5114
5457
  {
5115
5458
  name,
@@ -5126,350 +5469,120 @@ function ITTimePicker({
5126
5469
  size,
5127
5470
  touched,
5128
5471
  error: !isValidTime ? "Hora inv\xE1lida" : typeof error === "string" ? error : void 0,
5129
- iconRight: /* @__PURE__ */ jsx30(
5130
- FaClock,
5131
- {
5132
- onClick: () => {
5133
- if (!disabled) {
5134
- setIsOpen(!isOpen);
5135
- }
5136
- },
5137
- className: clsx27(
5138
- "cursor-pointer transition-colors",
5139
- disabled ? "text-slate-400 cursor-not-allowed" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
5140
- )
5141
- }
5142
- )
5143
- }
5144
- ),
5145
- isOpen && !disabled && createPortal5(
5146
- /* @__PURE__ */ jsxs24(
5147
- "div",
5148
- {
5149
- ref: dropdownRef,
5150
- 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",
5151
- style: panelStyle,
5152
- children: [
5153
- /* @__PURE__ */ jsxs24("div", { className: "flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider", children: [
5154
- /* @__PURE__ */ jsx30(ITText, { as: "div", className: "flex-1 text-center py-2 border-r border-secondary-100", children: "Horas" }),
5155
- /* @__PURE__ */ jsx30(ITText, { as: "div", className: "flex-1 text-center py-2", children: "Minutos" })
5156
- ] }),
5157
- /* @__PURE__ */ jsxs24("div", { className: "flex h-56 relative bg-white", children: [
5158
- /* @__PURE__ */ jsx30(
5159
- "div",
5160
- {
5161
- ref: hoursRef,
5162
- className: "flex-1 overflow-y-auto no-scrollbar border-r border-secondary-50 scroll-smooth relative",
5163
- children: /* @__PURE__ */ jsx30("div", { className: "py-2", children: hoursList.map((h) => {
5164
- const isSelected = currentHour === h;
5165
- return /* @__PURE__ */ jsx30(
5166
- "div",
5167
- {
5168
- "data-value": h,
5169
- className: clsx27(
5170
- "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5171
- isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5172
- ),
5173
- style: {
5174
- backgroundColor: isSelected ? activeColor : void 0
5175
- },
5176
- onMouseEnter: (e) => {
5177
- if (!isSelected)
5178
- e.currentTarget.style.backgroundColor = highlightColor;
5179
- },
5180
- onMouseLeave: (e) => {
5181
- if (!isSelected)
5182
- e.currentTarget.style.backgroundColor = "transparent";
5183
- },
5184
- onClick: () => handleHourSelect(h),
5185
- children: h
5186
- },
5187
- h
5188
- );
5189
- }) })
5190
- }
5191
- ),
5192
- /* @__PURE__ */ jsx30(
5193
- "div",
5194
- {
5195
- ref: minutesRef,
5196
- className: "flex-1 overflow-y-auto no-scrollbar scroll-smooth relative",
5197
- children: /* @__PURE__ */ jsx30("div", { className: "py-2", children: minutesList.map((m) => {
5198
- const isSelected = currentMinute === m;
5199
- return /* @__PURE__ */ jsx30(
5200
- "div",
5201
- {
5202
- "data-value": m,
5203
- className: clsx27(
5204
- "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5205
- isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5206
- ),
5207
- style: {
5208
- backgroundColor: isSelected ? activeColor : void 0
5209
- },
5210
- onMouseEnter: (e) => {
5211
- if (!isSelected)
5212
- e.currentTarget.style.backgroundColor = highlightColor;
5213
- },
5214
- onMouseLeave: (e) => {
5215
- if (!isSelected)
5216
- e.currentTarget.style.backgroundColor = "transparent";
5217
- },
5218
- onClick: () => handleMinuteSelect(m),
5219
- children: m
5220
- },
5221
- m
5222
- );
5223
- }) })
5224
- }
5225
- ),
5226
- /* @__PURE__ */ jsx30("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" })
5227
- ] }),
5228
- /* @__PURE__ */ jsx30("div", { className: "p-3 bg-secondary-50 border-t border-secondary-100 flex justify-end", children: /* @__PURE__ */ jsx30(
5229
- ITButton,
5230
- {
5231
- variant: "solid",
5232
- color,
5233
- size: "sm",
5234
- onClick: handleConfirm,
5235
- children: /* @__PURE__ */ jsx30(ITText, { as: "span", children: "Aceptar" })
5236
- }
5237
- ) })
5238
- ]
5239
- }
5240
- ),
5241
- document.body
5242
- )
5243
- ] });
5244
- }
5245
-
5246
- // src/components/molecules/search-select/search-select.tsx
5247
- import { useState as useState21, useEffect as useEffect11, useRef as useRef16, useMemo as useMemo7 } from "react";
5248
- import { createPortal as createPortal6 } from "react-dom";
5249
- import clsx28 from "clsx";
5250
- import { FaSearch as FaSearch2, FaTimes as FaTimes7 } from "react-icons/fa";
5251
- import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
5252
- function ITSearchSelect({
5253
- name,
5254
- options = [],
5255
- label,
5256
- placeholder = "Selecciona una opci\xF3n",
5257
- valueField = "value",
5258
- labelField = "label",
5259
- value,
5260
- onChange,
5261
- onBlur,
5262
- disabled = false,
5263
- className,
5264
- touched,
5265
- required,
5266
- error,
5267
- readOnly = false,
5268
- onSearch,
5269
- isLoading = false,
5270
- noResultsMessage = "No se encontraron resultados",
5271
- size = "md",
5272
- renderOption,
5273
- clearable = true,
5274
- onClear
5275
- }) {
5276
- const [isOpen, setIsOpen] = useState21(false);
5277
- const [searchTerm, setSearchTerm] = useState21("");
5278
- const [isFocused, setIsFocused] = useState21(false);
5279
- const [localTouched, setLocalTouched] = useState21(false);
5280
- const containerRef = useRef16(null);
5281
- const inputWrapperRef = useRef16(null);
5282
- const timeoutRef = useRef16(null);
5283
- const { panelRef, style: panelStyle } = useFloatingPanel(inputWrapperRef, isOpen, {
5284
- estimatedHeight: 260,
5285
- matchWidth: true
5286
- });
5287
- const selectedOption = useMemo7(() => {
5288
- return options.find((opt) => opt[valueField] === value);
5289
- }, [options, value, valueField]);
5290
- useEffect11(() => {
5291
- if (!isFocused) {
5292
- setSearchTerm(selectedOption ? String(selectedOption[labelField]) : "");
5293
- }
5294
- }, [selectedOption, isFocused, labelField]);
5295
- useEffect11(() => {
5296
- function handleClickOutside(event) {
5297
- const target = event.target;
5298
- const inContainer = containerRef.current?.contains(target);
5299
- const inPanel = panelRef.current?.contains(target);
5300
- if (!inContainer && !inPanel) {
5301
- setIsOpen(false);
5302
- }
5303
- }
5304
- document.addEventListener("mousedown", handleClickOutside);
5305
- return () => document.removeEventListener("mousedown", handleClickOutside);
5306
- }, []);
5307
- const selectedLabel = selectedOption ? String(selectedOption[labelField]) : "";
5308
- const filteredOptions = useMemo7(() => {
5309
- if (onSearch) return options;
5310
- if (!searchTerm || !isFocused || searchTerm === selectedLabel) return options;
5311
- return options.filter(
5312
- (opt) => String(opt[labelField]).toLowerCase().includes(searchTerm.toLowerCase())
5313
- );
5314
- }, [options, searchTerm, selectedLabel, onSearch, labelField, isFocused]);
5315
- const handleInputChange = (e) => {
5316
- const query = e.target.value;
5317
- setSearchTerm(query);
5318
- setIsOpen(true);
5319
- if (onSearch) {
5320
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
5321
- timeoutRef.current = setTimeout(() => {
5322
- onSearch(query);
5323
- }, 500);
5324
- }
5325
- };
5326
- const handleSelect = (option) => {
5327
- if (onChange) {
5328
- onChange(option[valueField], option);
5329
- }
5330
- setSearchTerm(String(option[labelField]));
5331
- setIsOpen(false);
5332
- };
5333
- const handleClear = () => {
5334
- setSearchTerm("");
5335
- setIsOpen(true);
5336
- if (onSearch) onSearch("");
5337
- if (value !== void 0 && value !== null && value !== "") {
5338
- onChange?.("", void 0);
5339
- }
5340
- onClear?.();
5341
- };
5342
- const handleFocus = () => {
5343
- if (disabled || readOnly) return;
5344
- setIsFocused(true);
5345
- setIsOpen(true);
5346
- };
5347
- const handleInputBlur = (e) => {
5348
- setTimeout(() => {
5349
- setIsFocused(false);
5350
- setLocalTouched(true);
5351
- onBlur?.(e);
5352
- }, 200);
5353
- };
5354
- const inputTheme = theme.input || {};
5355
- const isTouched = touched !== void 0 ? touched : localTouched;
5356
- const isEmpty = value === void 0 || value === null || String(value).trim() === "";
5357
- const effectiveError = error !== void 0 && error !== false ? error === true ? "Este campo es requerido" : error : required && isEmpty ? "Este campo es requerido" : void 0;
5358
- const hasError = isTouched && !!effectiveError;
5359
- const errorMessage = typeof effectiveError === "string" ? effectiveError : "Este campo es requerido";
5360
- const showClearButton = clearable && !disabled && !readOnly && (searchTerm.length > 0 || !isEmpty);
5361
- const getInputStyle = () => {
5362
- const sizeConfig = inputSizeTokens[size] ?? inputSizeTokens.md;
5363
- const style = {
5364
- backgroundColor: inputTheme.backgroundColor || "#ffffff",
5365
- borderColor: inputTheme.borderColor || "var(--color-secondary-300)",
5366
- borderRadius: inputTheme.borderRadius || "0.5rem",
5367
- padding: sizeConfig.padding,
5368
- fontSize: sizeConfig.fontSize,
5369
- borderWidth: "1px",
5370
- borderStyle: "solid",
5371
- transition: "all 0.2s",
5372
- color: "var(--it-input-text-color, var(--color-secondary-900))",
5373
- width: "100%"
5374
- };
5375
- if (disabled) {
5376
- style.backgroundColor = inputTheme.disabled?.backgroundColor || "var(--color-secondary-100)";
5377
- style.borderColor = inputTheme.disabled?.borderColor || "var(--color-secondary-200)";
5378
- style.opacity = 0.7;
5379
- style.cursor = "not-allowed";
5380
- }
5381
- if (hasError) {
5382
- style.borderColor = inputTheme.error?.borderColor || "red";
5383
- if (isFocused) {
5384
- style.boxShadow = inputTheme.error?.ring;
5385
- }
5386
- } else if (isFocused && !readOnly) {
5387
- style.boxShadow = inputTheme.focus?.ring;
5388
- style.borderColor = inputTheme.focus?.borderColor;
5389
- }
5390
- return style;
5391
- };
5392
- return /* @__PURE__ */ jsxs25("div", { className: clsx28("w-full flex flex-col gap-1.5", className, isOpen && "relative z-30"), ref: containerRef, children: [
5393
- label && /* @__PURE__ */ jsxs25(
5394
- ITText,
5395
- {
5396
- as: "label",
5397
- className: clsx28("text-sm font-medium text-secondary-700 dark:text-slate-300", {
5398
- "text-danger-500": hasError
5399
- }),
5400
- children: [
5401
- /* @__PURE__ */ jsx31(ITText, { as: "span", children: label }),
5402
- required && /* @__PURE__ */ jsx31(ITText, { as: "span", className: "text-danger-500 ml-1", children: "*" })
5403
- ]
5404
- }
5405
- ),
5406
- /* @__PURE__ */ jsxs25("div", { className: "relative", children: [
5407
- /* @__PURE__ */ jsxs25("div", { ref: inputWrapperRef, className: "relative flex items-center", children: [
5408
- /* @__PURE__ */ jsx31(
5409
- "input",
5472
+ iconRight: /* @__PURE__ */ jsx31(
5473
+ FaClock,
5410
5474
  {
5411
- type: "text",
5412
- name,
5413
- value: searchTerm,
5414
- onChange: handleInputChange,
5415
- onFocus: handleFocus,
5416
- onBlur: handleInputBlur,
5417
- disabled,
5418
- readOnly,
5419
- placeholder,
5420
- className: "outline-none pr-10",
5421
- style: getInputStyle(),
5422
- autoComplete: "off"
5475
+ onClick: () => {
5476
+ if (!disabled) {
5477
+ setIsOpen(!isOpen);
5478
+ }
5479
+ },
5480
+ className: clsx28(
5481
+ "cursor-pointer transition-colors",
5482
+ disabled ? "text-slate-400 cursor-not-allowed" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
5483
+ )
5423
5484
  }
5424
- ),
5425
- /* @__PURE__ */ jsxs25("div", { className: "absolute right-3 flex items-center gap-2 text-secondary-400", children: [
5426
- isLoading && /* @__PURE__ */ jsx31("div", { className: "pointer-events-none animate-spin h-4 w-4 border-2 border-primary-500 border-t-transparent rounded-full" }),
5427
- !isLoading && showClearButton && /* @__PURE__ */ jsx31(
5428
- "button",
5429
- {
5430
- type: "button",
5431
- "aria-label": "Limpiar",
5432
- title: "Limpiar",
5433
- onMouseDown: (e) => {
5434
- e.preventDefault();
5435
- handleClear();
5436
- },
5437
- 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",
5438
- children: /* @__PURE__ */ jsx31(FaTimes7, { size: 14 })
5439
- }
5440
- ),
5441
- !isLoading && !showClearButton && /* @__PURE__ */ jsx31(FaSearch2, { size: 14, className: clsx28("pointer-events-none", { "text-primary-500": isFocused }) })
5442
- ] })
5443
- ] }),
5444
- isOpen && createPortal6(
5445
- /* @__PURE__ */ jsx31(
5446
- "div",
5447
- {
5448
- ref: panelRef,
5449
- style: panelStyle,
5450
- 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",
5451
- children: /* @__PURE__ */ jsx31("div", { className: "max-h-60 overflow-y-auto", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
5452
- const isSelected = value === option[valueField];
5453
- return /* @__PURE__ */ jsx31(
5454
- ITText,
5485
+ )
5486
+ }
5487
+ ),
5488
+ isOpen && !disabled && createPortal6(
5489
+ /* @__PURE__ */ jsxs25(
5490
+ "div",
5491
+ {
5492
+ ref: dropdownRef,
5493
+ 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",
5494
+ style: panelStyle,
5495
+ children: [
5496
+ /* @__PURE__ */ jsxs25("div", { className: "flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider", children: [
5497
+ /* @__PURE__ */ jsx31(ITText, { as: "div", className: "flex-1 text-center py-2 border-r border-secondary-100", children: "Horas" }),
5498
+ /* @__PURE__ */ jsx31(ITText, { as: "div", className: "flex-1 text-center py-2", children: "Minutos" })
5499
+ ] }),
5500
+ /* @__PURE__ */ jsxs25("div", { className: "flex h-56 relative bg-white", children: [
5501
+ /* @__PURE__ */ jsx31(
5502
+ "div",
5455
5503
  {
5456
- as: "div",
5457
- onClick: () => handleSelect(option),
5458
- className: clsx28(
5459
- "px-4 py-2 text-sm cursor-pointer transition-colors",
5460
- 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"
5461
- ),
5462
- children: renderOption ? renderOption(option, { isSelected, searchTerm }) : /* @__PURE__ */ jsx31(ITText, { as: "span", children: option[labelField] })
5463
- },
5464
- option[valueField]
5465
- );
5466
- }) : /* @__PURE__ */ jsx31(ITText, { as: "div", className: "px-4 py-6 text-sm text-center text-secondary-500 italic", children: isLoading ? "Cargando..." : noResultsMessage }) })
5467
- }
5468
- ),
5469
- document.body
5470
- )
5471
- ] }),
5472
- hasError && /* @__PURE__ */ jsx31(ITText, { as: "p", className: "text-danger-500 text-xs mt-1", children: errorMessage })
5504
+ ref: hoursRef,
5505
+ className: "flex-1 overflow-y-auto no-scrollbar border-r border-secondary-50 scroll-smooth relative",
5506
+ children: /* @__PURE__ */ jsx31("div", { className: "py-2", children: hoursList.map((h) => {
5507
+ const isSelected = currentHour === h;
5508
+ return /* @__PURE__ */ jsx31(
5509
+ "div",
5510
+ {
5511
+ "data-value": h,
5512
+ className: clsx28(
5513
+ "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5514
+ isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5515
+ ),
5516
+ style: {
5517
+ backgroundColor: isSelected ? activeColor : void 0
5518
+ },
5519
+ onMouseEnter: (e) => {
5520
+ if (!isSelected)
5521
+ e.currentTarget.style.backgroundColor = highlightColor;
5522
+ },
5523
+ onMouseLeave: (e) => {
5524
+ if (!isSelected)
5525
+ e.currentTarget.style.backgroundColor = "transparent";
5526
+ },
5527
+ onClick: () => handleHourSelect(h),
5528
+ children: h
5529
+ },
5530
+ h
5531
+ );
5532
+ }) })
5533
+ }
5534
+ ),
5535
+ /* @__PURE__ */ jsx31(
5536
+ "div",
5537
+ {
5538
+ ref: minutesRef,
5539
+ className: "flex-1 overflow-y-auto no-scrollbar scroll-smooth relative",
5540
+ children: /* @__PURE__ */ jsx31("div", { className: "py-2", children: minutesList.map((m) => {
5541
+ const isSelected = currentMinute === m;
5542
+ return /* @__PURE__ */ jsx31(
5543
+ "div",
5544
+ {
5545
+ "data-value": m,
5546
+ className: clsx28(
5547
+ "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5548
+ isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5549
+ ),
5550
+ style: {
5551
+ backgroundColor: isSelected ? activeColor : void 0
5552
+ },
5553
+ onMouseEnter: (e) => {
5554
+ if (!isSelected)
5555
+ e.currentTarget.style.backgroundColor = highlightColor;
5556
+ },
5557
+ onMouseLeave: (e) => {
5558
+ if (!isSelected)
5559
+ e.currentTarget.style.backgroundColor = "transparent";
5560
+ },
5561
+ onClick: () => handleMinuteSelect(m),
5562
+ children: m
5563
+ },
5564
+ m
5565
+ );
5566
+ }) })
5567
+ }
5568
+ ),
5569
+ /* @__PURE__ */ jsx31("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" })
5570
+ ] }),
5571
+ /* @__PURE__ */ jsx31("div", { className: "p-3 bg-secondary-50 border-t border-secondary-100 flex justify-end", children: /* @__PURE__ */ jsx31(
5572
+ ITButton,
5573
+ {
5574
+ variant: "solid",
5575
+ color,
5576
+ size: "sm",
5577
+ onClick: handleConfirm,
5578
+ children: /* @__PURE__ */ jsx31(ITText, { as: "span", children: "Aceptar" })
5579
+ }
5580
+ ) })
5581
+ ]
5582
+ }
5583
+ ),
5584
+ document.body
5585
+ )
5473
5586
  ] });
5474
5587
  }
5475
5588
 
@@ -7410,6 +7523,14 @@ function ITSegmentedControl({
7410
7523
  import { useEffect as useEffect13, useRef as useRef20, useState as useState27 } from "react";
7411
7524
  import { FaChevronDown as FaChevronDown4 } from "react-icons/fa";
7412
7525
  import { jsx as jsx55, jsxs as jsxs43 } from "react/jsx-runtime";
7526
+ function isSubItemGroup(entry) {
7527
+ return "items" in entry;
7528
+ }
7529
+ function flattenSubItems(entries) {
7530
+ return entries.flatMap(
7531
+ (entry) => isSubItemGroup(entry) ? entry.items : [entry]
7532
+ );
7533
+ }
7413
7534
  function ITSidebar({
7414
7535
  navigationItems = [],
7415
7536
  isCollapsed = false,
@@ -7455,7 +7576,7 @@ function ITSidebar({
7455
7576
  useEffect13(() => {
7456
7577
  const activeParents = /* @__PURE__ */ new Set();
7457
7578
  navigationItems.forEach((item) => {
7458
- if (item.subitems && item.subitems.some((sub) => sub.isActive)) {
7579
+ if (item.subitems && flattenSubItems(item.subitems).some((sub) => sub.isActive)) {
7459
7580
  activeParents.add(item.id);
7460
7581
  }
7461
7582
  });
@@ -7489,6 +7610,80 @@ function ITSidebar({
7489
7610
  };
7490
7611
  const isSidebarCollapsed = visibleOnMobile ? false : !isHovering && isCollapsed;
7491
7612
  const sidebarWidth = isSidebarCollapsed ? "w-[88px]" : "w-[280px]";
7613
+ const renderSubItem = (subitem) => /* @__PURE__ */ jsx55("li", { className: "relative", children: /* @__PURE__ */ jsxs43(
7614
+ "button",
7615
+ {
7616
+ "aria-current": subitem.isActive ? "page" : void 0,
7617
+ onClick: () => {
7618
+ if (subitem.action) subitem.action();
7619
+ if (onSubItemClick) onSubItemClick(subitem);
7620
+ },
7621
+ className: `flex items-center gap-2 w-full text-left px-3 py-1.5 rounded-xl transition-all duration-300`,
7622
+ style: {
7623
+ color: subitem.isActive ? "var(--it-sidebar-active-color, var(--color-secondary-900))" : "var(--it-sidebar-label-color, var(--color-secondary-600))",
7624
+ backgroundColor: subitem.isActive ? "var(--it-sidebar-active-bg, var(--color-secondary-50))" : "transparent",
7625
+ fontSize: "0.78rem",
7626
+ fontWeight: subitem.isActive ? 600 : 500,
7627
+ letterSpacing: "0.01em",
7628
+ marginLeft: subitemConnector === "|" ? "-1px" : "0"
7629
+ },
7630
+ onMouseEnter: (e) => {
7631
+ if (!subitem.isActive) {
7632
+ e.currentTarget.style.backgroundColor = "var(--it-sidebar-hover-bg, var(--color-secondary-100))";
7633
+ e.currentTarget.style.transform = "translateX(3px)";
7634
+ }
7635
+ },
7636
+ onMouseLeave: (e) => {
7637
+ if (!subitem.isActive) {
7638
+ e.currentTarget.style.backgroundColor = "transparent";
7639
+ e.currentTarget.style.transform = "translateX(0)";
7640
+ }
7641
+ },
7642
+ children: [
7643
+ subitem.isActive && subitemConnector === "|" && /* @__PURE__ */ jsx55(
7644
+ "div",
7645
+ {
7646
+ className: "absolute left-0 top-1/3 bottom-1/3 w-[2.5px] rounded-r-full transition-all",
7647
+ style: {
7648
+ backgroundColor: "var(--it-sidebar-active-icon, var(--color-primary-500))",
7649
+ boxShadow: "0 0 6px color-mix(in srgb, var(--it-sidebar-active-icon, var(--color-primary-500)) 25%, transparent)"
7650
+ }
7651
+ }
7652
+ ),
7653
+ subitemConnector === "dot" && /* @__PURE__ */ jsx55(
7654
+ "span",
7655
+ {
7656
+ className: `w-1.5 h-1.5 rounded-full flex-shrink-0 transition-all duration-300 ${subitem.isActive ? "scale-125" : ""}`,
7657
+ style: {
7658
+ backgroundColor: subitem.isActive ? "var(--it-sidebar-active-icon, var(--color-primary-500))" : "var(--it-sidebar-icon-color, var(--color-secondary-400))"
7659
+ }
7660
+ }
7661
+ ),
7662
+ /* @__PURE__ */ jsx55(ITText, { as: "span", className: "truncate", children: subitem.label })
7663
+ ]
7664
+ }
7665
+ ) }, subitem.id);
7666
+ const renderSubItemGroup = (group, itemId) => {
7667
+ const headingId = `it-sidebar-subgroup-${itemId}-${group.id}`;
7668
+ return /* @__PURE__ */ jsxs43("li", { className: "relative", children: [
7669
+ /* @__PURE__ */ jsx55("div", { id: headingId, className: "px-3 pt-2.5 pb-1 mt-1", children: /* @__PURE__ */ jsx55(
7670
+ ITText,
7671
+ {
7672
+ as: "span",
7673
+ className: "block",
7674
+ style: {
7675
+ color: "var(--it-sidebar-icon-color, var(--color-secondary-400))",
7676
+ fontSize: "0.68rem",
7677
+ fontWeight: 700,
7678
+ letterSpacing: "0.08em",
7679
+ textTransform: "uppercase"
7680
+ },
7681
+ children: group.label
7682
+ }
7683
+ ) }),
7684
+ /* @__PURE__ */ jsx55("ul", { "aria-labelledby": headingId, className: "flex flex-col gap-0", children: group.items.map(renderSubItem) })
7685
+ ] }, group.id);
7686
+ };
7492
7687
  return /* @__PURE__ */ jsxs43(
7493
7688
  "aside",
7494
7689
  {
@@ -7622,7 +7817,7 @@ function ITSidebar({
7622
7817
  item.icon && /* @__PURE__ */ jsx55("span", { style: { color: "var(--it-sidebar-active-icon, var(--color-primary-500))" }, className: "text-xl drop-shadow-sm", children: item.icon }),
7623
7818
  /* @__PURE__ */ jsx55(ITText, { as: "span", className: "tracking-wide text-[15px]", children: item.label })
7624
7819
  ] }),
7625
- item.subitems && item.subitems.length > 0 ? /* @__PURE__ */ jsx55("div", { className: "py-2", children: item.subitems.map((subitem) => /* @__PURE__ */ jsxs43(
7820
+ item.subitems && item.subitems.length > 0 ? /* @__PURE__ */ jsx55("div", { className: "py-2", children: flattenSubItems(item.subitems).map((subitem) => /* @__PURE__ */ jsxs43(
7626
7821
  "div",
7627
7822
  {
7628
7823
  className: `px-5 py-2.5 text-sm flex items-center gap-3 transition-colors relative`,
@@ -7646,66 +7841,16 @@ function ITSidebar({
7646
7841
  ]
7647
7842
  }
7648
7843
  ),
7649
- !isSidebarCollapsed && item.subitems && item.subitems.length > 0 && /* @__PURE__ */ jsx55("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__ */ jsx55(
7844
+ !isSidebarCollapsed && item.subitems && item.subitems.length > 0 && /* @__PURE__ */ jsx55("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__ */ jsx55(
7650
7845
  "ul",
7651
7846
  {
7652
7847
  className: "ml-4 flex flex-col gap-0 py-0.5",
7653
7848
  style: {
7654
7849
  borderLeft: subitemConnector === "|" ? "1px solid var(--it-sidebar-border, var(--color-secondary-200))" : "none"
7655
7850
  },
7656
- children: item.subitems.map((subitem) => /* @__PURE__ */ jsx55("li", { className: "relative", children: /* @__PURE__ */ jsxs43(
7657
- "button",
7658
- {
7659
- "aria-current": subitem.isActive ? "page" : void 0,
7660
- onClick: () => {
7661
- if (subitem.action) subitem.action();
7662
- if (onSubItemClick) onSubItemClick(subitem);
7663
- },
7664
- className: `flex items-center gap-2 w-full text-left px-3 py-1.5 rounded-xl transition-all duration-300`,
7665
- style: {
7666
- color: subitem.isActive ? "var(--it-sidebar-active-color, var(--color-secondary-900))" : "var(--it-sidebar-label-color, var(--color-secondary-600))",
7667
- backgroundColor: subitem.isActive ? "var(--it-sidebar-active-bg, var(--color-secondary-50))" : "transparent",
7668
- fontSize: "0.78rem",
7669
- fontWeight: subitem.isActive ? 600 : 500,
7670
- letterSpacing: "0.01em",
7671
- marginLeft: subitemConnector === "|" ? "-1px" : "0"
7672
- },
7673
- onMouseEnter: (e) => {
7674
- if (!subitem.isActive) {
7675
- e.currentTarget.style.backgroundColor = "var(--it-sidebar-hover-bg, var(--color-secondary-100))";
7676
- e.currentTarget.style.transform = "translateX(3px)";
7677
- }
7678
- },
7679
- onMouseLeave: (e) => {
7680
- if (!subitem.isActive) {
7681
- e.currentTarget.style.backgroundColor = "transparent";
7682
- e.currentTarget.style.transform = "translateX(0)";
7683
- }
7684
- },
7685
- children: [
7686
- subitem.isActive && subitemConnector === "|" && /* @__PURE__ */ jsx55(
7687
- "div",
7688
- {
7689
- className: "absolute left-0 top-1/3 bottom-1/3 w-[2.5px] rounded-r-full transition-all",
7690
- style: {
7691
- backgroundColor: "var(--it-sidebar-active-icon, var(--color-primary-500))",
7692
- boxShadow: "0 0 6px color-mix(in srgb, var(--it-sidebar-active-icon, var(--color-primary-500)) 25%, transparent)"
7693
- }
7694
- }
7695
- ),
7696
- subitemConnector === "dot" && /* @__PURE__ */ jsx55(
7697
- "span",
7698
- {
7699
- className: `w-1.5 h-1.5 rounded-full flex-shrink-0 transition-all duration-300 ${subitem.isActive ? "scale-125" : ""}`,
7700
- style: {
7701
- backgroundColor: subitem.isActive ? "var(--it-sidebar-active-icon, var(--color-primary-500))" : "var(--it-sidebar-icon-color, var(--color-secondary-400))"
7702
- }
7703
- }
7704
- ),
7705
- /* @__PURE__ */ jsx55(ITText, { as: "span", className: "truncate", children: subitem.label })
7706
- ]
7707
- }
7708
- ) }, subitem.id))
7851
+ children: item.subitems.map(
7852
+ (entry) => isSubItemGroup(entry) ? renderSubItemGroup(entry, item.id) : renderSubItem(entry)
7853
+ )
7709
7854
  }
7710
7855
  ) })
7711
7856
  ] }, item.id);
@@ -7905,6 +8050,7 @@ import {
7905
8050
  FaThLarge as FaThLarge2
7906
8051
  } from "react-icons/fa";
7907
8052
  import { MdOutlineSwapVert as MdOutlineSwapVert2 } from "react-icons/md";
8053
+ import { isSameDay as isSameDay2, startOfDay as startOfDay2, endOfDay } from "date-fns";
7908
8054
  import { Fragment as Fragment9, jsx as jsx59, jsxs as jsxs46 } from "react/jsx-runtime";
7909
8055
  function ITTable({
7910
8056
  columns,
@@ -7988,15 +8134,32 @@ function ITTable({
7988
8134
  }, [data, sortConfig, columns]);
7989
8135
  const filteredData = sortedData.filter(
7990
8136
  (row) => columns.every((col) => {
7991
- if (!col.filter || filters[col.key] === void 0 || filters[col.key] === "")
8137
+ const rawFilter = filters[col.key];
8138
+ if (!col.filter || rawFilter === void 0 || rawFilter === "") return true;
8139
+ if (Array.isArray(rawFilter) && rawFilter[0] == null && rawFilter[1] == null) {
7992
8140
  return true;
8141
+ }
7993
8142
  const value = getNestedValue(row, col.key);
7994
- const filterValue = String(filters[col.key]).toLowerCase();
8143
+ if (col.filter === "date" || col.filter === "date-range") {
8144
+ const rowDate = value instanceof Date ? value : new Date(String(value));
8145
+ if (isNaN(rowDate.getTime())) return false;
8146
+ if (col.filter === "date") {
8147
+ return isSameDay2(rowDate, rawFilter);
8148
+ }
8149
+ const [start, end] = rawFilter;
8150
+ if (start && rowDate.getTime() < startOfDay2(start).getTime()) return false;
8151
+ if (end && rowDate.getTime() > endOfDay(end).getTime()) return false;
8152
+ return true;
8153
+ }
8154
+ if (col.filter === "search") {
8155
+ return String(value) === String(rawFilter);
8156
+ }
8157
+ const filterValue = String(rawFilter).toLowerCase();
7995
8158
  switch (col.type) {
7996
8159
  case "number":
7997
8160
  return String(value).includes(filterValue);
7998
8161
  case "boolean":
7999
- return value === filters[col.key];
8162
+ return value === rawFilter;
8000
8163
  case "catalog": {
8001
8164
  if (!col.catalogOptions) return true;
8002
8165
  const catalogItem = col.catalogOptions.data.find(
@@ -8019,6 +8182,7 @@ function ITTable({
8019
8182
  const isStickyHeader = stickyHeader && isTableVirtual;
8020
8183
  const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
8021
8184
  const columnCount = columns.length;
8185
+ const pinnedMeta = React11.useMemo(() => getPinnedColumnMeta(columns), [columns]);
8022
8186
  const {
8023
8187
  scrollRef,
8024
8188
  startIndex,
@@ -8102,6 +8266,75 @@ function ITTable({
8102
8266
  }
8103
8267
  );
8104
8268
  }
8269
+ if (col.filter === "search" && col.catalogOptions) {
8270
+ if (col.catalogOptions.loading) {
8271
+ return /* @__PURE__ */ jsx59(
8272
+ FaSpinner3,
8273
+ {
8274
+ className: "animate-spin",
8275
+ "aria-label": "Cargando opciones",
8276
+ title: "Cargando opciones"
8277
+ }
8278
+ );
8279
+ }
8280
+ if (col.catalogOptions.error) {
8281
+ return /* @__PURE__ */ jsx59(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
8282
+ }
8283
+ const searchValue = filters[col.key];
8284
+ return /* @__PURE__ */ jsx59(
8285
+ ITSearchSelect,
8286
+ {
8287
+ name: `filter-${col.key}`,
8288
+ options: col.catalogOptions.data.map((item) => ({
8289
+ value: item.id,
8290
+ label: item.name
8291
+ })),
8292
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
8293
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
8294
+ onSearch: col.catalogOptions.onSearch,
8295
+ isLoading: col.catalogOptions.loading,
8296
+ size: "sm",
8297
+ placeholder: "Buscar...",
8298
+ clearable: true,
8299
+ className: "w-full",
8300
+ onBlur: () => {
8301
+ }
8302
+ }
8303
+ );
8304
+ }
8305
+ if (col.filter === "date") {
8306
+ const dateValue = filters[col.key];
8307
+ return /* @__PURE__ */ jsx59(
8308
+ ITDatePicker,
8309
+ {
8310
+ name: `filter-${col.key}`,
8311
+ value: dateValue instanceof Date ? dateValue : void 0,
8312
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8313
+ minDate: col.dateFilterOptions?.minDate,
8314
+ maxDate: col.dateFilterOptions?.maxDate,
8315
+ size: "sm",
8316
+ placeholder: "dd/mm/aaaa",
8317
+ className: "w-full"
8318
+ }
8319
+ );
8320
+ }
8321
+ if (col.filter === "date-range") {
8322
+ const rangeValue = filters[col.key];
8323
+ return /* @__PURE__ */ jsx59(
8324
+ ITDatePicker,
8325
+ {
8326
+ name: `filter-${col.key}`,
8327
+ range: true,
8328
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
8329
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8330
+ minDate: col.dateFilterOptions?.minDate,
8331
+ maxDate: col.dateFilterOptions?.maxDate,
8332
+ size: "sm",
8333
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
8334
+ className: "w-full"
8335
+ }
8336
+ );
8337
+ }
8105
8338
  return /* @__PURE__ */ jsx59(
8106
8339
  ITInput,
8107
8340
  {
@@ -8274,37 +8507,45 @@ function ITTable({
8274
8507
  {
8275
8508
  className: clsx43(tableHeaderRow, "dark:text-slate-200"),
8276
8509
  "aria-rowindex": isTableVirtual ? 1 : void 0,
8277
- children: columns.map((col) => /* @__PURE__ */ jsx59(
8278
- "th",
8279
- {
8280
- scope: "col",
8281
- className: clsx43(
8282
- tableHeaderCell(col.className, density),
8283
- col.align && tableAlignClasses[col.align],
8284
- isStickyHeader && "sticky top-0 z-10 bg-secondary-50"
8285
- ),
8286
- style: col.minWidth != null || isStickyHeader ? {
8287
- ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8288
- ...isStickyHeader ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {}
8289
- } : void 0,
8290
- children: /* @__PURE__ */ jsxs46("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
8291
- /* @__PURE__ */ jsxs46("div", { className: "flex items-center justify-between gap-2", children: [
8292
- /* @__PURE__ */ jsx59(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
8293
- col.sortable && col.type !== "actions" && /* @__PURE__ */ jsx59(
8294
- "button",
8295
- {
8296
- onClick: () => handleSort(col.key),
8297
- 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"}`,
8298
- title: `Ordenar por ${col.label}`,
8299
- children: /* @__PURE__ */ jsx59(MdOutlineSwapVert2, { className: "w-4 h-4", "aria-hidden": "true" })
8300
- }
8301
- )
8302
- ] }),
8303
- /* @__PURE__ */ jsx59("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
8304
- ] })
8305
- },
8306
- col.key
8307
- ))
8510
+ children: columns.map((col) => {
8511
+ const pin = pinnedMeta[col.key];
8512
+ const isPinned = pin != null;
8513
+ return /* @__PURE__ */ jsx59(
8514
+ "th",
8515
+ {
8516
+ scope: "col",
8517
+ className: clsx43(
8518
+ tableHeaderCell(col.className, density),
8519
+ col.align && tableAlignClasses[col.align],
8520
+ isPinned && "sticky",
8521
+ isStickyHeader && "sticky top-0 bg-secondary-50",
8522
+ isPinned ? "z-[15]" : isStickyHeader && "z-10",
8523
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right")
8524
+ ),
8525
+ style: col.minWidth != null || isStickyHeader || isPinned ? {
8526
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8527
+ ...isStickyHeader || isPinned ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {},
8528
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
8529
+ } : void 0,
8530
+ children: /* @__PURE__ */ jsxs46("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
8531
+ /* @__PURE__ */ jsxs46("div", { className: "flex items-center justify-between gap-2", children: [
8532
+ /* @__PURE__ */ jsx59(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
8533
+ col.sortable && col.type !== "actions" && /* @__PURE__ */ jsx59(
8534
+ "button",
8535
+ {
8536
+ onClick: () => handleSort(col.key),
8537
+ 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"}`,
8538
+ title: `Ordenar por ${col.label}`,
8539
+ children: /* @__PURE__ */ jsx59(MdOutlineSwapVert2, { className: "w-4 h-4", "aria-hidden": "true" })
8540
+ }
8541
+ )
8542
+ ] }),
8543
+ /* @__PURE__ */ jsx59("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
8544
+ ] })
8545
+ },
8546
+ col.key
8547
+ );
8548
+ })
8308
8549
  }
8309
8550
  ) }),
8310
8551
  /* @__PURE__ */ jsx59("tbody", { className: clsx43(tableBody, "dark:divide-slate-700/30"), children: currentData.length > 0 ? /* @__PURE__ */ jsxs46(Fragment9, { children: [
@@ -8326,14 +8567,22 @@ function ITTable({
8326
8567
  children: columns.map((col) => {
8327
8568
  const rawValue = getNestedValue(row, col.key);
8328
8569
  const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
8570
+ const pin = pinnedMeta[col.key];
8571
+ const isPinned = pin != null;
8329
8572
  return /* @__PURE__ */ jsx59(
8330
8573
  "td",
8331
8574
  {
8332
8575
  className: clsx43(
8333
8576
  tableCell(col.className, density),
8334
- col.align && tableAlignClasses[col.align]
8577
+ col.align && tableAlignClasses[col.align],
8578
+ isPinned && "sticky bg-[var(--color-table-rowBg,white)] group-hover:bg-[var(--color-table-rowHover,var(--color-secondary-50))]",
8579
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
8580
+ isPinned && "z-[1]"
8335
8581
  ),
8336
- style: col.minWidth != null ? { minWidth: `${col.minWidth}px` } : void 0,
8582
+ style: col.minWidth != null || isPinned ? {
8583
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8584
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
8585
+ } : void 0,
8337
8586
  title: truncateTitle,
8338
8587
  children: col.type === "actions" ? /* @__PURE__ */ jsx59("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ jsx59("div", { className: clsx43(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
8339
8588
  },