@axzydev/axzy_ui_system 1.2.9 → 1.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +6 -0
  2. package/dist/index.cjs +141 -73
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +1 -1
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.cts +141 -5
  7. package/dist/index.d.ts +141 -5
  8. package/dist/index.js +141 -73
  9. package/dist/index.js.map +1 -1
  10. package/package.json +4 -3
  11. package/snippets/axzy-ui-system.code-snippets +547 -0
  12. package/src/App.tsx +37 -34
  13. package/src/components/avatar/avatar.props.ts +12 -1
  14. package/src/components/avatar/avatar.stories.tsx +19 -0
  15. package/src/components/avatar/avatar.tsx +26 -3
  16. package/src/components/confirm-dialog/confirm-dialog.tsx +1 -1
  17. package/src/components/data-table/dataTable.props.ts +10 -0
  18. package/src/components/data-table/dataTable.tsx +24 -13
  19. package/src/components/date-picker/datePicker.tsx +1 -1
  20. package/src/components/dialog/dialog.tsx +2 -1
  21. package/src/components/drawer/drawer.tsx +1 -1
  22. package/src/components/dropfile/dropfile.props.ts +6 -0
  23. package/src/components/dropfile/dropfile.tsx +51 -16
  24. package/src/components/layout/layout.tsx +1 -1
  25. package/src/components/navbar/navbar.tsx +2 -2
  26. package/src/components/popover/popover.tsx +1 -1
  27. package/src/components/search-select/search-select.tsx +4 -4
  28. package/src/components/select/select.tsx +6 -8
  29. package/src/components/sidebar/sidebar.tsx +15 -15
  30. package/src/components/stepper/stepper.props.ts +4 -0
  31. package/src/components/table/table.props.ts +21 -3
  32. package/src/components/table/table.tsx +24 -13
  33. package/src/components/theme-provider/themeProvider.props.ts +21 -3
  34. package/src/components/time-picker/timePicker.tsx +1 -1
  35. package/src/components/toast/toast.tsx +1 -1
  36. package/src/components/tooltip/tooltip.tsx +1 -1
  37. package/src/components/topbar/topbar.tsx +1 -1
  38. package/src/dev.css +1 -1
  39. package/src/hooks/useClickOutside.ts +8 -0
  40. package/src/hooks/useTableState.ts +5 -2
  41. package/src/index.css +1 -1
  42. package/src/showcases/HomeShowcase.tsx +95 -3
  43. package/src/theme/theme.ts +21 -0
  44. package/src/types/field.types.ts +70 -7
package/src/App.tsx CHANGED
@@ -1,10 +1,9 @@
1
1
  import React, { useEffect, useMemo, useState } from "react";
2
2
  import {
3
3
  FaCreditCard,
4
- FaHome,
4
+ FaHome,
5
5
  FaKeyboard,
6
6
  FaRegBell,
7
- FaSearch,
8
7
  FaSlidersH,
9
8
  FaTable,
10
9
  } from "react-icons/fa";
@@ -61,36 +60,35 @@ import {
61
60
  ThemeProviderShowcase,
62
61
  } from "./showcases/FeedbackShowcases";
63
62
 
