@mci-ui/mci-ui 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1157 @@
1
+ // src/shared/ui/breadcrumb/Breadcrumb.tsx
2
+ import { ChevronRight } from "lucide-react";
3
+
4
+ // src/shared/lib/utils.ts
5
+ import { clsx } from "clsx";
6
+ import { twMerge } from "tailwind-merge";
7
+ function cn(...inputs) {
8
+ return twMerge(clsx(inputs));
9
+ }
10
+ function useEscapeKey(callback) {
11
+ const handleEscape = (e) => {
12
+ if (e.key === "Escape") callback();
13
+ };
14
+ return { handleEscape };
15
+ }
16
+ function useClickOutside(ref, callback) {
17
+ const handleClick = (e) => {
18
+ if (ref.current && !ref.current.contains(e.target)) {
19
+ callback();
20
+ }
21
+ };
22
+ return { handleClick };
23
+ }
24
+
25
+ // src/shared/ui/breadcrumb/Breadcrumb.tsx
26
+ import { jsx, jsxs } from "react/jsx-runtime";
27
+ function Breadcrumb({
28
+ items,
29
+ className,
30
+ separatorIcon = /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4 text-gray-400 dark:text-gray-500" })
31
+ }) {
32
+ return /* @__PURE__ */ jsx(
33
+ "nav",
34
+ {
35
+ className: cn(
36
+ "flex items-center space-x-2 text-sm font-medium text-gray-600 dark:text-gray-300",
37
+ className
38
+ ),
39
+ "aria-label": "Breadcrumb",
40
+ children: items.map((item, index) => {
41
+ const isLast = index === items.length - 1;
42
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
43
+ item.href ? /* @__PURE__ */ jsx(
44
+ "a",
45
+ {
46
+ href: item.href,
47
+ onClick: item.onClick,
48
+ className: cn(
49
+ "hover:text-primary-600 dark:hover:text-primary-400 transition-colors",
50
+ isLast && "text-primary-600 dark:text-primary-400"
51
+ ),
52
+ children: item.label
53
+ }
54
+ ) : /* @__PURE__ */ jsx(
55
+ "span",
56
+ {
57
+ className: cn(
58
+ isLast ? "text-primary-600 dark:text-primary-400" : "text-gray-500 dark:text-gray-400"
59
+ ),
60
+ children: item.label
61
+ }
62
+ ),
63
+ !isLast && /* @__PURE__ */ jsx("span", { className: "mx-2 flex items-center", children: separatorIcon })
64
+ ] }, index);
65
+ })
66
+ }
67
+ );
68
+ }
69
+
70
+ // src/shared/ui/button/Button.tsx
71
+ import { Loader } from "lucide-react";
72
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
73
+ function Button({
74
+ text,
75
+ icon,
76
+ iconPosition = "left",
77
+ size = "md",
78
+ variant = "accent",
79
+ loading = false,
80
+ disabled = false,
81
+ onClick,
82
+ className
83
+ }) {
84
+ const sizes2 = {
85
+ sm: "h-[38px] px-3 text-sm gap-2",
86
+ md: "h-[48px] px-4 text-base gap-2.5",
87
+ lg: "h-[56px] px-5 text-lg gap-3"
88
+ };
89
+ const variants2 = {
90
+ primary: `
91
+ bg-secondary-500
92
+ hover:bg-secondary-600
93
+ active:bg-secondary-700
94
+ hover:shadow-lg
95
+ hover:shadow-secondary-500/30
96
+ active:scale-[0.98]
97
+ text-white
98
+ `,
99
+ secondary: `
100
+ bg-secondary-50
101
+ hover:bg-secondary-100
102
+ active:bg-secondary-200
103
+ hover:shadow-md
104
+ hover:shadow-secondary-500/10
105
+ active:scale-[0.98]
106
+ text-secondary-700
107
+ border border-secondary-200
108
+ hover:border-secondary-300
109
+ `,
110
+ accent: `
111
+ bg-accent-500
112
+ hover:bg-accent-600
113
+ active:bg-accent-700
114
+ hover:shadow-lg
115
+ hover:shadow-accent-500/30
116
+ active:scale-[0.98]
117
+ text-white
118
+ `
119
+ };
120
+ return /* @__PURE__ */ jsxs2(
121
+ "button",
122
+ {
123
+ onClick,
124
+ disabled: disabled || loading,
125
+ className: cn(
126
+ "inline-flex items-center justify-center rounded-[7px] font-medium",
127
+ "transition-all duration-300 ease-in-out",
128
+ "transform hover:-translate-y-0.5",
129
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:translate-y-0 disabled:hover:shadow-none",
130
+ "focus:outline-none focus:ring-2 focus:ring-offset-2",
131
+ variant === "primary" && "focus:ring-secondary-500",
132
+ variant === "secondary" && "focus:ring-secondary-400",
133
+ variant === "accent" && "focus:ring-accent-500",
134
+ variants2[variant],
135
+ sizes2[size],
136
+ className
137
+ ),
138
+ children: [
139
+ icon && iconPosition === "left" && /* @__PURE__ */ jsx2("span", { className: "flex items-center justify-center transition-transform duration-300 ease-in-out group-hover:scale-110", children: loading ? /* @__PURE__ */ jsx2(Loader, { className: "animate-spin", size: 20 }) : icon }),
140
+ text && /* @__PURE__ */ jsx2("span", { className: "transition-all duration-300", children: text }),
141
+ icon && iconPosition === "right" && /* @__PURE__ */ jsx2("span", { className: "flex items-center justify-center transition-transform duration-300 ease-in-out group-hover:scale-110", children: loading ? /* @__PURE__ */ jsx2(Loader, { className: "animate-spin", size: 20 }) : icon }),
142
+ loading && /* @__PURE__ */ jsx2(Loader, { className: "animate-spin", size: 20 })
143
+ ]
144
+ }
145
+ );
146
+ }
147
+
148
+ // src/shared/ui/collapse/Collapse.tsx
149
+ import { ChevronDownIcon } from "lucide-react";
150
+ import { useEffect, useRef, useState } from "react";
151
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
152
+ function Collapse({
153
+ title,
154
+ children,
155
+ defaultOpen = false,
156
+ icon,
157
+ variant = "primary",
158
+ className,
159
+ titleClassName,
160
+ contentClassName
161
+ }) {
162
+ const [isOpen, setIsOpen] = useState(defaultOpen);
163
+ const [contentHeight, setContentHeight] = useState(0);
164
+ const contentRef = useRef(null);
165
+ useEffect(() => {
166
+ if (contentRef.current) {
167
+ setContentHeight(isOpen ? contentRef.current.scrollHeight : 0);
168
+ }
169
+ }, [isOpen]);
170
+ const variantClasses = {
171
+ primary: {
172
+ title: "bg-secondary-50 hover:bg-secondary-100 border-secondary-200 text-secondary-800",
173
+ content: "bg-secondary-25 border-secondary-100"
174
+ },
175
+ secondary: {
176
+ title: "bg-accent-50 hover:bg-accent-100 border-accent-200 text-accent-800",
177
+ content: "bg-accent-25 border-accent-100"
178
+ },
179
+ accent: {
180
+ title: "bg-gray-50 hover:bg-gray-100 border-gray-200 text-gray-800",
181
+ content: "bg-gray-25 border-gray-100"
182
+ }
183
+ };
184
+ const variantConfig = variantClasses[variant];
185
+ return /* @__PURE__ */ jsxs3("div", { className: cn("border rounded-lg overflow-hidden", className), children: [
186
+ /* @__PURE__ */ jsxs3(
187
+ "button",
188
+ {
189
+ onClick: () => setIsOpen(!isOpen),
190
+ className: cn(
191
+ "w-full flex items-center justify-between p-4 transition-all duration-300",
192
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-blue-500",
193
+ "border-b",
194
+ variantConfig.title
195
+ ),
196
+ children: [
197
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3", children: [
198
+ icon && /* @__PURE__ */ jsx3("span", { className: "flex-shrink-0", children: icon }),
199
+ /* @__PURE__ */ jsx3("span", { className: cn("font-medium text-left", titleClassName), children: title })
200
+ ] }),
201
+ /* @__PURE__ */ jsx3(
202
+ ChevronDownIcon,
203
+ {
204
+ className: cn(
205
+ "w-5 h-5 transition-transform duration-300 flex-shrink-0",
206
+ isOpen && "rotate-180"
207
+ )
208
+ }
209
+ )
210
+ ]
211
+ }
212
+ ),
213
+ /* @__PURE__ */ jsx3(
214
+ "div",
215
+ {
216
+ className: cn(
217
+ "transition-all duration-300 ease-out overflow-hidden",
218
+ variantConfig.content
219
+ ),
220
+ style: {
221
+ height: `${contentHeight}px`
222
+ },
223
+ children: /* @__PURE__ */ jsx3("div", { ref: contentRef, className: cn("p-4", contentClassName), children })
224
+ }
225
+ )
226
+ ] });
227
+ }
228
+
229
+ // src/shared/ui/inputMain/InputMain.tsx
230
+ import { Eye, EyeOff } from "lucide-react";
231
+ import { useMemo, useState as useState2 } from "react";
232
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
233
+ function InputMain({
234
+ label,
235
+ placeholder,
236
+ type = "text",
237
+ icon,
238
+ iconPosition = "left",
239
+ size = "md",
240
+ error,
241
+ success,
242
+ disabled = false,
243
+ required = false,
244
+ value,
245
+ onChange,
246
+ onFocus,
247
+ onBlur,
248
+ className
249
+ }) {
250
+ const [isFocused, setIsFocused] = useState2(false);
251
+ const [internalValue, setInternalValue] = useState2("");
252
+ const [showPassword, setShowPassword] = useState2(false);
253
+ const [autoFilled, setAutoFilled] = useState2(false);
254
+ const currentValue = value ?? internalValue;
255
+ const hasValue = Boolean(currentValue) || autoFilled;
256
+ const isPassword = type === "password";
257
+ const handleFocus = () => {
258
+ setIsFocused(true);
259
+ onFocus?.();
260
+ };
261
+ const handleBlur = () => {
262
+ setIsFocused(false);
263
+ onBlur?.();
264
+ };
265
+ const handleChange = (e) => {
266
+ if (value === void 0) setInternalValue(e.target.value);
267
+ onChange?.(e);
268
+ };
269
+ const togglePassword = () => setShowPassword((p) => !p);
270
+ const sizes2 = useMemo(
271
+ () => ({
272
+ sm: {
273
+ input: "h-[38px] text-sm",
274
+ padding: icon ? iconPosition === "left" ? "pl-10 pr-3" : "pl-3 pr-10" : "px-3",
275
+ icon: "w-4 h-4",
276
+ iconWrapper: iconPosition === "left" ? "left-3" : "right-3",
277
+ labelFont: "text-xs"
278
+ },
279
+ md: {
280
+ input: "h-[48px] text-base",
281
+ padding: icon ? iconPosition === "left" ? "pl-12 pr-4" : "pl-4 pr-12" : "px-4",
282
+ icon: "w-5 h-5",
283
+ iconWrapper: iconPosition === "left" ? "left-3.5" : "right-3.5",
284
+ labelFont: "text-sm"
285
+ },
286
+ lg: {
287
+ input: "h-[56px] text-lg",
288
+ padding: icon ? iconPosition === "left" ? "pl-14 pr-5" : "pl-5 pr-14" : "px-5",
289
+ icon: "w-6 h-6",
290
+ iconWrapper: iconPosition === "left" ? "left-4" : "right-4",
291
+ labelFont: "text-base"
292
+ }
293
+ }),
294
+ [icon, iconPosition]
295
+ );
296
+ const stateStyles = useMemo(() => {
297
+ if (error)
298
+ return "border-error-500 focus:border-error-600 focus:ring-error-500/20";
299
+ if (success)
300
+ return "border-success-500 focus:border-success-600 focus:ring-success-500/20";
301
+ return "border-gray-300 hover:border-gray-400 focus:border-accent-500 focus:ring-accent-500/20";
302
+ }, [error, success]);
303
+ const handleAutoFill = (e) => {
304
+ if (e.animationName === "onAutoFillStart") {
305
+ setAutoFilled(true);
306
+ } else if (e.animationName === "onAutoFillCancel") {
307
+ setAutoFilled(false);
308
+ }
309
+ };
310
+ return /* @__PURE__ */ jsxs4("div", { className: cn("w-full", className), children: [
311
+ /* @__PURE__ */ jsxs4("div", { className: "relative flex items-center", children: [
312
+ /* @__PURE__ */ jsx4(
313
+ "input",
314
+ {
315
+ type: isPassword && showPassword ? "text" : type,
316
+ value: currentValue,
317
+ onChange: handleChange,
318
+ onFocus: handleFocus,
319
+ onBlur: handleBlur,
320
+ onAnimationStart: handleAutoFill,
321
+ disabled,
322
+ placeholder: label ? "" : placeholder,
323
+ required,
324
+ className: cn(
325
+ "w-full rounded-[7px] border bg-white font-medium outline-none transition-all duration-300 ease-in-out",
326
+ "focus:ring-4 disabled:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-60 autofill:shadow-[inset_0_0_0px_1000px_white]",
327
+ sizes2[size].input,
328
+ sizes2[size].padding,
329
+ stateStyles
330
+ ),
331
+ autoComplete: "on"
332
+ }
333
+ ),
334
+ label && /* @__PURE__ */ jsxs4(
335
+ "label",
336
+ {
337
+ className: cn(
338
+ "absolute pointer-events-none transition-all duration-300 ease-in-out font-medium",
339
+ icon && iconPosition === "left" && !hasValue && !isFocused ? sizes2[size].padding : "left-4",
340
+ isFocused || hasValue ? cn(
341
+ "top-0 -translate-y-1/2 bg-white px-2",
342
+ sizes2[size].labelFont,
343
+ error ? "text-error-600" : success ? "text-success-600" : "text-accent-600"
344
+ ) : cn(
345
+ "top-1/2 -translate-y-1/2 text-gray-500",
346
+ sizes2[size].input.includes("38") && "text-sm",
347
+ sizes2[size].input.includes("48") && "text-base",
348
+ sizes2[size].input.includes("56") && "text-lg"
349
+ )
350
+ ),
351
+ children: [
352
+ label,
353
+ required && /* @__PURE__ */ jsx4("span", { className: "text-error-500 ml-1", children: "*" })
354
+ ]
355
+ }
356
+ ),
357
+ icon && /* @__PURE__ */ jsx4(
358
+ "div",
359
+ {
360
+ className: cn(
361
+ "absolute top-1/2 -translate-y-1/2 flex items-center transition-all duration-300",
362
+ sizes2[size].iconWrapper,
363
+ error ? "text-error-500" : success ? "text-success-500" : isFocused ? "text-accent-500" : "text-gray-400"
364
+ ),
365
+ children: /* @__PURE__ */ jsx4("span", { className: cn(sizes2[size].icon, "mr-2"), children: icon })
366
+ }
367
+ ),
368
+ isPassword && /* @__PURE__ */ jsx4(
369
+ "button",
370
+ {
371
+ type: "button",
372
+ onClick: togglePassword,
373
+ className: cn(
374
+ "absolute top-1/2 -translate-y-1/2 flex items-center justify-center text-gray-400 hover:text-gray-600 transition-all",
375
+ "right-3"
376
+ ),
377
+ children: showPassword ? /* @__PURE__ */ jsx4(EyeOff, { className: cn(sizes2[size].icon) }) : /* @__PURE__ */ jsx4(Eye, { className: cn(sizes2[size].icon) })
378
+ }
379
+ )
380
+ ] }),
381
+ error && /* @__PURE__ */ jsx4("p", { className: "mt-1.5 text-sm text-error-600 flex items-center gap-1 animate-[slideDown_0.3s_ease-out]", children: error }),
382
+ success && !error && /* @__PURE__ */ jsx4("p", { className: "mt-1.5 text-sm text-success-600 flex items-center gap-1 animate-[slideDown_0.3s_ease-out]", children: success }),
383
+ /* @__PURE__ */ jsx4("style", { children: `
384
+ input {
385
+ animation-name: onAutoFillCancel;
386
+ }
387
+ input:-webkit-autofill {
388
+ animation-name: onAutoFillStart;
389
+ }
390
+ @keyframes onAutoFillStart {}
391
+ @keyframes onAutoFillCancel {}
392
+ ` })
393
+ ] });
394
+ }
395
+
396
+ // src/shared/ui/mciTable/MciTable.tsx
397
+ import { ArrowUpDown, Box, ChevronDown, ChevronUp } from "lucide-react";
398
+ import { useMemo as useMemo2, useState as useState6 } from "react";
399
+
400
+ // src/shared/ui/modal/Modal.tsx
401
+ import { X } from "lucide-react";
402
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
403
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
404
+ function Modal({
405
+ show,
406
+ setShow,
407
+ title,
408
+ Header,
409
+ Body,
410
+ footer
411
+ }) {
412
+ const modalRef = useRef2(null);
413
+ const { handleEscape } = useEscapeKey(() => setShow(false));
414
+ useEffect2(() => {
415
+ if (show) {
416
+ document.addEventListener("keydown", handleEscape);
417
+ document.body.style.overflow = "hidden";
418
+ } else {
419
+ document.body.style.overflow = "unset";
420
+ }
421
+ return () => document.removeEventListener("keydown", handleEscape);
422
+ }, [show, handleEscape]);
423
+ const { handleClick } = useClickOutside(modalRef, () => setShow(false));
424
+ useEffect2(() => {
425
+ if (show) document.addEventListener("mousedown", handleClick);
426
+ return () => document.removeEventListener("mousedown", handleClick);
427
+ }, [show, handleClick]);
428
+ return /* @__PURE__ */ jsx5(
429
+ "div",
430
+ {
431
+ className: cn(
432
+ "fixed inset-0 z-50 flex items-center justify-center p-4 bg-secondary-100/50 backdrop-blur-sm transition-all duration-500 ease-in-out",
433
+ show ? "opacity-100 pointer-events-auto" : "opacity-0 pointer-events-none"
434
+ ),
435
+ children: /* @__PURE__ */ jsxs5(
436
+ "div",
437
+ {
438
+ ref: modalRef,
439
+ className: cn(
440
+ "relative w-full max-w-lg rounded-[7px] shadow-xl bg-secondary-50 text-gray-800",
441
+ "transform transition-all duration-500 ease-out",
442
+ show ? "opacity-100 scale-100" : "opacity-0 scale-90"
443
+ ),
444
+ children: [
445
+ (Header || title) && /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-6 py-4 border-b border-secondary-300", children: [
446
+ Header || /* @__PURE__ */ jsx5("h2", { className: "text-xl font-semibold text-gray-800", children: title }),
447
+ /* @__PURE__ */ jsx5(
448
+ "button",
449
+ {
450
+ onClick: () => setShow(false),
451
+ className: "text-gray-800 hover:text-secondary-300 active:animate-spin transition",
452
+ children: /* @__PURE__ */ jsx5(X, { className: "w-5 h-5" })
453
+ }
454
+ )
455
+ ] }),
456
+ Body && /* @__PURE__ */ jsx5("div", { className: "px-6 py-4 max-h-96 overflow-y-auto scrollbar-thin scrollbar-thumb-gray-300", children: Body }),
457
+ footer && /* @__PURE__ */ jsx5("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-secondary-300", children: footer })
458
+ ]
459
+ }
460
+ )
461
+ }
462
+ );
463
+ }
464
+
465
+ // src/shared/ui/pagination/Pagination.tsx
466
+ import { ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
467
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
468
+ function Pagination({
469
+ totalItems,
470
+ currentPage,
471
+ perPage,
472
+ onPageChange,
473
+ onPerPageChange,
474
+ siblingCount = 1,
475
+ perPageOptions = [10, 20, 30],
476
+ showPerPage = true
477
+ }) {
478
+ const totalPages = Math.ceil(totalItems / perPage);
479
+ const createPageRange = () => {
480
+ const totalPageNumbers = siblingCount * 2 + 5;
481
+ if (totalPages <= totalPageNumbers) {
482
+ return Array.from({ length: totalPages }, (_, i) => i + 1);
483
+ }
484
+ const leftSiblingIndex = Math.max(currentPage - siblingCount, 2);
485
+ const rightSiblingIndex = Math.min(
486
+ currentPage + siblingCount,
487
+ totalPages - 1
488
+ );
489
+ const showLeftDots = leftSiblingIndex > 2;
490
+ const showRightDots = rightSiblingIndex < totalPages - 1;
491
+ const range = [1];
492
+ if (showLeftDots) range.push("...");
493
+ for (let i = leftSiblingIndex; i <= rightSiblingIndex; i++) {
494
+ range.push(i);
495
+ }
496
+ if (showRightDots) range.push("...");
497
+ range.push(totalPages);
498
+ return range;
499
+ };
500
+ const pages = createPageRange();
501
+ const handlePrev = () => {
502
+ if (currentPage > 1) onPageChange(currentPage - 1);
503
+ };
504
+ const handleNext = () => {
505
+ if (currentPage < totalPages) onPageChange(currentPage + 1);
506
+ };
507
+ return /* @__PURE__ */ jsxs6("div", { className: "w-full flex flex-col md:flex-row md:justify-between md:items-center gap-4 py-4", children: [
508
+ showPerPage && onPerPageChange && /* @__PURE__ */ jsx6("div", { className: "flex justify-center md:justify-start w-full md:w-auto", children: /* @__PURE__ */ jsx6(
509
+ "select",
510
+ {
511
+ value: perPage,
512
+ onChange: (e) => onPerPageChange(Number(e.target.value)),
513
+ className: "border rounded-lg px-3 py-2 text-sm bg-white\n hover:border-secondary-500 \n focus:outline-none focus:ring-2 focus:ring-secondary-500\n transition-all duration-200",
514
+ children: perPageOptions.map((option) => /* @__PURE__ */ jsxs6("option", { value: option, children: [
515
+ option,
516
+ " / page"
517
+ ] }, option))
518
+ }
519
+ ) }),
520
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-center md:justify-end w-full", children: [
521
+ /* @__PURE__ */ jsx6(
522
+ "button",
523
+ {
524
+ onClick: handlePrev,
525
+ disabled: currentPage === 1,
526
+ className: `flex items-center justify-center rounded-xl border px-3 py-2 transition-all duration-200
527
+ ${currentPage === 1 ? "opacity-40 cursor-not-allowed" : "hover:bg-secondary-100 hover:text-secondary-700"}`,
528
+ children: /* @__PURE__ */ jsx6(ChevronLeft, { size: 18 })
529
+ }
530
+ ),
531
+ /* @__PURE__ */ jsx6("div", { className: "flex items-center gap-1 mx-2", children: pages.map((page, idx) => /* @__PURE__ */ jsx6(
532
+ "button",
533
+ {
534
+ onClick: () => typeof page === "number" && onPageChange(page),
535
+ disabled: page === "...",
536
+ className: `min-w-[40px] rounded-xl border px-3 py-2 text-sm font-medium transition-all duration-200
537
+ ${page === currentPage ? "bg-secondary-500 text-white shadow-md" : page === "..." ? "cursor-default border-none text-gray-400" : "bg-white text-secondary-700 hover:bg-secondary-100"}`,
538
+ children: page
539
+ },
540
+ idx
541
+ )) }),
542
+ /* @__PURE__ */ jsx6(
543
+ "button",
544
+ {
545
+ onClick: handleNext,
546
+ disabled: currentPage === totalPages,
547
+ className: `flex items-center justify-center rounded-xl border px-3 py-2 transition-all duration-200
548
+ ${currentPage === totalPages ? "opacity-40 cursor-not-allowed" : "hover:bg-secondary-100 hover:text-secondary-700"}`,
549
+ children: /* @__PURE__ */ jsx6(ChevronRight2, { size: 18 })
550
+ }
551
+ )
552
+ ] })
553
+ ] });
554
+ }
555
+
556
+ // src/shared/ui/skeleton/Skeleton.tsx
557
+ import { jsx as jsx7 } from "react/jsx-runtime";
558
+ function Skeleton({
559
+ className,
560
+ variant = "default",
561
+ width = "100%",
562
+ height = "1rem"
563
+ }) {
564
+ return /* @__PURE__ */ jsx7(
565
+ "div",
566
+ {
567
+ className: cn(
568
+ "relative overflow-hidden bg-secondary-200 dark:bg-secondary-800",
569
+ "rounded-sm",
570
+ variant === "circle" && "rounded-full",
571
+ variant === "rounded" && "rounded-md",
572
+ className
573
+ ),
574
+ style: {
575
+ width: typeof width === "number" ? `${width}px` : width,
576
+ height: typeof height === "number" ? `${height}px` : height
577
+ },
578
+ children: /* @__PURE__ */ jsx7("div", { className: "absolute inset-0 shimmer-mask" })
579
+ }
580
+ );
581
+ }
582
+
583
+ // src/shared/ui/tabs/Tabs.tsx
584
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
585
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
586
+ function Tabs({
587
+ tabs,
588
+ defaultTab,
589
+ position = "top",
590
+ variant = "primary",
591
+ className,
592
+ onChange
593
+ }) {
594
+ const [activeTab, setActiveTab] = useState3(defaultTab || tabs[0]?.id);
595
+ const [indicatorStyle, setIndicatorStyle] = useState3({});
596
+ const tabsRef = useRef3([]);
597
+ useEffect3(() => {
598
+ const activeIndex = tabs.findIndex((tab) => tab.id === activeTab);
599
+ const activeTabElement = tabsRef.current[activeIndex];
600
+ if (activeTabElement) {
601
+ const { offsetLeft, offsetTop, offsetWidth, offsetHeight } = activeTabElement;
602
+ setIndicatorStyle({
603
+ left: offsetLeft,
604
+ top: offsetTop,
605
+ width: offsetWidth,
606
+ height: offsetHeight,
607
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
608
+ });
609
+ }
610
+ }, [activeTab, position, tabs]);
611
+ const containerClasses = {
612
+ top: "flex-col",
613
+ bottom: "flex-col-reverse",
614
+ left: "flex-row",
615
+ right: "flex-row-reverse"
616
+ };
617
+ const tabsContainerClasses = {
618
+ top: "flex-row",
619
+ bottom: "flex-row",
620
+ left: "flex-col",
621
+ right: "flex-col"
622
+ };
623
+ const contentClasses = {
624
+ top: "mt-6",
625
+ bottom: "mb-6",
626
+ left: "ml-6",
627
+ right: "mr-6"
628
+ };
629
+ const variantClasses = {
630
+ primary: {
631
+ active: "text-secondary-600",
632
+ inactive: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300",
633
+ disabled: "text-gray-300 dark:text-gray-600 cursor-not-allowed",
634
+ bg: "bg-secondary-100 dark:bg-secondary-900"
635
+ },
636
+ secondary: {
637
+ active: "text-accent-600",
638
+ inactive: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300",
639
+ disabled: "text-gray-300 dark:text-gray-600 cursor-not-allowed",
640
+ bg: "bg-accent-100 dark:bg-accent-900"
641
+ },
642
+ accent: {
643
+ active: "text-gray-800 dark:text-gray-200",
644
+ inactive: "text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300",
645
+ disabled: "text-gray-300 dark:text-gray-600 cursor-not-allowed",
646
+ bg: "bg-gray-100 dark:bg-gray-800"
647
+ }
648
+ };
649
+ const isVertical = position === "left" || position === "right";
650
+ return /* @__PURE__ */ jsxs7("div", { className: cn("flex w-full", containerClasses[position], className), children: [
651
+ /* @__PURE__ */ jsxs7(
652
+ "div",
653
+ {
654
+ className: cn(
655
+ "flex relative bg-gray-50 dark:bg-gray-900 rounded-lg p-1",
656
+ tabsContainerClasses[position],
657
+ isVertical ? "min-w-48" : "w-full"
658
+ ),
659
+ children: [
660
+ /* @__PURE__ */ jsx8(
661
+ "div",
662
+ {
663
+ className: cn(
664
+ "absolute rounded-md transition-all duration-300 ease-out",
665
+ variantClasses[variant].bg,
666
+ isVertical ? "w-full" : "h-full"
667
+ ),
668
+ style: indicatorStyle
669
+ }
670
+ ),
671
+ tabs.map((tab, index) => {
672
+ const isActive = activeTab === tab.id;
673
+ const variantConfig = variantClasses[variant];
674
+ return /* @__PURE__ */ jsxs7(
675
+ "button",
676
+ {
677
+ ref: (el) => {
678
+ tabsRef.current[index] = el;
679
+ },
680
+ onClick: () => {
681
+ if (!tab.disabled) {
682
+ setActiveTab(tab.id);
683
+ onChange?.(tab.id);
684
+ }
685
+ },
686
+ disabled: tab.disabled,
687
+ className: cn(
688
+ "relative flex items-center justify-center gap-2 px-4 py-3 font-medium",
689
+ "text-sm whitespace-nowrap transition-all duration-200 z-10",
690
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500",
691
+ "rounded-md",
692
+ isActive ? [variantConfig.active, "font-semibold"] : [
693
+ variantConfig.inactive,
694
+ "hover:bg-white/50 dark:hover:bg-gray-800/50"
695
+ ],
696
+ tab.disabled && variantConfig.disabled,
697
+ isVertical ? "w-full justify-start" : "flex-1"
698
+ ),
699
+ children: [
700
+ tab.icon && /* @__PURE__ */ jsx8(
701
+ "span",
702
+ {
703
+ className: cn(
704
+ "flex-shrink-0 transition-transform duration-200",
705
+ isActive && "scale-110"
706
+ ),
707
+ children: tab.icon
708
+ }
709
+ ),
710
+ /* @__PURE__ */ jsx8("span", { className: "relative z-10", children: tab.label })
711
+ ]
712
+ },
713
+ tab.id
714
+ );
715
+ })
716
+ ]
717
+ }
718
+ ),
719
+ /* @__PURE__ */ jsx8("div", { className: cn("flex-1 overflow-hidden", contentClasses[position]), children: /* @__PURE__ */ jsx8("div", { className: "animate-fade-in", children: tabs.find((tab) => tab.id === activeTab)?.content }, activeTab) })
720
+ ] });
721
+ }
722
+ function TabPanel({ children, className }) {
723
+ return /* @__PURE__ */ jsx8(
724
+ "div",
725
+ {
726
+ className: cn(
727
+ "p-6 rounded-lg bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700",
728
+ className
729
+ ),
730
+ children
731
+ }
732
+ );
733
+ }
734
+
735
+ // src/shared/ui/tag/Tag.tsx
736
+ import { X as X2 } from "lucide-react";
737
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
738
+ var sizes = {
739
+ sm: "text-xs px-2 py-0.5",
740
+ md: "text-sm px-3 py-1",
741
+ lg: "text-base px-4 py-1.5"
742
+ };
743
+ var iconSizes = {
744
+ sm: "w-3 h-3",
745
+ md: "w-4 h-4",
746
+ lg: "w-5 h-5"
747
+ };
748
+ var variants = {
749
+ default: "bg-gray-100 text-gray-800 border border-gray-200 dark:bg-gray-800 dark:text-gray-100 dark:border-gray-700",
750
+ secondary: "bg-secondary-100 text-secondary-800 border border-secondary-200 dark:bg-secondary-800 dark:text-secondary-50 dark:border-secondary-700",
751
+ success: "bg-success-100 text-success-800 border border-success-200 dark:bg-success-800 dark:text-success-50 dark:border-success-700",
752
+ error: "bg-error-100 text-error-800 border border-error-200 dark:bg-error-800 dark:text-error-50 dark:border-error-700",
753
+ info: "bg-info-100 text-info-800 border border-info-200 dark:bg-info-800 dark:text-info-50 dark:border-info-700",
754
+ accent: "bg-accent-100 text-accent-800 border border-accent-200 dark:bg-accent-800 dark:text-accent-50 dark:border-accent-700"
755
+ };
756
+ function Tag({
757
+ children,
758
+ variant = "default",
759
+ size = "md",
760
+ icon,
761
+ iconPosition = "left",
762
+ closable = false,
763
+ onClose,
764
+ className
765
+ }) {
766
+ return /* @__PURE__ */ jsxs8(
767
+ "span",
768
+ {
769
+ className: cn(
770
+ "inline-flex items-center font-medium animate-[fadeIn_0.3s_ease-out] rounded-[7px]",
771
+ sizes[size],
772
+ variants[variant],
773
+ icon && "gap-1.5",
774
+ className
775
+ ),
776
+ children: [
777
+ icon && iconPosition === "left" && /* @__PURE__ */ jsx9("span", { className: `flex items-center ${cn(iconSizes[size])}`, children: icon }),
778
+ /* @__PURE__ */ jsx9("span", { children }),
779
+ icon && iconPosition === "right" && /* @__PURE__ */ jsx9("span", { className: `flex items-center ${cn(iconSizes[size])}`, children: icon }),
780
+ closable && /* @__PURE__ */ jsx9(
781
+ "button",
782
+ {
783
+ type: "button",
784
+ onClick: onClose,
785
+ className: "ml-1 rounded-full p-0.5 hover:bg-black/10 dark:hover:bg-white/10 transition-colors",
786
+ children: /* @__PURE__ */ jsx9(X2, { className: cn(iconSizes[size]) })
787
+ }
788
+ )
789
+ ]
790
+ }
791
+ );
792
+ }
793
+
794
+ // src/shared/ui/textarea/Textarea.tsx
795
+ import { useState as useState4 } from "react";
796
+ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
797
+ function Textarea({
798
+ label,
799
+ placeholder,
800
+ value = "",
801
+ onChange,
802
+ required = false,
803
+ disabled = false,
804
+ error,
805
+ className,
806
+ rows = 4
807
+ }) {
808
+ const [focused, setFocused] = useState4(false);
809
+ const isFloating = focused || value.length > 0;
810
+ return /* @__PURE__ */ jsxs9("div", { className: "relative w-full", children: [
811
+ label && /* @__PURE__ */ jsxs9(
812
+ "label",
813
+ {
814
+ className: cn(
815
+ "absolute left-3 top-2 text-gray-500 dark:text-gray-400 transition-all duration-200 pointer-events-none",
816
+ isFloating ? "text-xs -translate-y-3 bg-white dark:bg-gray-900 px-1" : "text-sm translate-y-0"
817
+ ),
818
+ children: [
819
+ label,
820
+ required && /* @__PURE__ */ jsx10("span", { className: "text-error-500 ml-0.5", children: "*" })
821
+ ]
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsx10(
825
+ "textarea",
826
+ {
827
+ rows,
828
+ placeholder: label ? void 0 : placeholder,
829
+ value,
830
+ onChange: (e) => onChange?.(e.target.value),
831
+ onFocus: () => setFocused(true),
832
+ onBlur: () => setFocused(false),
833
+ disabled,
834
+ className: cn(
835
+ "w-full rounded-md border border-gray-300 dark:border-gray-700 bg-transparent text-gray-900 dark:text-gray-100 px-3 py-2 outline-none transition-all resize-none",
836
+ "focus:border-primary-500 focus:ring-1 focus:ring-primary-500",
837
+ disabled && "opacity-50 cursor-not-allowed",
838
+ error && "border-error-500 focus:ring-error-500 focus:border-error-500",
839
+ label && "pt-5",
840
+ className
841
+ )
842
+ }
843
+ ),
844
+ error && /* @__PURE__ */ jsx10("p", { className: "mt-1 text-sm text-error-500", children: error })
845
+ ] });
846
+ }
847
+
848
+ // src/shared/ui/toast/Toast.tsx
849
+ import {
850
+ AlertCircle,
851
+ CheckCircle2,
852
+ Info,
853
+ Loader2,
854
+ X as X3,
855
+ XCircle
856
+ } from "lucide-react";
857
+ import { useEffect as useEffect4, useState as useState5 } from "react";
858
+ import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
859
+ function Toast({
860
+ id = Math.random().toString(36),
861
+ title,
862
+ description,
863
+ type = "info",
864
+ duration = 5e3,
865
+ position = "top-right",
866
+ onClose,
867
+ action
868
+ }) {
869
+ const [isVisible, setIsVisible] = useState5(false);
870
+ const [isLeaving, setIsLeaving] = useState5(false);
871
+ useEffect4(() => {
872
+ const showTimer = setTimeout(() => setIsVisible(true), 100);
873
+ if (duration !== Infinity) {
874
+ const closeTimer = setTimeout(() => handleClose(), duration);
875
+ return () => {
876
+ clearTimeout(showTimer);
877
+ clearTimeout(closeTimer);
878
+ };
879
+ }
880
+ return () => clearTimeout(showTimer);
881
+ }, [duration]);
882
+ const handleClose = () => {
883
+ setIsLeaving(true);
884
+ setTimeout(() => {
885
+ setIsVisible(false);
886
+ onClose?.(id);
887
+ }, 300);
888
+ };
889
+ const handleAction = () => {
890
+ action?.onClick();
891
+ handleClose();
892
+ };
893
+ const icons = {
894
+ success: /* @__PURE__ */ jsx11(CheckCircle2, { className: "w-5 h-5" }),
895
+ error: /* @__PURE__ */ jsx11(XCircle, { className: "w-5 h-5" }),
896
+ warning: /* @__PURE__ */ jsx11(AlertCircle, { className: "w-5 h-5" }),
897
+ info: /* @__PURE__ */ jsx11(Info, { className: "w-5 h-5" }),
898
+ loading: /* @__PURE__ */ jsx11(Loader2, { className: "w-5 h-5 animate-spin" })
899
+ };
900
+ const variantClasses = {
901
+ success: "bg-success-50 border-success-200 text-success-800",
902
+ error: "bg-error-50 border-error-200 text-error-800",
903
+ warning: "bg-secondary-50 border-secondary-200 text-secondary-800",
904
+ info: "bg-info-50 border-info-200 text-info-800",
905
+ loading: "bg-gray-50 border-gray-200 text-gray-800"
906
+ };
907
+ const iconColors = {
908
+ success: "text-success-600",
909
+ error: "text-error-600",
910
+ warning: "text-secondary-600",
911
+ info: "text-info-600",
912
+ loading: "text-gray-600"
913
+ };
914
+ const positionClasses = {
915
+ "top-right": "top-4 right-4",
916
+ "top-left": "top-4 left-4",
917
+ "bottom-right": "bottom-4 right-4",
918
+ "bottom-left": "bottom-4 left-4",
919
+ "top-center": "top-4 left-1/2 -translate-x-1/2",
920
+ "bottom-center": "bottom-4 left-1/2 -translate-x-1/2"
921
+ };
922
+ if (!isVisible) return null;
923
+ return /* @__PURE__ */ jsx11(
924
+ "div",
925
+ {
926
+ className: cn(
927
+ "fixed z-50 transform transition-all duration-300",
928
+ positionClasses[position],
929
+ isLeaving ? "opacity-0 scale-95" : "opacity-100 scale-100",
930
+ position.includes("top") && !isLeaving && "animate-slide-down",
931
+ position.includes("bottom") && !isLeaving && "animate-slide-up"
932
+ ),
933
+ children: /* @__PURE__ */ jsxs10(
934
+ "div",
935
+ {
936
+ className: cn(
937
+ "flex items-start gap-3 p-4 rounded-lg border shadow-lg max-w-sm",
938
+ "backdrop-blur-sm bg-white/95",
939
+ variantClasses[type]
940
+ ),
941
+ children: [
942
+ /* @__PURE__ */ jsx11("div", { className: cn("flex-shrink-0 mt-0.5", iconColors[type]), children: icons[type] }),
943
+ /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
944
+ /* @__PURE__ */ jsx11("h4", { className: "font-semibold text-sm mb-1", children: title }),
945
+ description && /* @__PURE__ */ jsx11("p", { className: "text-sm opacity-90", children: description }),
946
+ action && /* @__PURE__ */ jsx11(
947
+ "button",
948
+ {
949
+ onClick: handleAction,
950
+ className: "mt-2 text-sm font-medium underline underline-offset-2 hover:no-underline",
951
+ children: action.label
952
+ }
953
+ )
954
+ ] }),
955
+ /* @__PURE__ */ jsx11(
956
+ "button",
957
+ {
958
+ onClick: handleClose,
959
+ className: "flex-shrink-0 p-1 rounded-full hover:bg-black/5 transition-colors",
960
+ children: /* @__PURE__ */ jsx11(X3, { className: "w-4 h-4" })
961
+ }
962
+ )
963
+ ]
964
+ }
965
+ )
966
+ }
967
+ );
968
+ }
969
+
970
+ // src/shared/ui/toast/ToastContainer.tsx
971
+ import { Fragment, jsx as jsx12 } from "react/jsx-runtime";
972
+ function ToastContainer({
973
+ toasts,
974
+ onRemove,
975
+ position = "top-right"
976
+ }) {
977
+ return /* @__PURE__ */ jsx12(Fragment, { children: toasts.map((t) => /* @__PURE__ */ jsx12(Toast, { ...t, onClose: onRemove, position }, t.id)) });
978
+ }
979
+
980
+ // src/shared/ui/tooltip/Tooltip.tsx
981
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
982
+ function Tooltip({
983
+ content,
984
+ children,
985
+ position = "top",
986
+ delay = 200,
987
+ className
988
+ }) {
989
+ const positionClasses = {
990
+ top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
991
+ bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
992
+ left: "right-full top-1/2 -translate-y-1/2 mr-2",
993
+ right: "left-full top-1/2 -translate-y-1/2 ml-2"
994
+ };
995
+ const arrowClasses = {
996
+ top: "left-1/2 -translate-x-1/2 top-full",
997
+ bottom: "left-1/2 -translate-x-1/2 bottom-full",
998
+ left: "top-1/2 -translate-y-1/2 left-full",
999
+ right: "top-1/2 -translate-y-1/2 right-full"
1000
+ };
1001
+ return /* @__PURE__ */ jsxs11("div", { className: "relative inline-block group", children: [
1002
+ children,
1003
+ /* @__PURE__ */ jsxs11(
1004
+ "div",
1005
+ {
1006
+ className: cn(
1007
+ "absolute z-50 whitespace-nowrap rounded-md bg-gray-800 text-white text-xs px-2 py-1 shadow-md dark:bg-gray-900",
1008
+ "transition-all opacity-0 scale-95 group-hover:opacity-100 group-hover:scale-100",
1009
+ "group-hover:delay-200 duration-200 ease-out",
1010
+ positionClasses[position],
1011
+ className
1012
+ ),
1013
+ style: { transitionDelay: `${delay}ms` },
1014
+ children: [
1015
+ content,
1016
+ /* @__PURE__ */ jsx13(
1017
+ "span",
1018
+ {
1019
+ className: cn(
1020
+ "absolute w-2 h-2 bg-gray-800 dark:bg-gray-900 rotate-45",
1021
+ arrowClasses[position]
1022
+ )
1023
+ }
1024
+ )
1025
+ ]
1026
+ }
1027
+ )
1028
+ ] });
1029
+ }
1030
+
1031
+ // src/shared/ui/mciTable/MciTable.tsx
1032
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1033
+ function MciTable({
1034
+ columns,
1035
+ data,
1036
+ loading = false,
1037
+ variant = "clean",
1038
+ skeletonRows = 5,
1039
+ actions,
1040
+ noDataText
1041
+ }) {
1042
+ const [sortConfig, setSortConfig] = useState6(null);
1043
+ const sortedData = useMemo2(() => {
1044
+ if (!sortConfig || !sortConfig.direction) return data;
1045
+ return [...data].sort((a, b) => {
1046
+ const aVal = a[sortConfig.key];
1047
+ const bVal = b[sortConfig.key];
1048
+ if (aVal < bVal) return sortConfig.direction === "asc" ? -1 : 1;
1049
+ if (aVal > bVal) return sortConfig.direction === "asc" ? 1 : -1;
1050
+ return 0;
1051
+ });
1052
+ }, [data, sortConfig]);
1053
+ const handleSort = (col) => {
1054
+ if (!col.sortable) return;
1055
+ setSortConfig((prev) => {
1056
+ if (!prev || prev.key !== col.key) {
1057
+ return { key: col.key, direction: "asc" };
1058
+ }
1059
+ if (prev.direction === "asc") return { key: col.key, direction: "desc" };
1060
+ if (prev.direction === "desc") return { key: col.key, direction: null };
1061
+ return null;
1062
+ });
1063
+ };
1064
+ const getSortIcon = (col) => {
1065
+ if (!col.sortable) return null;
1066
+ if (!sortConfig || sortConfig.key !== col.key || !sortConfig.direction) {
1067
+ return /* @__PURE__ */ jsx14(ArrowUpDown, { size: 15, className: "opacity-40" });
1068
+ }
1069
+ return sortConfig.direction === "asc" ? /* @__PURE__ */ jsx14(ChevronUp, { size: 15 }) : /* @__PURE__ */ jsx14(ChevronDown, { size: 15 });
1070
+ };
1071
+ const variantStyle = cn(
1072
+ "w-full border-separate border-spacing-0 transition-all duration-300",
1073
+ variant === "clean" && "bg-white",
1074
+ variant === "elevated" && "bg-white shadow-lg",
1075
+ variant === "bordered" && "border border-secondary-200 rounded-lg"
1076
+ );
1077
+ const headerCell = (col) => cn(
1078
+ "bg-secondary-50 text-secondary-800 text-sm font-semibold py-3 px-4 select-none",
1079
+ "border-b border-secondary-200 transition-colors",
1080
+ col.align === "center" && "text-center",
1081
+ col.align === "right" && "text-right",
1082
+ col.sortable && "cursor-pointer hover:bg-secondary-100/70"
1083
+ );
1084
+ return /* @__PURE__ */ jsxs12("div", { className: "w-full space-y-3", children: [
1085
+ actions && /* @__PURE__ */ jsx14("div", { className: "flex justify-between items-center mb-2", children: actions }),
1086
+ /* @__PURE__ */ jsx14("div", { className: "w-full overflow-x-auto rounded-lg", children: /* @__PURE__ */ jsxs12("table", { className: variantStyle, children: [
1087
+ /* @__PURE__ */ jsx14("thead", { children: /* @__PURE__ */ jsx14("tr", { children: columns.map((col, idx) => /* @__PURE__ */ jsx14(
1088
+ "th",
1089
+ {
1090
+ onClick: () => handleSort(col),
1091
+ className: cn(
1092
+ headerCell(col),
1093
+ idx === 0 && "rounded-tl-lg",
1094
+ idx === columns.length - 1 && "rounded-tr-lg"
1095
+ ),
1096
+ style: { width: col.width },
1097
+ children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between gap-2", children: [
1098
+ /* @__PURE__ */ jsx14("span", { className: "truncate", children: col.title }),
1099
+ getSortIcon(col)
1100
+ ] })
1101
+ },
1102
+ String(col.key)
1103
+ )) }) }),
1104
+ /* @__PURE__ */ jsx14("tbody", { children: loading ? Array.from({ length: skeletonRows }).map((_, idx) => /* @__PURE__ */ jsx14("tr", { children: columns.map((_2, i) => /* @__PURE__ */ jsx14("td", { className: "px-4 py-3", children: /* @__PURE__ */ jsx14(Skeleton, { height: 18, variant: "rounded" }) }, i)) }, idx)) : sortedData.map((row, idx) => /* @__PURE__ */ jsx14(
1105
+ "tr",
1106
+ {
1107
+ className: cn(
1108
+ "border-b border-secondary-100 transition-all duration-200"
1109
+ ),
1110
+ children: columns.map((col, i) => /* @__PURE__ */ jsx14(
1111
+ "td",
1112
+ {
1113
+ className: cn(
1114
+ "px-4 py-3 text-sm text-gray-800",
1115
+ col.align === "center" && "text-center",
1116
+ col.align === "right" && "text-right"
1117
+ ),
1118
+ children: col.render ? col.render(row[col.key], row) : String(row[col.key])
1119
+ },
1120
+ i
1121
+ ))
1122
+ },
1123
+ idx
1124
+ )) })
1125
+ ] }) }),
1126
+ !loading && sortedData.length === 0 && /* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-center justify-center py-10 text-gray-500 dark:text-gray-400 animate-[fadeIn_0.4s_ease-in-out]", children: [
1127
+ /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
1128
+ /* @__PURE__ */ jsx14(
1129
+ Box,
1130
+ {
1131
+ size: 64,
1132
+ className: "mb-3 text-secondary-400 dark:text-secondary-500 opacity-80 animate-[float_2.5s_ease-in-out_infinite]"
1133
+ }
1134
+ ),
1135
+ /* @__PURE__ */ jsx14("div", { className: "absolute inset-0 blur-2xl bg-secondary-200/20 dark:bg-secondary-700/20 rounded-full scale-75 animate-[pulse_3s_ease-in-out_infinite]" })
1136
+ ] }),
1137
+ /* @__PURE__ */ jsx14("p", { className: "text-sm font-medium animate-[fadeUp_0.6s_ease-out]", children: noDataText })
1138
+ ] })
1139
+ ] });
1140
+ }
1141
+ export {
1142
+ Breadcrumb,
1143
+ Button,
1144
+ Collapse,
1145
+ InputMain,
1146
+ MciTable,
1147
+ Modal,
1148
+ Pagination,
1149
+ Skeleton,
1150
+ TabPanel,
1151
+ Tabs,
1152
+ Tag,
1153
+ Textarea,
1154
+ ToastContainer,
1155
+ Tooltip
1156
+ };
1157
+ //# sourceMappingURL=index.js.map