63
+ type ViewMode = "home" | "ui-system";
64
+
64
65
  function App() {
65
- const [activeComponentId, setActiveComponentId] = useState(
66
- () => window.location.hash.replace("#", "") || "home"
67
- );
68
- const [searchTerm, setSearchTerm] = useState("");
69
- const [subitemConnector, setSubitemConnector] = useState<
66
+ const [view, setView] = useState<ViewMode>(() => {
67
+ const hash = window.location.hash.replace("#", "");
68
+ return hash.startsWith("ui-system") ? "ui-system" : "home";
69
+ });
70
+ const [showroomActive, setShowroomActive] = useState("getting-started");
71
+ const [searchTerm] = useState("");
72
+ const [subitemConnector] = useState<
70
73
  "dot" | "|" | "none"
71
74
  >("dot");
72
75
 
73
76
  useEffect(() => {
74
77
  const onHashChange = () => {
75
- const id = window.location.hash.replace("#", "") || "home";
76
- setActiveComponentId(id);
78
+ const hash = window.location.hash.replace("#", "");
79
+ setView(hash.startsWith("ui-system") ? "ui-system" : "home");
77
80
  };
78
81
  window.addEventListener("hashchange", onHashChange);
79
82
  return () => window.removeEventListener("hashchange", onHashChange);
80
83
  }, []);
81
84
 
82
- useEffect(() => {
83
- window.location.hash = activeComponentId;
84
- }, [activeComponentId]);
85
-
86
- // Group definitions for the sidebar
85
+ // Group definitions for the sidebar (UI System showroom)
87
86
  const categories = [
88
87
  {
89
88
  id: "general",
90
89
  label: "General",
91
90
  icon: <FaHome />,
92
91
  subitems: [
93
- { id: "home", label: "Home" },
94
92
  { id: "getting-started", label: "Getting Started" },
95
93
  ],
96
94
  },
@@ -174,8 +172,8 @@ function App() {
174
172
  if (matches) {
175
173
  return {
176
174
  ...cat,
177
- isActive: activeComponentId === cat.id,
178
- action: () => setActiveComponentId(cat.id),
175
+ isActive: showroomActive === cat.id,
176
+ action: () => setShowroomActive(cat.id),
179
177
  };
180
178
  }
181
179
  return null;
@@ -190,8 +188,8 @@ function App() {
190
188
  const mappedSubitems = matchingSubitems.map((sub) => ({
191
189
  id: sub.id,
192
190
  label: sub.label,
193
- isActive: activeComponentId === sub.id,
194
- action: () => setActiveComponentId(sub.id),
191
+ isActive: showroomActive === sub.id,
192
+ action: () => setShowroomActive(sub.id),
195
193
  }));
196
194
 
197
195
  const isAnySubitemActive = mappedSubitems.some((sub) => sub.isActive);
@@ -207,7 +205,7 @@ function App() {
207
205
  if (cat.subitems) return cat.subitems.length > 0;
208
206
  return true;
209
207
  });
210
- }, [searchTerm, activeComponentId]);
208
+ }, [searchTerm, showroomActive]);
211
209
 
212
210
  const sidebarProps = {
213
211
  navigationItems: filteredNavigationItems,
@@ -215,27 +213,24 @@ function App() {
215
213
  };
216
214
 
217
215
  const topBarProps = {
218
- logoText: "AXZY Showroom",
216
+ logoText: "AXZY UI System",
219
217
  userMenu: {
220
218
  userName: "Alex Dev",
221
219
  userEmail: "alex@axzy.dev",
222
220
  menuItems: [
223
221
  {
224
- label: "Resetear Demo",
222
+ label: "Ir al Portafolio",
225
223
  onClick: () => {
226
- setActiveComponentId("home");
227
- setSearchTerm("");
224
+ window.location.hash = "home";
228
225
  },
229
226
  },
230
227
  ],
231
228
  },
232
229
  };
233
230
 
234
- // Render correct component based on active navigation
231
+ // Render correct component based on active showroom navigation
235
232
  const renderShowcase = () => {
236
- switch (activeComponentId) {
237
- case "home":
238
- return <HomeShowcase />;
233
+ switch (showroomActive) {
239
234
  case "getting-started":
240
235
  return <GettingStartedShowcase />;
241
236
  // Structure
@@ -308,17 +303,25 @@ function App() {
308
303
  case "themeprovider":
309
304
  return <ThemeProviderShowcase />;
310
305
  default:
311
- return <HomeShowcase />;
306
+ return <GettingStartedShowcase />;
312
307
  }
313
308
  };
314
309
 
315
310
  return (
316
- <ITThemeProvider showFab={true}>
317
- <ITLayout sidebar={sidebarProps} topBar={topBarProps}>
318
- <div className="max-w-7xl mx-auto">
319
- {renderShowcase()}
311
+ <ITThemeProvider showFab={false}>
312
+ {view === "home" ? (
313
+ <div className="min-h-screen bg-slate-50 dark:bg-slate-950 py-10 px-4 sm:px-6 lg:px-8">
314
+ <div className="max-w-6xl mx-auto">
315
+ <HomeShowcase />
316
+ </div>
320
317
  </div>
321
- </ITLayout>
318
+ ) : (
319
+ <ITLayout sidebar={sidebarProps} topBar={topBarProps}>
320
+ <div className="max-w-7xl mx-auto">
321
+ {renderShowcase()}
322
+ </div>
323
+ </ITLayout>
324
+ )}
322
325
  </ITThemeProvider>
323
326
  );
324
327
  }
@@ -11,7 +11,18 @@ export interface ITAvatarProps {
11
11
  initials?: string;
12
12
  /** Avatar dimensions. Valid values: `"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"`. @default "md" */
13
13
  size?: AvatarSize;
14
- /** Background color class for the initials fallback. @default "bg-primary-600" */
14
+ /**
15
+ * Color de fondo para el fallback de iniciales. Acepta un valor de color
16
+ * real (`"#8b5cf6"`, `"rgb(...)"`, `"hsl(...)"`, `"var(--...)"`) — se
17
+ * aplica como `style` inline y SIEMPRE se renderiza — o una clase de
18
+ * Tailwind (`"bg-purple-600"`) por compatibilidad con código existente.
19
+ * Una clase de Tailwind solo se ve si esa clase exacta ya existe en el
20
+ * CSS compilado que consume la app (esta librería se distribuye con un
21
+ * CSS estático pre-compilado, ver scripts/build-css.mjs), así que para
22
+ * cualquier color calculado en tiempo de ejecución (p.ej. un hash por
23
+ * usuario) se recomienda pasar el valor de color directamente.
24
+ * @default "bg-primary-600"
25
+ */
15
26
  color?: string;
16
27
  /** Additional CSS class names for the avatar container. */
17
28
  className?: string;
@@ -44,3 +44,22 @@ export const Sizes: Story = {
44
44
  </div>
45
45
  ),
46
46
  };
47
+
48
+ export const WithRawColor: Story = {
49
+ name: "Con color calculado en runtime",
50
+ parameters: {
51
+ docs: {
52
+ description: {
53
+ story:
54
+ "Cuando el color se calcula dinámicamente (por ejemplo, un hash por usuario o etiqueta), pasa un valor de color real en vez de una clase de Tailwind. Una clase de Tailwind arbitraria solo se ve si ya existe en el CSS pre-compilado de esta librería; un color inline siempre se aplica.",
55
+ },
56
+ },
57
+ },
58
+ render: () => (
59
+ <div className="flex items-center gap-4">
60
+ {["#3b82f6", "#a855f7", "#059669", "#f59e0b", "#ec4899"].map((hex) => (
61
+ <ITAvatar key={hex} initials="JD" size="md" color={hex} />
62
+ ))}
63
+ </div>
64
+ ),
65
+ };
@@ -14,6 +14,17 @@ const DEFAULT_COLOR = "bg-primary-600";
14
14
  const DEFAULT_BG = "var(--color-primary-600)";
15
15
  const DEFAULT_SHADOW = "0 4px 14px 0 rgba(37, 99, 235, 0.35)";
16
16
 
17
+ // Un valor tipo "#8b5cf6", "rgb(...)", "hsl(...)" o "var(--...)" se aplica
18
+ // como color inline; cualquier otra cosa se trata como clase de Tailwind
19
+ // (comportamiento previo, sin romper a quien ya pasa "bg-purple-600" etc.).
20
+ // Motivo: esta librería se consume vía un CSS estático pre-compilado
21
+ // (ver scripts/build-css.mjs) que solo contiene las clases usadas en el
22
+ // código FUENTE de la librería. Si una app consumidora pasa un color de
23
+ // Tailwind que la librería nunca usa en ningún otro lado, esa clase no
24
+ // existe en el CSS entregado y el avatar se renderiza sin color visible.
25
+ // Un valor de color inline no tiene ese problema: siempre se aplica.
26
+ const isRawColorValue = (value: string) => /^#|^rgb|^hsl|^var\(/i.test(value.trim());
27
+
17
28
  /**
18
29
  * Circular avatar component with image, initials fallback, and optional badge overlay.
19
30
  *
@@ -22,6 +33,11 @@ const DEFAULT_SHADOW = "0 4px 14px 0 rgba(37, 99, 235, 0.35)";
22
33
  *
23
34
  * @example
24
35
  * <ITAvatar initials="JD" size="md" color="bg-purple-600" />
36
+ *
37
+ * @example
38
+ * // Recomendado cuando el color se calcula en tiempo de ejecución (p.ej. un
39
+ * // hash por usuario/etiqueta): pasa un valor de color real, no una clase.
40
+ * <ITAvatar initials="JD" size="md" color="#8b5cf6" />
25
41
  */
26
42
  export default function ITAvatar({
27
43
  src,
@@ -34,17 +50,24 @@ export default function ITAvatar({
34
50
  onClick,
35
51
  }: ITAvatarProps) {
36
52
  const { container, text } = sizeMap[size];
37
- const useInlineStyle = !color || color === DEFAULT_COLOR;
53
+ const useDefaultStyle = !color || color === DEFAULT_COLOR;
54
+ const useRawColorStyle = !useDefaultStyle && isRawColorValue(color);
38
55
 
39
56
  return (
40
57
  <div
41
58
  className={clsx(
42
59
  "relative inline-flex items-center justify-center rounded-full flex-shrink-0 overflow-hidden text-white font-bold tracking-wide",
43
60
  container,
44
- !useInlineStyle && color,
61
+ !useDefaultStyle && !useRawColorStyle && color,
45
62
  className,
46
63
  )}
47
- style={useInlineStyle ? { backgroundColor: DEFAULT_BG, boxShadow: DEFAULT_SHADOW } : undefined}
64
+ style={
65
+ useDefaultStyle
66
+ ? { backgroundColor: DEFAULT_BG, boxShadow: DEFAULT_SHADOW }
67
+ : useRawColorStyle
68
+ ? { backgroundColor: color }
69
+ : undefined
70
+ }
48
71
  onClick={onClick}
49
72
  role={onClick ? "button" : undefined}
50
73
  tabIndex={onClick ? 0 : undefined}
@@ -37,7 +37,7 @@ export default function ITConfirmDialog({
37
37
  if (!isOpen) return null;
38
38
 
39
39
  return (
40
- <div className="fixed inset-0 z-[300] flex items-center justify-center p-4">
40
+ <div className="fixed inset-0 z-[60] flex items-center justify-center p-4">
41
41
  <div className="absolute inset-0 bg-black/40 backdrop-blur-sm" onClick={onClose} />
42
42
  <div
43
43
  className={clsx(
@@ -1,18 +1,28 @@
1
1
  import { ReactNode } from "react";
2
2
  import { Column } from "../table/table.props";
3
3
 
4
+ /** Parameters passed to `fetchData` every time pagination, filters, or sorting change. */
4
5
  export interface ITDataTableFetchParams {
6
+ /** 1-indexed current page number. */
5
7
  page: number;
8
+ /** Number of rows requested per page. */
6
9
  limit: number;
10
+ /** Active per-column filter values (from `Column.filter`), keyed by column `key`. */
7
11
  filters: Record<string, string | number | boolean | Date>;
12
+ /** Active sort, present only when the user has clicked a sortable column header. */
8
13
  sort?: {
14
+ /** Column `key` currently sorted by. */
9
15
  key: string;
16
+ /** Sort direction. */
10
17
  direction: "asc" | "desc";
11
18
  };
12
19
  }
13
20
 
21
+ /** Expected shape of the Promise returned by `fetchData`. */
14
22
  export interface ITDataTableResponse<T> {
23
+ /** Rows for the requested page. */
15
24
  data: T[];
25
+ /** Total row count across all pages (used to compute the paginator's total pages). */
16
26
  total: number;
17
27
  }
18
28
 
@@ -11,6 +11,17 @@ import { Column } from "../table/table.props";
11
11
  import { formatCurrencyMX } from "../table/table";
12
12
  import { ITDataTableProps } from "./dataTable.props";
13
13
  import ITText from "@/components/text/text";
14
+ import {
15
+ tableActionsCell,
16
+ tableBody,
17
+ tableCell,
18
+ tableCellText,
19
+ tableContainer,
20
+ tableEmptyContent,
21
+ tableHeaderCell,
22
+ tableHeaderRow,
23
+ tableRow,
24
+ } from "@/utils/styles";
14
25
 
15
26
  const getNestedValue = (obj: unknown, path: string) => {
16
27
  return path.split(".").reduce((acc, part) => acc && acc[part], obj);
@@ -157,7 +168,7 @@ export default function ITDataTable<T extends Record<string, unknown>>({
157
168
  return <FaSpinner className="animate-spin" aria-label="Cargando opciones" title="Cargando opciones" />;
158
169
  }
159
170
  if (col.catalogOptions.error) {
160
- return <ITText as="span" className="text-red-500 text-xs">Error cargando</ITText>;
171
+ return <ITText as="span" className="text-danger-500 text-xs">Error cargando</ITText>;
161
172
  }
162
173
  return (
163
174
  <ITSelect
@@ -203,9 +214,9 @@ export default function ITDataTable<T extends Record<string, unknown>>({
203
214
  return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
204
215
  case "boolean":
205
216
  return value ? (
206
- <FaCheck className="text-green-500" aria-label="Verdadero" title="Verdadero" />
217
+ <FaCheck className="text-success-500" aria-label="Verdadero" title="Verdadero" />
207
218
  ) : (
208
- <FaTimes className="text-red-500" aria-label="Falso" title="Falso" />
219
+ <FaTimes className="text-danger-500" aria-label="Falso" title="Falso" />
209
220
  );
210
221
  case "actions":
211
222
  return col.actions ? col.actions(row) : null;
@@ -253,7 +264,7 @@ export default function ITDataTable<T extends Record<string, unknown>>({
253
264
 
254
265
  return (
255
266
  <div className={clsx("space-y-4 w-full relative", containerClassName)}>
256
- <div className="rounded-xl shadow-sm overflow-hidden" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
267
+ <div className={tableContainer} style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
257
268
  {title && (
258
269
  <div className="px-6 py-5 flex items-center justify-between" style={{ backgroundColor: 'var(--color-table-rowBg, #ffffff)' }}>
259
270
  <ITText as="h2" className="text-xl font-bold text-secondary-900 leading-tight">{title}</ITText>
@@ -316,7 +327,7 @@ export default function ITDataTable<T extends Record<string, unknown>>({
316
327
  ))
317
328
  ) : (
318
329
  !isLoading && (
319
- <div className="flex flex-col items-center justify-center py-12 text-secondary-400">
330
+ <div className={clsx(tableEmptyContent, "py-12")}>
320
331
  <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
321
332
  <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
322
333
  </div>
@@ -336,9 +347,9 @@ export default function ITDataTable<T extends Record<string, unknown>>({
336
347
  )}
337
348
  >
338
349
  <thead>
339
- <tr className="bg-secondary-50 text-xs uppercase tracking-wider font-semibold text-slate-700 dark:text-slate-200">
350
+ <tr className={clsx(tableHeaderRow, "dark:text-slate-200")}>
340
351
  {columns.map((col) => (
341
- <th key={col.key} scope="col" className={clsx("px-4 py-4 align-top", col.className)}>
352
+ <th key={col.key} scope="col" className={tableHeaderCell(col.className)}>
342
353
  <div className="flex flex-col gap-3 min-w-[150px]">
343
354
  <div className="flex items-center justify-between gap-2">
344
355
  <ITText as="span" className="text-slate-900 dark:text-white font-bold">{col.label}</ITText>
@@ -364,18 +375,18 @@ export default function ITDataTable<T extends Record<string, unknown>>({
364
375
  ))}
365
376
  </tr>
366
377
  </thead>
367
- <tbody className="divide-y divide-slate-100 dark:divide-slate-700/30">
378
+ <tbody className={clsx(tableBody, "dark:divide-slate-700/30")}>
368
379
  {data.length > 0 ? (
369
380
  data.map((row, rowIndex) => (
370
- <tr key={rowIndex} className={clsx("hover:bg-secondary-50/50 transition-colors duration-150 group", variant === "striped" && "odd:bg-secondary-50/40 dark:odd:bg-slate-800/20")}>
381
+ <tr key={rowIndex} className={clsx(tableRow, variant === "striped" && "odd:bg-secondary-50/40 dark:odd:bg-slate-800/20")}>
371
382
  {columns.map((col) => (
372
- <td key={`${rowIndex}-${col.key}`} className={clsx("px-4 py-3 align-middle", col.className)}>
383
+ <td key={`${rowIndex}-${col.key}`} className={tableCell(col.className)}>
373
384
  {col.type === "actions" ? (
374
- <div className="flex items-center justify-center gap-2">
385
+ <div className={tableActionsCell}>
375
386
  {renderCellContent(col, row) as React.ReactNode}
376
387
  </div>
377
388
  ) : (
378
- <div className="text-secondary-700 font-medium">
389
+ <div className={tableCellText}>
379
390
  {renderCellContent(col, row) as React.ReactNode}
380
391
  </div>
381
392
  )}
@@ -387,7 +398,7 @@ export default function ITDataTable<T extends Record<string, unknown>>({
387
398
  <tr>
388
399
  <td colSpan={columns.length} className="px-6 py-12 text-center">
389
400
  {!isLoading && (
390
- <div className="flex flex-col items-center justify-center text-secondary-400">
401
+ <div className={tableEmptyContent}>
391
402
  <ITText as="span" className="text-lg">No se encontraron resultados</ITText>
392
403
  <ITText as="span" className="text-sm mt-1">Intenta ajustar los filtros</ITText>
393
404
  </div>
@@ -303,7 +303,7 @@ export default function ITDatePicker({
303
303
  {isOpen && (
304
304
  <div
305
305
  className={clsx(
306
- "fixed z-[9999]",
306
+ "fixed z-[70]",
307
307
  calendarClassName,
308
308
  range ? "w-[320px]" : "w-[280px]"
309
309
  )}
@@ -67,9 +67,10 @@ export default function ITDialog({
67
67
 
68
68
  const content = (
69
69
  <div
70
+ data-it-dialog="true"
70
71
  className={`fixed inset-0 flex ${
71
72
  fullScreen ? "items-stretch" : "items-center justify-center"
72
- } bg-black/50 z-[9999]`}
73
+ } bg-black/50 z-[60]`}
73
74
  >
74
75
  <div
75
76
  ref={modalRef}
@@ -41,7 +41,7 @@ export default function ITDrawer({
41
41
  return (
42
42
  <>
43
43
  {isOpen && (
44
- <div className="fixed inset-0 z-[100] flex">
44
+ <div className="fixed inset-0 z-[50] flex">
45
45
  <div className="absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" />
46
46
  <div
47
47
  ref={panelRef}
@@ -7,6 +7,12 @@ export enum FileTypeEnum {
7
7
  PNG = "image/png",
8
8
  JPG = "image/jpg",
9
9
  JPEG = "image/jpeg",
10
+ MP4 = "video/mp4",
11
+ MOV = "video/quicktime",
12
+ AVI = "video/x-msvideo",
13
+ MKV = "video/x-matroska",
14
+ VIDEO_3GPP = "video/3gpp",
15
+ WEBM = "video/webm",
10
16
  }
11
17
 
12
18
  /** Upload lifecycle status */
@@ -3,6 +3,7 @@ import { useDropzone } from "react-dropzone";
3
3
  // import pdfjsLib from "@/hooks/pdf"; // Disabled as hook is missing
4
4
  import clsx from "clsx";
5
5
  import ITText from "@/components/text/text";
6
+ import ITButton from "@/components/button/button";
6
7
  import { ITDropfileProps, FileTypeEnum, UploadStatus } from "./dropfile.props";
7
8
  export { FileTypeEnum, UploadStatus } from "./dropfile.props";
8
9
 
@@ -94,6 +95,24 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
94
95
  case FileTypeEnum.JPEG:
95
96
  accept[FileTypeEnum.JPEG] = [".jpeg", ".jpg"];
96
97
  break;
98
+ case FileTypeEnum.MP4:
99
+ accept[FileTypeEnum.MP4] = [".mp4"];
100
+ break;
101
+ case FileTypeEnum.MOV:
102
+ accept[FileTypeEnum.MOV] = [".mov"];
103
+ break;
104
+ case FileTypeEnum.AVI:
105
+ accept[FileTypeEnum.AVI] = [".avi"];
106
+ break;
107
+ case FileTypeEnum.MKV:
108
+ accept[FileTypeEnum.MKV] = [".mkv"];
109
+ break;
110
+ case FileTypeEnum.VIDEO_3GPP:
111
+ accept[FileTypeEnum.VIDEO_3GPP] = [".3gp"];
112
+ break;
113
+ case FileTypeEnum.WEBM:
114
+ accept[FileTypeEnum.WEBM] = [".webm"];
115
+ break;
97
116
  }
98
117
  });
99
118
 
@@ -121,6 +140,14 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
121
140
  case FileTypeEnum.JPEG:
122
141
  if (!extensions.includes("IMAGEN")) extensions.push("IMAGEN");
123
142
  break;
143
+ case FileTypeEnum.MP4:
144
+ case FileTypeEnum.MOV:
145
+ case FileTypeEnum.AVI:
146
+ case FileTypeEnum.MKV:
147
+ case FileTypeEnum.VIDEO_3GPP:
148
+ case FileTypeEnum.WEBM:
149
+ if (!extensions.includes("VIDEO")) extensions.push("VIDEO");
150
+ break;
124
151
  }
125
152
  });
126
153
 
@@ -341,35 +368,43 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
341
368
  <div className="px-3 py-2 bg-white border-t border-gray-100 flex justify-end gap-2">
342
369
  {!isConfirmed ? (
343
370
  <>
344
- <button
371
+ <ITButton
345
372
  type="button"
373
+ variant="outlined"
374
+ color="secondary"
375
+ size="small"
346
376
  onClick={handleCancel}
347
- className="px-3 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
348
377
  >
349
- <ITText as="span">Cancelar</ITText>
350
- </button>
351
- <button
378
+ <ITText>Cancelar</ITText>
379
+ </ITButton>
380
+ <ITButton
352
381
  type="button"
382
+ variant="filled"
383
+ color="primary"
384
+ size="small"
353
385
  onClick={handleConfirm}
354
- className="px-3 py-1.5 text-xs font-medium text-white bg-primary-600 rounded-lg hover:bg-primary-700 shadow-sm transition-colors flex items-center gap-1"
355
386
  >
356
- <ITText as="span">Confirmar</ITText>
357
- <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
358
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
359
- </svg>
360
- </button>
387
+ <div className="flex items-center gap-2">
388
+ <ITText>Confirmar</ITText>
389
+ <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
390
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
391
+ </svg>
392
+ </div>
393
+ </ITButton>
361
394
  </>
362
395
  ) : (
363
- <button
396
+ <ITButton
364
397
  type="button"
398
+ variant="outlined"
399
+ color="danger"
400
+ size="small"
365
401
  onClick={handleDelete}
366
- className="px-3 py-1.5 text-xs font-medium text-danger-600 bg-danger-50 border border-danger-100 rounded-lg hover:bg-danger-100 transition-colors flex items-center gap-1"
367
402
  >
368
403
  <svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
369
404
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
370
405
  </svg>
371
- <ITText as="span">Eliminar</ITText>
372
- </button>
406
+ <ITText>Eliminar</ITText>
407
+ </ITButton>
373
408
  )}
374
409
  </div>
375
410
 
@@ -392,4 +427,4 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
392
427
  );
393
428
  };
394
429
 
395
- export default ITDropfile;
430
+ export default ITDropfile;
@@ -73,7 +73,7 @@ export default function ITLayout({
73
73
  {/* MOBILE SIDEBAR PANE */}
74
74
  {mobileSidebarOpen && (
75
75
  <div
76
- className="lg:hidden fixed inset-0 z-50 transition-opacity duration-300 backdrop-blur-sm bg-black/40"
76
+ className="lg:hidden fixed inset-0 z-[40] transition-opacity duration-300 backdrop-blur-sm bg-black/40"
77
77
  onClick={() => setMobileSidebarOpen(false)}
78
78
  >
79
79
  <div
@@ -116,7 +116,7 @@ export default function ITNavbar({
116
116
  {isUserMenuOpen && (
117
117
  <div
118
118
  ref={userMenuRef}
119
- className="z-50 absolute right-0 mt-2 text-base list-none bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
119
+ className="z-[70] absolute right-0 mt-2 text-base list-none bg-white divide-y divide-gray-100 rounded-lg shadow-sm"
120
120
  >
121
121
  <div className="px-4 py-3">
122
122
  <ITText as="span" className="block text-sm text-gray-900">
@@ -152,7 +152,7 @@ export default function ITNavbar({
152
152
 
153
153
  <div className="flex-1 flex overflow-hidden relative">
154
154
  {(showSidebar || showSidebarOnMobile) && (
155
- <aside className="fixed inset-y-0 left-0 w-64 bg-gray-50 transform transition-transform duration-300 ease-in-out z-50 shadow-lg md:static md:transform-none md:shadow-none md:border-r md:border-gray-200">
155
+ <aside className="fixed inset-y-0 left-0 w-64 bg-gray-50 transform transition-transform duration-300 ease-in-out z-[40] shadow-lg md:static md:transform-none md:shadow-none md:border-r md:border-gray-200">
156
156
  <div className="h-full overflow-y-auto py-4 px-3">
157
157
  <ul className="space-y-2 font-medium">{sidebarItems}</ul>
158
158
  </div>
@@ -47,7 +47,7 @@ export default function ITPopover({
47
47
  {trigger}
48
48
  </div>
49
49
  {open && (
50
- <div className={clsx("absolute z-[200]", positionClasses[position])}>
50
+ <div className={clsx("absolute z-[70]", positionClasses[position])}>
51
51
  <div className="bg-white dark:bg-slate-800 rounded-xl shadow-xl border border-slate-200 dark:border-slate-700 p-3 min-w-[160px]">
52
52
  {children}
53
53
  </div>
@@ -148,7 +148,7 @@ export default function ITSearchSelect({
148
148
  const getInputStyle = () => {
149
149
  const style: React.CSSProperties = {
150
150
  backgroundColor: inputTheme.backgroundColor || "#ffffff",
151
- borderColor: inputTheme.borderColor || "#e2e8f0",
151
+ borderColor: inputTheme.borderColor || "var(--color-secondary-300)",
152
152
  borderRadius: inputTheme.borderRadius || "0.5rem",
153
153
  padding: inputTheme.padding || "0.5rem 0.75rem",
154
154
  fontSize: inputTheme.fontSize || "0.875rem",
@@ -160,8 +160,8 @@ export default function ITSearchSelect({
160
160
  };
161
161
 
162
162
  if (disabled) {
163
- style.backgroundColor = inputTheme.disabled?.backgroundColor || "#f1f5f9";
164
- style.borderColor = inputTheme.disabled?.borderColor || "#e2e8f0";
163
+ style.backgroundColor = inputTheme.disabled?.backgroundColor || "var(--color-secondary-100)";
164
+ style.borderColor = inputTheme.disabled?.borderColor || "var(--color-secondary-200)";
165
165
  style.opacity = 0.7;
166
166
  style.cursor = "not-allowed";
167
167
  }
@@ -217,7 +217,7 @@ export default function ITSearchSelect({
217
217
 
218
218
  {/* Dropdown Panel */}
219
219
  {isOpen && (
220
- <div className="absolute z-50 w-full mt-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded-lg shadow-xl overflow-hidden animate-in fade-in zoom-in duration-200 origin-top">
220
+ <div className="absolute z-[70] w-full mt-1 bg-white dark:bg-slate-900 border border-gray-200 dark:border-slate-800 rounded-lg shadow-xl overflow-hidden animate-in fade-in zoom-in duration-200 origin-top">
221
221
  <div className="max-h-60 overflow-y-auto">
222
222
  {filteredOptions.length > 0 ? (
223
223
  filteredOptions.map((option) => (