@universe-platform/ui 0.1.0-beta.4 → 0.1.0-beta.6

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
@@ -77,7 +77,7 @@ function cn(...inputs) {
77
77
  }
78
78
 
79
79
  // src/components/TableBlock/TableBlockClient.tsx
80
- var import_react5 = require("react");
80
+ var import_react6 = require("react");
81
81
 
82
82
  // src/hooks/useToast.ts
83
83
  var import_react2 = require("react");
@@ -277,7 +277,7 @@ function useToast() {
277
277
  }
278
278
 
279
279
  // src/components/TableBlock/fields/fieldRegistry.tsx
280
- var import_react4 = __toESM(require("react"));
280
+ var import_react5 = __toESM(require("react"));
281
281
 
282
282
  // src/components/TableBlock/fields/DrivePickerCell.tsx
283
283
  var import_react3 = require("react");
@@ -399,8 +399,311 @@ function DrivePickerCell({ value, onChange, tableName, onMarkForDeletion, contex
399
399
  ) });
400
400
  }
401
401
 
402
- // src/components/TableBlock/fields/fieldRegistry.tsx
402
+ // src/components/TableBlock/fields/DatePickerCell.tsx
403
+ var import_react4 = require("react");
404
+ var import_lucide_react3 = require("lucide-react");
403
405
  var import_jsx_runtime3 = require("react/jsx-runtime");
406
+ function parseDateParts(val) {
407
+ if (val === void 0 || val === null || val === "") return null;
408
+ if (typeof val === "string") {
409
+ const trimmed = val.trim();
410
+ if (!trimmed) return null;
411
+ const ymdMatch = trimmed.match(/^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})/);
412
+ if (ymdMatch) {
413
+ const year = parseInt(ymdMatch[1], 10);
414
+ const month = parseInt(ymdMatch[2], 10);
415
+ const day = parseInt(ymdMatch[3], 10);
416
+ if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
417
+ return { year, month, day };
418
+ }
419
+ }
420
+ const dmyMatch = trimmed.match(/^(\d{1,2})[-/.](\d{1,2})[-/.](\d{4})/);
421
+ if (dmyMatch) {
422
+ const day = parseInt(dmyMatch[1], 10);
423
+ const month = parseInt(dmyMatch[2], 10);
424
+ const year = parseInt(dmyMatch[3], 10);
425
+ if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
426
+ return { year, month, day };
427
+ }
428
+ }
429
+ const parsed = new Date(trimmed);
430
+ if (!isNaN(parsed.getTime())) {
431
+ return {
432
+ year: parsed.getFullYear(),
433
+ month: parsed.getMonth() + 1,
434
+ day: parsed.getDate()
435
+ };
436
+ }
437
+ } else if (val instanceof Date && !isNaN(val.getTime())) {
438
+ return {
439
+ year: val.getFullYear(),
440
+ month: val.getMonth() + 1,
441
+ day: val.getDate()
442
+ };
443
+ } else if (typeof val === "number" && !isNaN(val)) {
444
+ const parsed = new Date(val);
445
+ if (!isNaN(parsed.getTime())) {
446
+ return {
447
+ year: parsed.getFullYear(),
448
+ month: parsed.getMonth() + 1,
449
+ day: parsed.getDate()
450
+ };
451
+ }
452
+ }
453
+ return null;
454
+ }
455
+ function formatDateIso(year, month, day) {
456
+ const mm = String(month).padStart(2, "0");
457
+ const dd = String(day).padStart(2, "0");
458
+ return `${year}-${mm}-${dd}`;
459
+ }
460
+ function formatDateDisplay(parts) {
461
+ if (!parts) return "";
462
+ const mm = String(parts.month).padStart(2, "0");
463
+ const dd = String(parts.day).padStart(2, "0");
464
+ return `${dd}/${mm}/${parts.year}`;
465
+ }
466
+ var HEBREW_MONTHS = [
467
+ "\u05D9\u05E0\u05D5\u05D0\u05E8",
468
+ "\u05E4\u05D1\u05E8\u05D5\u05D0\u05E8",
469
+ "\u05DE\u05E8\u05E5",
470
+ "\u05D0\u05E4\u05E8\u05D9\u05DC",
471
+ "\u05DE\u05D0\u05D9",
472
+ "\u05D9\u05D5\u05E0\u05D9",
473
+ "\u05D9\u05D5\u05DC\u05D9",
474
+ "\u05D0\u05D5\u05D2\u05D5\u05E1\u05D8",
475
+ "\u05E1\u05E4\u05D8\u05DE\u05D1\u05E8",
476
+ "\u05D0\u05D5\u05E7\u05D8\u05D5\u05D1\u05E8",
477
+ "\u05E0\u05D5\u05D1\u05DE\u05D1\u05E8",
478
+ "\u05D3\u05E6\u05DE\u05D1\u05E8"
479
+ ];
480
+ var WEEKDAY_LABELS = ["\u05D0'", "\u05D1'", "\u05D2'", "\u05D3'", "\u05D4'", "\u05D5'", "\u05E9'"];
481
+ function DatePickerCell({ value, onChange, readOnly = false }) {
482
+ const [isOpen, setIsOpen] = (0, import_react4.useState)(false);
483
+ const containerRef = (0, import_react4.useRef)(null);
484
+ const [popoverPos, setPopoverPos] = (0, import_react4.useState)({ top: 0, right: 0 });
485
+ const parsedParts = (0, import_react4.useMemo)(() => parseDateParts(value), [value]);
486
+ const displayString = (0, import_react4.useMemo)(() => formatDateDisplay(parsedParts), [parsedParts]);
487
+ const [rawInput, setRawInput] = (0, import_react4.useState)(displayString);
488
+ (0, import_react4.useEffect)(() => {
489
+ setRawInput(displayString);
490
+ }, [displayString]);
491
+ const now = /* @__PURE__ */ new Date();
492
+ const [viewYear, setViewYear] = (0, import_react4.useState)((parsedParts == null ? void 0 : parsedParts.year) || now.getFullYear());
493
+ const [viewMonth, setViewMonth] = (0, import_react4.useState)((parsedParts == null ? void 0 : parsedParts.month) || now.getMonth() + 1);
494
+ (0, import_react4.useEffect)(() => {
495
+ if (parsedParts) {
496
+ setViewYear(parsedParts.year);
497
+ setViewMonth(parsedParts.month);
498
+ }
499
+ }, [parsedParts, isOpen]);
500
+ const updatePopoverPosition = (0, import_react4.useCallback)(() => {
501
+ if (containerRef.current) {
502
+ const rect = containerRef.current.getBoundingClientRect();
503
+ const right = window.innerWidth - rect.right;
504
+ const popoverHeight = 320;
505
+ const spaceBelow = window.innerHeight - rect.bottom;
506
+ if (spaceBelow < popoverHeight && rect.top > popoverHeight) {
507
+ setPopoverPos({
508
+ top: Math.max(10, rect.top - popoverHeight - 4),
509
+ right: Math.max(10, right)
510
+ });
511
+ } else {
512
+ setPopoverPos({
513
+ top: Math.min(window.innerHeight - popoverHeight - 10, rect.bottom + 4),
514
+ right: Math.max(10, right)
515
+ });
516
+ }
517
+ }
518
+ }, []);
519
+ (0, import_react4.useEffect)(() => {
520
+ if (!isOpen) return;
521
+ updatePopoverPosition();
522
+ function handleScrollOrResize() {
523
+ updatePopoverPosition();
524
+ }
525
+ function handleClickOutside(event) {
526
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
527
+ const popoverEl = document.getElementById("date-picker-popover");
528
+ if (popoverEl && popoverEl.contains(event.target)) {
529
+ return;
530
+ }
531
+ setIsOpen(false);
532
+ }
533
+ }
534
+ window.addEventListener("scroll", handleScrollOrResize, true);
535
+ window.addEventListener("resize", handleScrollOrResize);
536
+ document.addEventListener("mousedown", handleClickOutside);
537
+ return () => {
538
+ window.removeEventListener("scroll", handleScrollOrResize, true);
539
+ window.removeEventListener("resize", handleScrollOrResize);
540
+ document.removeEventListener("mousedown", handleClickOutside);
541
+ };
542
+ }, [isOpen, updatePopoverPosition]);
543
+ const handleInputChange = (e) => {
544
+ const text = e.target.value;
545
+ setRawInput(text);
546
+ if (!text.trim()) {
547
+ onChange(null);
548
+ return;
549
+ }
550
+ const parts = parseDateParts(text);
551
+ if (parts) {
552
+ const iso = formatDateIso(parts.year, parts.month, parts.day);
553
+ onChange(iso);
554
+ }
555
+ };
556
+ const handleInputBlur = () => {
557
+ const parts = parseDateParts(rawInput);
558
+ if (parts) {
559
+ setRawInput(formatDateDisplay(parts));
560
+ } else if (!rawInput.trim()) {
561
+ setRawInput("");
562
+ }
563
+ };
564
+ const handleSelectDay = (day) => {
565
+ const iso = formatDateIso(viewYear, viewMonth, day);
566
+ onChange(iso);
567
+ setRawInput(formatDateDisplay({ year: viewYear, month: viewMonth, day }));
568
+ setIsOpen(false);
569
+ };
570
+ const handlePrevMonth = () => {
571
+ if (viewMonth === 1) {
572
+ setViewMonth(12);
573
+ setViewYear((prev) => prev - 1);
574
+ } else {
575
+ setViewMonth((prev) => prev - 1);
576
+ }
577
+ };
578
+ const handleNextMonth = () => {
579
+ if (viewMonth === 12) {
580
+ setViewMonth(1);
581
+ setViewYear((prev) => prev + 1);
582
+ } else {
583
+ setViewMonth((prev) => prev + 1);
584
+ }
585
+ };
586
+ const calendarDays = (0, import_react4.useMemo)(() => {
587
+ const firstDayIndex = new Date(viewYear, viewMonth - 1, 1).getDay();
588
+ const totalDays = new Date(viewYear, viewMonth, 0).getDate();
589
+ const days = [];
590
+ const prevMonthTotalDays = new Date(viewYear, viewMonth - 1, 0).getDate();
591
+ for (let i = firstDayIndex - 1; i >= 0; i--) {
592
+ days.push({ day: prevMonthTotalDays - i, isCurrentMonth: false });
593
+ }
594
+ for (let d = 1; d <= totalDays; d++) {
595
+ days.push({ day: d, isCurrentMonth: true });
596
+ }
597
+ const remaining = 7 - days.length % 7;
598
+ if (remaining < 7) {
599
+ for (let d = 1; d <= remaining; d++) {
600
+ days.push({ day: d, isCurrentMonth: false });
601
+ }
602
+ }
603
+ return days;
604
+ }, [viewYear, viewMonth]);
605
+ if (readOnly) {
606
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "px-2 py-1 flex items-center justify-end w-full h-full text-sm font-normal text-slate-800 text-right", dir: "ltr", children: displayString });
607
+ }
608
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref: containerRef, className: "relative w-full h-full flex items-center", children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
610
+ "input",
611
+ {
612
+ type: "text",
613
+ dir: "ltr",
614
+ placeholder: "DD/MM/YYYY",
615
+ className: "w-full h-8 pl-8 pr-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm text-right font-normal text-slate-800",
616
+ value: rawInput,
617
+ onChange: handleInputChange,
618
+ onBlur: handleInputBlur
619
+ }
620
+ ),
621
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
622
+ "button",
623
+ {
624
+ type: "button",
625
+ onClick: () => {
626
+ setIsOpen((prev) => {
627
+ const next = !prev;
628
+ if (next) updatePopoverPosition();
629
+ return next;
630
+ });
631
+ },
632
+ className: "absolute left-1.5 p-1 text-slate-400 hover:text-blue-600 rounded transition-colors",
633
+ title: "\u05D1\u05D7\u05E8 \u05EA\u05D0\u05E8\u05D9\u05DA",
634
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.Calendar, { className: "w-4 h-4" })
635
+ }
636
+ ),
637
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
638
+ "div",
639
+ {
640
+ id: "date-picker-popover",
641
+ dir: "rtl",
642
+ style: { top: `${popoverPos.top}px`, right: `${popoverPos.right}px` },
643
+ className: "fixed z-[99999] w-72 bg-white rounded-xl shadow-2xl border border-slate-200 p-3.5 animate-in fade-in zoom-in-95 duration-150",
644
+ children: [
645
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between border-b border-slate-100 pb-2.5 mb-2.5", children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "text-xs font-semibold text-slate-500", children: parsedParts ? `${parsedParts.day} \u05D1${HEBREW_MONTHS[parsedParts.month - 1]} ${parsedParts.year}` : "\u05D1\u05D7\u05D9\u05E8\u05EA \u05EA\u05D0\u05E8\u05D9\u05DA" }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
648
+ "button",
649
+ {
650
+ onClick: () => setIsOpen(false),
651
+ className: "text-slate-400 hover:text-slate-600 p-0.5 rounded-full hover:bg-slate-100",
652
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.X, { className: "w-4 h-4" })
653
+ }
654
+ )
655
+ ] }),
656
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center justify-between mb-3 px-1", children: [
657
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
658
+ "button",
659
+ {
660
+ type: "button",
661
+ onClick: handleNextMonth,
662
+ className: "p-1 text-slate-600 hover:bg-slate-100 rounded-lg transition-colors",
663
+ title: "\u05D7\u05D5\u05D3\u05E9 \u05D4\u05D1\u05D0",
664
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronRight, { className: "w-4 h-4" })
665
+ }
666
+ ),
667
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "font-bold text-sm text-slate-800", children: [
668
+ HEBREW_MONTHS[viewMonth - 1],
669
+ " ",
670
+ viewYear
671
+ ] }),
672
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
673
+ "button",
674
+ {
675
+ type: "button",
676
+ onClick: handlePrevMonth,
677
+ className: "p-1 text-slate-600 hover:bg-slate-100 rounded-lg transition-colors",
678
+ title: "\u05D7\u05D5\u05D3\u05E9 \u05E7\u05D5\u05D3\u05DD",
679
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react3.ChevronLeft, { className: "w-4 h-4" })
680
+ }
681
+ )
682
+ ] }),
683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "grid grid-cols-7 gap-1 text-center mb-1.5", children: WEEKDAY_LABELS.map((label, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[11px] font-bold text-slate-400 select-none py-0.5", children: label }, idx)) }),
684
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "grid grid-cols-7 gap-1 text-center", children: calendarDays.map((item, idx) => {
685
+ const isSelected = item.isCurrentMonth && (parsedParts == null ? void 0 : parsedParts.year) === viewYear && (parsedParts == null ? void 0 : parsedParts.month) === viewMonth && (parsedParts == null ? void 0 : parsedParts.day) === item.day;
686
+ const isToday = item.isCurrentMonth && now.getFullYear() === viewYear && now.getMonth() + 1 === viewMonth && now.getDate() === item.day;
687
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
688
+ "button",
689
+ {
690
+ type: "button",
691
+ disabled: !item.isCurrentMonth,
692
+ onClick: () => item.isCurrentMonth && handleSelectDay(item.day),
693
+ className: `h-8 w-8 mx-auto flex items-center justify-center rounded-lg text-xs transition-all ${!item.isCurrentMonth ? "text-slate-300 cursor-not-allowed" : isSelected ? "bg-blue-600 text-white font-bold shadow-md scale-105" : isToday ? "bg-blue-50 text-blue-700 font-bold border border-blue-300 hover:bg-blue-100" : "text-slate-700 hover:bg-slate-100 font-medium"}`,
694
+ children: item.day
695
+ },
696
+ idx
697
+ );
698
+ }) })
699
+ ]
700
+ }
701
+ )
702
+ ] });
703
+ }
704
+
705
+ // src/components/TableBlock/fields/fieldRegistry.tsx
706
+ var import_jsx_runtime4 = require("react/jsx-runtime");
404
707
  var CURRENCY_SYMBOLS = {
405
708
  USD: "$",
406
709
  EUR: "\u20AC",
@@ -436,17 +739,22 @@ function getRelationDisplayLabel(opt, column) {
436
739
  return "\u05E2\u05E8\u05DA \u05E8\u05D9\u05E7";
437
740
  }
438
741
  var FORM_INPUTS = {
742
+ DATE: ({ value, onChange, column }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DatePickerCell, { value, onChange, column }),
439
743
  CURRENCY: ({ value, column, onChange }) => {
440
744
  const symbol = getCurrencySymbol(column.currencySymbol);
441
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "relative w-full h-full", children: [
442
- symbol && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
443
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
745
+ const [isFocused, setIsFocused] = import_react5.default.useState(false);
746
+ const displayValue = !isFocused && value !== void 0 && value !== null && value !== "" && !isNaN(Number(value)) ? new Intl.NumberFormat("en-US").format(Number(value)) : value !== void 0 && value !== null ? value : "";
747
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative w-full h-full", children: [
748
+ symbol && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute left-2 top-1/2 -translate-y-1/2 text-slate-400 pointer-events-none text-sm", children: symbol }),
749
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
444
750
  "input",
445
751
  {
446
- type: "number",
752
+ type: isFocused ? "number" : "text",
447
753
  step: "any",
448
754
  className: `w-full h-8 ${symbol ? "pl-6 pr-2" : "px-2"} bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm`,
449
- value: value !== void 0 && value !== null ? value : "",
755
+ value: displayValue,
756
+ onFocus: () => setIsFocused(true),
757
+ onBlur: () => setIsFocused(false),
450
758
  onChange: (e) => {
451
759
  const val = e.target.value;
452
760
  onChange(val === "" ? "" : Number(val));
@@ -455,7 +763,7 @@ var FORM_INPUTS = {
455
763
  )
456
764
  ] });
457
765
  },
458
- TIME: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
766
+ TIME: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
459
767
  "input",
460
768
  {
461
769
  type: "time",
@@ -465,13 +773,13 @@ var FORM_INPUTS = {
465
773
  }
466
774
  ),
467
775
  LINK: ({ value, onChange }) => {
468
- const [isEditing, setIsEditing] = import_react4.default.useState(false);
776
+ const [isEditing, setIsEditing] = import_react5.default.useState(false);
469
777
  const label = (value == null ? void 0 : value.label) || "";
470
778
  const url = (value == null ? void 0 : value.url) || "";
471
779
  if (!isEditing) {
472
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 h-full w-full", children: [
473
- url ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate", children: label || url }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-slate-400 italic flex-1 text-sm", children: "\u05E8\u05D9\u05E7" }),
474
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
780
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2 px-2 py-1 h-full w-full", children: [
781
+ url ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: url, target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:underline flex-1 truncate", children: label || url }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-slate-400 italic flex-1 text-sm", children: "\u05E8\u05D9\u05E7" }),
782
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
475
783
  "button",
476
784
  {
477
785
  onClick: () => setIsEditing(true),
@@ -482,8 +790,8 @@ var FORM_INPUTS = {
482
790
  )
483
791
  ] });
484
792
  }
485
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex gap-2 p-1 w-full min-w-[250px] items-center bg-white border border-blue-200 rounded shadow-sm z-10", children: [
486
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
793
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-2 p-1 w-full min-w-[250px] items-center bg-white border border-blue-200 rounded shadow-sm z-10", children: [
794
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
487
795
  "input",
488
796
  {
489
797
  type: "text",
@@ -493,7 +801,7 @@ var FORM_INPUTS = {
493
801
  onChange: (e) => onChange({ label: e.target.value, url })
494
802
  }
495
803
  ),
496
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
804
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
497
805
  "input",
498
806
  {
499
807
  type: "url",
@@ -503,7 +811,7 @@ var FORM_INPUTS = {
503
811
  onChange: (e) => onChange({ label, url: e.target.value })
504
812
  }
505
813
  ),
506
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
814
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
507
815
  "button",
508
816
  {
509
817
  onClick: () => setIsEditing(false),
@@ -514,7 +822,7 @@ var FORM_INPUTS = {
514
822
  )
515
823
  ] });
516
824
  },
517
- BOOLEAN: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "flex items-center justify-center w-full h-full p-2", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
825
+ BOOLEAN: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center justify-center w-full h-full p-2", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
518
826
  "input",
519
827
  {
520
828
  type: "checkbox",
@@ -523,7 +831,7 @@ var FORM_INPUTS = {
523
831
  className: "w-4 h-4 rounded border-slate-300 text-brand"
524
832
  }
525
833
  ) }),
526
- GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
834
+ GOOGLE_DRIVE_FILE: ({ value, onChange, context }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
527
835
  DrivePickerCell,
528
836
  {
529
837
  value: value || null,
@@ -536,7 +844,7 @@ var FORM_INPUTS = {
536
844
  RELATION: ({ value, onChange, column, context }) => {
537
845
  var _a;
538
846
  const options = ((_a = context == null ? void 0 : context.relationOptions) == null ? void 0 : _a[column.name]) || [];
539
- import_react4.default.useEffect(() => {
847
+ import_react5.default.useEffect(() => {
540
848
  if (typeof value === "string" && value !== "" && options.length > 0) {
541
849
  const isValidId = options.some((o) => String(o.id) === String(value));
542
850
  if (!isValidId) {
@@ -555,7 +863,7 @@ var FORM_INPUTS = {
555
863
  _displayLabel: getRelationDisplayLabel(opt, column)
556
864
  }));
557
865
  const validOptions = processedOptions.filter((o) => o._displayLabel !== "\u05D4\u05E2\u05E8\u05DA \u05E9\u05D1\u05E8\u05E9\u05D5\u05DE\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E0\u05E9\u05D0\u05E8 \u05E8\u05D9\u05E7");
558
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
866
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
559
867
  "select",
560
868
  {
561
869
  className: "w-full h-8 px-2 bg-transparent focus:bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 text-sm",
@@ -567,13 +875,13 @@ var FORM_INPUTS = {
567
875
  }
568
876
  },
569
877
  children: [
570
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: "\u05D1\u05D7\u05E8..." }),
571
- validOptions.length > 0 ? validOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: opt.id, children: opt._displayLabel }, opt.id)) : options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "empty_all", disabled: true, children: "\u05DB\u05DC \u05D4\u05E2\u05E8\u05DB\u05D9\u05DD \u05D1\u05D8\u05D1\u05DC\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E8\u05D9\u05E7\u05D9\u05DD" }) : null
878
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "", children: "\u05D1\u05D7\u05E8..." }),
879
+ validOptions.length > 0 ? validOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: opt.id, children: opt._displayLabel }, opt.id)) : options.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "empty_all", disabled: true, children: "\u05DB\u05DC \u05D4\u05E2\u05E8\u05DB\u05D9\u05DD \u05D1\u05D8\u05D1\u05DC\u05D4 \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05EA \u05E8\u05D9\u05E7\u05D9\u05DD" }) : null
572
880
  ]
573
881
  }
574
882
  );
575
883
  },
576
- NUMBER: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
884
+ NUMBER: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
577
885
  "input",
578
886
  {
579
887
  type: "number",
@@ -585,7 +893,7 @@ var FORM_INPUTS = {
585
893
  }
586
894
  }
587
895
  ),
588
- DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
896
+ DEFAULT: ({ value, onChange }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
589
897
  "input",
590
898
  {
591
899
  type: "text",
@@ -597,7 +905,8 @@ var FORM_INPUTS = {
597
905
  };
598
906
 
599
907
  // src/components/TableBlock/TableBlockClient.tsx
600
- var import_jsx_runtime4 = require("react/jsx-runtime");
908
+ var import_lucide_react4 = require("lucide-react");
909
+ var import_jsx_runtime5 = require("react/jsx-runtime");
601
910
  function TableBlockClient({
602
911
  data: initialRecords,
603
912
  settings: schema,
@@ -614,6 +923,68 @@ function TableBlockClient({
614
923
  "data-testid": dataTestId
615
924
  }) {
616
925
  const { showError, addToast } = useToast();
926
+ const [columnWidths, setColumnWidths] = (0, import_react6.useState)({});
927
+ const [isMounted, setIsMounted] = (0, import_react6.useState)(false);
928
+ const tableKey = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
929
+ const [page, setPage] = (0, import_react6.useState)(1);
930
+ const [limit, setLimit] = (0, import_react6.useState)(50);
931
+ const [totalRecords, setTotalRecords] = (0, import_react6.useState)(0);
932
+ const [totalPages, setTotalPages] = (0, import_react6.useState)(1);
933
+ (0, import_react6.useEffect)(() => {
934
+ if (typeof window !== "undefined") {
935
+ const savedWidths = localStorage.getItem(`table_widths_${tableKey}`);
936
+ if (savedWidths) {
937
+ try {
938
+ setColumnWidths(JSON.parse(savedWidths));
939
+ } catch (e) {
940
+ }
941
+ }
942
+ const savedSummary = localStorage.getItem(`table_summary_${tableKey}`);
943
+ if (savedSummary !== null) {
944
+ setShowSummary(savedSummary === "true");
945
+ }
946
+ const savedLimit = localStorage.getItem(`table_limit_${tableKey}`);
947
+ if (savedLimit) {
948
+ const parsed = parseInt(savedLimit, 10);
949
+ if ([20, 50, 100].includes(parsed)) {
950
+ setLimit(parsed);
951
+ }
952
+ }
953
+ }
954
+ setIsMounted(true);
955
+ }, [tableKey]);
956
+ const [showSummary, setShowSummary] = (0, import_react6.useState)(false);
957
+ const toggleSummary = () => {
958
+ setShowSummary((prev) => {
959
+ const next = !prev;
960
+ const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
961
+ localStorage.setItem(`table_summary_${tableKey2}`, String(next));
962
+ return next;
963
+ });
964
+ };
965
+ const [resizingCol, setResizingCol] = (0, import_react6.useState)(null);
966
+ (0, import_react6.useEffect)(() => {
967
+ if (!resizingCol) return;
968
+ const handleMouseMove = (e) => {
969
+ const diffX = resizingCol.startX - e.clientX;
970
+ const newWidth = Math.max(100, Math.min(500, resizingCol.startWidth + diffX));
971
+ setColumnWidths((prev) => __spreadProps(__spreadValues({}, prev), { [resizingCol.name]: newWidth }));
972
+ };
973
+ const handleMouseUp = () => {
974
+ setResizingCol(null);
975
+ setColumnWidths((prev) => {
976
+ const tableKey2 = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id) || (schema == null ? void 0 : schema.name) || "default";
977
+ localStorage.setItem(`table_widths_${tableKey2}`, JSON.stringify(prev));
978
+ return prev;
979
+ });
980
+ };
981
+ document.addEventListener("mousemove", handleMouseMove);
982
+ document.addEventListener("mouseup", handleMouseUp);
983
+ return () => {
984
+ document.removeEventListener("mousemove", handleMouseMove);
985
+ document.removeEventListener("mouseup", handleMouseUp);
986
+ };
987
+ }, [resizingCol, schema]);
617
988
  const normalizeRecords = (records) => {
618
989
  return (records || []).map((row) => {
619
990
  var _c;
@@ -639,18 +1010,38 @@ function TableBlockClient({
639
1010
  return __spreadProps(__spreadValues({}, row), { id: String(row.id || ""), data: rowData });
640
1011
  });
641
1012
  };
642
- const [localColumns, setLocalColumns] = (0, import_react5.useState)(() => (schema == null ? void 0 : schema.columns) || []);
643
- (0, import_react5.useEffect)(() => {
1013
+ const mergeColumnDefs = (0, import_react6.useCallback)((existingCols, incomingCols) => {
1014
+ if (!incomingCols || incomingCols.length === 0) return existingCols || [];
1015
+ if (!existingCols || existingCols.length === 0) return incomingCols;
1016
+ const existingMap = new Map(existingCols.map((c) => [c.name, c]));
1017
+ const merged = incomingCols.map((inc) => {
1018
+ const ext = existingMap.get(inc.name);
1019
+ if (ext) {
1020
+ existingMap.delete(inc.name);
1021
+ return __spreadValues(__spreadValues({}, ext), inc);
1022
+ }
1023
+ return inc;
1024
+ });
1025
+ for (const [, extCol] of existingMap) {
1026
+ merged.push(extCol);
1027
+ }
1028
+ return merged.sort((a, b) => {
1029
+ var _a, _b;
1030
+ return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
1031
+ });
1032
+ }, []);
1033
+ const [localColumns, setLocalColumns] = (0, import_react6.useState)(() => (schema == null ? void 0 : schema.columns) || []);
1034
+ (0, import_react6.useEffect)(() => {
644
1035
  if ((schema == null ? void 0 : schema.columns) && schema.columns.length > 0) {
645
- setLocalColumns(schema.columns);
1036
+ setLocalColumns((prev) => mergeColumnDefs(prev, schema.columns));
646
1037
  }
647
- }, [schema == null ? void 0 : schema.columns]);
648
- const [dirty, setDirty] = (0, import_react5.useState)({ added: [], modified: {}, deleted: [] });
649
- const dirtyRef = (0, import_react5.useRef)(dirty);
650
- (0, import_react5.useEffect)(() => {
1038
+ }, [schema == null ? void 0 : schema.columns, mergeColumnDefs]);
1039
+ const [dirty, setDirty] = (0, import_react6.useState)({ added: [], modified: {}, deleted: [] });
1040
+ const dirtyRef = (0, import_react6.useRef)(dirty);
1041
+ (0, import_react6.useEffect)(() => {
651
1042
  dirtyRef.current = dirty;
652
1043
  }, [dirty]);
653
- const mergeWithDirty = (0, import_react5.useCallback)((baseRecords) => {
1044
+ const mergeWithDirty = (0, import_react6.useCallback)((baseRecords) => {
654
1045
  const { added, modified, deleted } = dirtyRef.current;
655
1046
  const nonDeleted = (baseRecords || []).filter((r) => !deleted.includes(r.id));
656
1047
  const modifiedRecords = nonDeleted.map((r) => {
@@ -663,8 +1054,8 @@ function TableBlockClient({
663
1054
  const uniqueAdded = added.filter((r) => !baseIds.has(r.id));
664
1055
  return [...uniqueAdded, ...modifiedRecords];
665
1056
  }, []);
666
- const [data, setData] = (0, import_react5.useState)(() => normalizeRecords(initialRecords));
667
- (0, import_react5.useEffect)(() => {
1057
+ const [data, setData] = (0, import_react6.useState)(() => normalizeRecords(initialRecords));
1058
+ (0, import_react6.useEffect)(() => {
668
1059
  if (initialRecords) {
669
1060
  setData(mergeWithDirty(normalizeRecords(initialRecords)));
670
1061
  }
@@ -679,54 +1070,82 @@ function TableBlockClient({
679
1070
  }
680
1071
  return false;
681
1072
  };
682
- const [baseRecordsMap, setBaseRecordsMap] = (0, import_react5.useState)(() => {
1073
+ const [baseRecordsMap, setBaseRecordsMap] = (0, import_react6.useState)(() => {
683
1074
  const map = /* @__PURE__ */ new Map();
684
1075
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
685
1076
  return map;
686
1077
  });
687
- (0, import_react5.useEffect)(() => {
1078
+ (0, import_react6.useEffect)(() => {
688
1079
  if (initialRecords && initialRecords.length > 0) {
689
1080
  const map = /* @__PURE__ */ new Map();
690
1081
  (normalizeRecords(initialRecords) || []).forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
691
1082
  setBaseRecordsMap(map);
692
1083
  }
693
1084
  }, [initialRecords]);
694
- (0, import_react5.useEffect)(() => {
1085
+ const refetchTableData = (0, import_react6.useCallback)((targetPage) => {
695
1086
  const tableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
696
- if (!tableId || !executeAction) return;
697
- if (!(schema == null ? void 0 : schema.columns) || schema.columns.length === 0 || (!initialRecords || initialRecords.length === 0)) {
698
- executeAction("FETCH_TABLE_DATA", { tableId }).then((res) => {
699
- var _a;
700
- if (res) {
701
- if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
702
- setLocalColumns(res.schema.columns);
703
- }
704
- if (res.records && Array.isArray(res.records)) {
705
- const norm = normalizeRecords(res.records);
706
- const map = /* @__PURE__ */ new Map();
707
- norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
708
- setBaseRecordsMap(map);
709
- setData(mergeWithDirty(norm));
1087
+ if (!tableId || !executeAction) return Promise.resolve();
1088
+ const activePage = targetPage !== void 0 ? targetPage : page;
1089
+ const skip = (activePage - 1) * limit;
1090
+ return executeAction("FETCH_TABLE_DATA", { tableId, page: activePage, limit, skip }).then((res) => {
1091
+ var _a;
1092
+ if (res) {
1093
+ if (((_a = res.schema) == null ? void 0 : _a.columns) && res.schema.columns.length > 0) {
1094
+ setLocalColumns((prev) => mergeColumnDefs(prev, res.schema.columns));
1095
+ }
1096
+ if (res.records && Array.isArray(res.records)) {
1097
+ const norm = normalizeRecords(res.records);
1098
+ const map = /* @__PURE__ */ new Map();
1099
+ norm.forEach((r) => map.set(r.id, __spreadValues({}, r.data)));
1100
+ setBaseRecordsMap(map);
1101
+ setData(norm);
1102
+ }
1103
+ if (res.meta) {
1104
+ const total = typeof res.meta.totalRecords === "number" ? res.meta.totalRecords : 0;
1105
+ const pages = typeof res.meta.totalPages === "number" ? res.meta.totalPages : Math.ceil(total / limit) || 1;
1106
+ setTotalRecords(total);
1107
+ setTotalPages(pages);
1108
+ if (activePage > pages && pages >= 1) {
1109
+ setPage(pages);
710
1110
  }
1111
+ } else if (res.records && Array.isArray(res.records)) {
1112
+ setTotalRecords(res.records.length);
1113
+ setTotalPages(Math.ceil(res.records.length / limit) || 1);
711
1114
  }
712
- }).catch((err) => {
713
- console.error("[TableBlock] Failed to auto-fetch table data:", err);
714
- });
1115
+ }
1116
+ }).catch((err) => {
1117
+ console.error("[TableBlock] Failed to auto-fetch table data:", err);
1118
+ });
1119
+ }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, page, limit, executeAction, mergeWithDirty, mergeColumnDefs]);
1120
+ (0, import_react6.useEffect)(() => {
1121
+ refetchTableData();
1122
+ }, [refetchTableData]);
1123
+ const handleLimitChange = (newLimit) => {
1124
+ setLimit(newLimit);
1125
+ setPage(1);
1126
+ if (typeof window !== "undefined") {
1127
+ localStorage.setItem(`table_limit_${tableKey}`, String(newLimit));
715
1128
  }
716
- }, [schema == null ? void 0 : schema.tableMetaId, schema == null ? void 0 : schema.tableId, schema == null ? void 0 : schema.id, schema == null ? void 0 : schema.columns, initialRecords, executeAction, mergeWithDirty]);
717
- (0, import_react5.useEffect)(() => {
1129
+ };
1130
+ const handlePrevPage = () => {
1131
+ setPage((prev) => Math.max(1, prev - 1));
1132
+ };
1133
+ const handleNextPage = () => {
1134
+ setPage((prev) => Math.min(totalPages, prev + 1));
1135
+ };
1136
+ (0, import_react6.useEffect)(() => {
718
1137
  if (error) {
719
1138
  showError(error, "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E8\u05DB\u05D9\u05D1");
720
1139
  }
721
1140
  }, [error, showError]);
722
- const [searchQuery, setSearchQuery] = (0, import_react5.useState)("");
723
- const [selectedIds, setSelectedIds] = (0, import_react5.useState)(/* @__PURE__ */ new Set());
724
- const [pendingDeletions, setPendingDeletions] = (0, import_react5.useState)([]);
725
- const [isSaving, setIsSaving] = (0, import_react5.useState)(false);
726
- const [isSaveSuccess, setIsSaveSuccess] = (0, import_react5.useState)(false);
727
- const [relationOptions, setRelationOptions] = (0, import_react5.useState)({});
728
- const schemaColsString = (0, import_react5.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
729
- const refetchRelation = (0, import_react5.useCallback)(async (colName) => {
1141
+ const [searchQuery, setSearchQuery] = (0, import_react6.useState)("");
1142
+ const [selectedIds, setSelectedIds] = (0, import_react6.useState)(/* @__PURE__ */ new Set());
1143
+ const [pendingDeletions, setPendingDeletions] = (0, import_react6.useState)([]);
1144
+ const [isSaving, setIsSaving] = (0, import_react6.useState)(false);
1145
+ const [isSaveSuccess, setIsSaveSuccess] = (0, import_react6.useState)(false);
1146
+ const [relationOptions, setRelationOptions] = (0, import_react6.useState)({});
1147
+ const schemaColsString = (0, import_react6.useMemo)(() => JSON.stringify(localColumns || []), [localColumns]);
1148
+ const refetchRelation = (0, import_react6.useCallback)(async (colName) => {
730
1149
  var _a;
731
1150
  let parsedCols = [];
732
1151
  try {
@@ -746,7 +1165,7 @@ function TableBlockClient({
746
1165
  console.warn(`[TableBlock] Could not fetch relation options for column ${colName}:`, err);
747
1166
  }
748
1167
  }, [schemaColsString, executeAction]);
749
- (0, import_react5.useEffect)(() => {
1168
+ (0, import_react6.useEffect)(() => {
750
1169
  let parsedCols = [];
751
1170
  try {
752
1171
  parsedCols = JSON.parse(schemaColsString);
@@ -760,10 +1179,144 @@ function TableBlockClient({
760
1179
  refetchRelation(col.name);
761
1180
  });
762
1181
  }, [schemaColsString, refetchRelation]);
763
- const filteredColumns = (0, import_react5.useMemo)(() => {
764
- const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
765
- return (localColumns || []).filter((col) => !systemFields.includes(col.name));
1182
+ const normalizedColumns = (0, import_react6.useMemo)(() => {
1183
+ return (localColumns || []).map((col, idx) => {
1184
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
1185
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
1186
+ const isProtected = isRequired || isUnique;
1187
+ return __spreadProps(__spreadValues({}, col), {
1188
+ order: typeof col.order === "number" ? col.order : idx,
1189
+ isHidden: isProtected ? false : Boolean(col.isHidden)
1190
+ });
1191
+ }).sort((a, b) => {
1192
+ var _a, _b;
1193
+ return ((_a = a.order) != null ? _a : 0) - ((_b = b.order) != null ? _b : 0);
1194
+ });
766
1195
  }, [localColumns]);
1196
+ const filteredColumns = (0, import_react6.useMemo)(() => {
1197
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1198
+ return normalizedColumns.filter((col) => !systemFields.includes(col.name) && !col.isHidden);
1199
+ }, [normalizedColumns]);
1200
+ const customizableColumns = (0, import_react6.useMemo)(() => {
1201
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1202
+ return normalizedColumns.filter((col) => !systemFields.includes(col.name));
1203
+ }, [normalizedColumns]);
1204
+ const [isColumnsDropdownOpen, setIsColumnsDropdownOpen] = (0, import_react6.useState)(false);
1205
+ const dropdownRef = (0, import_react6.useRef)(null);
1206
+ (0, import_react6.useEffect)(() => {
1207
+ const handleClickOutside = (e) => {
1208
+ if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
1209
+ setIsColumnsDropdownOpen(false);
1210
+ }
1211
+ };
1212
+ if (isColumnsDropdownOpen) {
1213
+ document.addEventListener("mousedown", handleClickOutside);
1214
+ }
1215
+ return () => {
1216
+ document.removeEventListener("mousedown", handleClickOutside);
1217
+ };
1218
+ }, [isColumnsDropdownOpen]);
1219
+ const handleShowAllColumns = async () => {
1220
+ var _a;
1221
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1222
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
1223
+ const updatedCustomCols = customizableColumns.map((col) => __spreadProps(__spreadValues({}, col), {
1224
+ isHidden: false
1225
+ }));
1226
+ const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
1227
+ setLocalColumns(fullUpdatedColumns);
1228
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
1229
+ if (targetTableId && executeAction) {
1230
+ try {
1231
+ const res = await executeAction("UPDATE_TABLE_COLUMNS", {
1232
+ tableId: targetTableId,
1233
+ tableMetaId: targetTableId,
1234
+ columns: fullUpdatedColumns
1235
+ });
1236
+ const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
1237
+ if (returnedCols && Array.isArray(returnedCols)) {
1238
+ setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
1239
+ }
1240
+ } catch (err) {
1241
+ console.error("[TableBlock] Failed to save show all columns:", err);
1242
+ showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05D4\u05E6\u05D2\u05EA \u05DB\u05DC \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
1243
+ }
1244
+ }
1245
+ };
1246
+ const handleToggleColumnVisibility = async (colName, isVisible) => {
1247
+ var _a;
1248
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1249
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
1250
+ const updatedCustomCols = customizableColumns.map((col) => {
1251
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
1252
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
1253
+ const isProtected = isRequired || isUnique;
1254
+ if (col.name === colName) {
1255
+ if (isProtected) {
1256
+ return __spreadProps(__spreadValues({}, col), { isHidden: false });
1257
+ }
1258
+ return __spreadProps(__spreadValues({}, col), { isHidden: !isVisible });
1259
+ }
1260
+ return __spreadProps(__spreadValues({}, col), {
1261
+ isHidden: isProtected ? false : Boolean(col.isHidden)
1262
+ });
1263
+ });
1264
+ const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
1265
+ setLocalColumns(fullUpdatedColumns);
1266
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
1267
+ if (targetTableId && executeAction) {
1268
+ try {
1269
+ const res = await executeAction("UPDATE_TABLE_COLUMNS", {
1270
+ tableId: targetTableId,
1271
+ tableMetaId: targetTableId,
1272
+ columns: fullUpdatedColumns
1273
+ });
1274
+ const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
1275
+ if (returnedCols && Array.isArray(returnedCols)) {
1276
+ setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
1277
+ }
1278
+ } catch (err) {
1279
+ console.error("[TableBlock] Failed to save column visibility:", err);
1280
+ showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05D4\u05E1\u05EA\u05E8\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
1281
+ }
1282
+ }
1283
+ };
1284
+ const [draggedColName, setDraggedColName] = (0, import_react6.useState)(null);
1285
+ const [dragOverColName, setDragOverColName] = (0, import_react6.useState)(null);
1286
+ const handleColumnReorder = async (draggedName, dropTargetName) => {
1287
+ var _a;
1288
+ if (draggedName === dropTargetName) return;
1289
+ const currentCustomCols = [...customizableColumns];
1290
+ const fromIndex = currentCustomCols.findIndex((c) => c.name === draggedName);
1291
+ const toIndex = currentCustomCols.findIndex((c) => c.name === dropTargetName);
1292
+ if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
1293
+ const [draggedItem] = currentCustomCols.splice(fromIndex, 1);
1294
+ currentCustomCols.splice(toIndex, 0, draggedItem);
1295
+ const updatedCustomCols = currentCustomCols.map((col, idx) => __spreadProps(__spreadValues({}, col), {
1296
+ order: idx
1297
+ }));
1298
+ const systemFields = ["_id", "createdAt", "updatedAt", "orgId", "tableId"];
1299
+ const systemCols = (localColumns || []).filter((c) => systemFields.includes(c.name));
1300
+ const fullUpdatedColumns = [...systemCols, ...updatedCustomCols];
1301
+ setLocalColumns(fullUpdatedColumns);
1302
+ const targetTableId = (schema == null ? void 0 : schema.tableMetaId) || (schema == null ? void 0 : schema.tableId) || (schema == null ? void 0 : schema.id);
1303
+ if (targetTableId && executeAction) {
1304
+ try {
1305
+ const res = await executeAction("UPDATE_TABLE_COLUMNS", {
1306
+ tableId: targetTableId,
1307
+ tableMetaId: targetTableId,
1308
+ columns: fullUpdatedColumns
1309
+ });
1310
+ const returnedCols = (res == null ? void 0 : res.columns) || ((_a = res == null ? void 0 : res.data) == null ? void 0 : _a.columns);
1311
+ if (returnedCols && Array.isArray(returnedCols)) {
1312
+ setLocalColumns((prev) => mergeColumnDefs(prev, returnedCols));
1313
+ }
1314
+ } catch (err) {
1315
+ console.error("[TableBlock] Failed to save column reorder:", err);
1316
+ showError((err == null ? void 0 : err.message) || String(err), "\u05E9\u05D2\u05D9\u05D0\u05D4 \u05D1\u05E2\u05D3\u05DB\u05D5\u05DF \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D5\u05EA");
1317
+ }
1318
+ }
1319
+ };
767
1320
  const generateTempId = () => `temp_${Math.random().toString(36).substr(2, 9)}`;
768
1321
  const handleAddRow = () => {
769
1322
  const defaultData = {};
@@ -793,6 +1346,34 @@ function TableBlockClient({
793
1346
  setData((prev) => [newRow, ...prev]);
794
1347
  setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
795
1348
  };
1349
+ const handleDuplicateRow = () => {
1350
+ if (selectedIds.size !== 1) return;
1351
+ const targetId = Array.from(selectedIds)[0];
1352
+ const sourceRow = data.find((r) => r.id === targetId);
1353
+ if (!sourceRow) return;
1354
+ const uniqueColNames = new Set(
1355
+ (localColumns || []).filter((c) => c.isUnique === true || String(c.isUnique) === "true").map((c) => c.name)
1356
+ );
1357
+ const fieldsToScrub = /* @__PURE__ */ new Set(["id", "_id", "createdAt", "updatedAt", "created_at", "updated_at"]);
1358
+ const clonedData = __spreadValues({}, sourceRow.data);
1359
+ Object.keys(clonedData).forEach((key) => {
1360
+ var _a;
1361
+ if (fieldsToScrub.has(key) || uniqueColNames.has(key)) {
1362
+ const col = (localColumns || []).find((c) => c.name === key);
1363
+ const typeUpper = (_a = col == null ? void 0 : col.type) == null ? void 0 : _a.toUpperCase();
1364
+ if (typeUpper === "NUMBER" || typeUpper === "CURRENCY") {
1365
+ clonedData[key] = 0;
1366
+ } else if (typeUpper === "BOOLEAN") {
1367
+ clonedData[key] = false;
1368
+ } else {
1369
+ clonedData[key] = "";
1370
+ }
1371
+ }
1372
+ });
1373
+ const newRow = { id: generateTempId(), data: clonedData };
1374
+ setData((prev) => [newRow, ...prev]);
1375
+ setDirty((prev) => __spreadProps(__spreadValues({}, prev), { added: [newRow, ...prev.added] }));
1376
+ };
796
1377
  const handleCellChange = (rowId, colName, value) => {
797
1378
  setData((prev) => prev.map(
798
1379
  (row) => row.id === rowId ? __spreadProps(__spreadValues({}, row), { data: __spreadProps(__spreadValues({}, row.data), { [colName]: value }) }) : row
@@ -1013,6 +1594,7 @@ function TableBlockClient({
1013
1594
  return next;
1014
1595
  });
1015
1596
  setDirty({ added: [], modified: {}, deleted: [] });
1597
+ await refetchTableData();
1016
1598
  setIsSaveSuccess(true);
1017
1599
  setTimeout(() => {
1018
1600
  setIsSaveSuccess(false);
@@ -1025,7 +1607,7 @@ function TableBlockClient({
1025
1607
  setIsSaving(false);
1026
1608
  }
1027
1609
  };
1028
- const filteredData = (0, import_react5.useMemo)(() => {
1610
+ const filteredData = (0, import_react6.useMemo)(() => {
1029
1611
  if (!searchQuery) return data;
1030
1612
  const lowerQuery = searchQuery.toLowerCase();
1031
1613
  return data.filter(
@@ -1036,32 +1618,60 @@ function TableBlockClient({
1036
1618
  }, [data, searchQuery]);
1037
1619
  const isUpdatingActive = Boolean(isUpdating || isSaving);
1038
1620
  const errorMessage = error ? typeof error === "string" ? error : error.message || String(error) : null;
1039
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1621
+ const columnTotals = (0, import_react6.useMemo)(() => {
1622
+ const totals = {};
1623
+ if (!showSummary) return totals;
1624
+ filteredColumns.forEach((col) => {
1625
+ var _a;
1626
+ const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
1627
+ if (typeUpper === "CURRENCY" || typeUpper === "NUMBER") {
1628
+ const sum = filteredData.reduce((acc, row) => {
1629
+ var _a2;
1630
+ const val = (_a2 = row.data) == null ? void 0 : _a2[col.name];
1631
+ const num = Number(val);
1632
+ return acc + (isNaN(num) ? 0 : num);
1633
+ }, 0);
1634
+ totals[col.name] = sum;
1635
+ }
1636
+ });
1637
+ return totals;
1638
+ }, [filteredData, filteredColumns, showSummary]);
1639
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1040
1640
  "div",
1041
1641
  {
1042
1642
  id: componentId,
1043
1643
  "data-testid": dataTestId || (componentId ? `table-block-${componentId}` : void 0),
1044
- className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs overflow-hidden ${className}`,
1644
+ className: `flex flex-col w-full bg-white border border-slate-200 rounded-xl shadow-xs min-h-[350px] overflow-hidden ${className}`,
1045
1645
  dir: "rtl",
1046
1646
  children: [
1047
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-2", children: [
1048
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
1049
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: errorMessage })
1647
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "p-3 bg-rose-50 border-b border-rose-200 text-rose-700 text-sm flex items-center justify-between", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
1648
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-rose-500 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
1649
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: errorMessage })
1050
1650
  ] }) }),
1051
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
1052
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
1053
- ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: schema.title || schema.name }) }),
1054
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center justify-between gap-3 p-3.5 sm:p-4 bg-slate-50 border-b border-slate-200", children: [
1652
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-wrap items-center gap-2.5", children: [
1653
+ ((schema == null ? void 0 : schema.title) || (schema == null ? void 0 : schema.name)) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "font-bold text-slate-800 text-sm sm:text-base border-l border-slate-300 pl-3 ml-1", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: schema.title || schema.name }) }),
1654
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1055
1655
  "button",
1056
1656
  {
1057
1657
  onClick: handleAddRow,
1058
1658
  disabled: isLoading || isUpdatingActive,
1059
1659
  className: "w-9 h-9 bg-emerald-600 hover:bg-emerald-700 active:bg-emerald-800 text-white rounded-lg shadow-xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
1060
1660
  title: "\u05D4\u05D5\u05E1\u05E3 \u05E9\u05D5\u05E8\u05D4 \u05D7\u05D3\u05E9\u05D4",
1061
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
1661
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M12 4v16m8-8H4" }) })
1662
+ }
1663
+ ),
1664
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1665
+ "button",
1666
+ {
1667
+ onClick: handleDuplicateRow,
1668
+ disabled: isLoading || isUpdatingActive || selectedIds.size !== 1,
1669
+ className: "w-9 h-9 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-700 rounded-lg shadow-2xs flex items-center justify-center transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
1670
+ title: "\u05E9\u05DB\u05E4\u05DC \u05E9\u05D5\u05E8\u05D4 \u05E0\u05D1\u05D7\u05E8\u05EA",
1671
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.Copy, { className: "w-4 h-4 text-blue-600 shrink-0" })
1062
1672
  }
1063
1673
  ),
1064
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1674
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1065
1675
  "button",
1066
1676
  {
1067
1677
  onClick: handleDeleteSelected,
@@ -1069,14 +1679,120 @@ function TableBlockClient({
1069
1679
  className: "w-9 h-9 bg-rose-50 hover:bg-rose-100 border border-rose-200 text-rose-700 rounded-lg shadow-2xs flex items-center justify-center relative transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
1070
1680
  title: "\u05DE\u05D7\u05E7 \u05E9\u05D5\u05E8\u05D5\u05EA \u05E0\u05D1\u05D7\u05E8\u05D5\u05EA",
1071
1681
  children: [
1072
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("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" }) }),
1073
- selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
1682
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4.5 h-4.5 text-rose-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("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" }) }),
1683
+ selectedIds.size > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "absolute -top-1.5 -right-1.5 bg-rose-600 text-white min-w-[18px] h-[18px] px-1 rounded-full text-[10px] font-bold flex items-center justify-center shadow-xs", children: selectedIds.size })
1074
1684
  ]
1075
1685
  }
1076
1686
  ),
1077
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
1078
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
1079
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1687
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1688
+ "button",
1689
+ {
1690
+ onClick: toggleSummary,
1691
+ disabled: isLoading || isUpdatingActive,
1692
+ className: `h-9 px-3 border font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer ${showSummary ? "bg-indigo-50 border-indigo-200 text-indigo-700 hover:bg-indigo-100" : "bg-white border-slate-300 text-slate-700 hover:bg-slate-100"}`,
1693
+ title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E9\u05D5\u05E8\u05EA \u05E1\u05D9\u05DB\u05D5\u05DD",
1694
+ children: [
1695
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M4 6h16M4 10h16M4 14h16M4 18h16" }) }),
1696
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "hidden sm:inline", children: "\u05E1\u05DB\u05D9\u05DE\u05D4" })
1697
+ ]
1698
+ }
1699
+ ),
1700
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative", ref: dropdownRef, children: [
1701
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1702
+ "button",
1703
+ {
1704
+ onClick: () => setIsColumnsDropdownOpen((prev) => !prev),
1705
+ disabled: isLoading || isUpdatingActive,
1706
+ className: "h-9 px-3 bg-white hover:bg-slate-100 border border-slate-300 text-slate-700 font-semibold rounded-lg shadow-2xs flex items-center gap-1.5 text-xs transition-all disabled:opacity-40 disabled:pointer-events-none cursor-pointer",
1707
+ title: "\u05D4\u05E6\u05D2/\u05D4\u05E1\u05EA\u05E8 \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA",
1708
+ children: [
1709
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" }) }),
1710
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: `w-3.5 h-3.5 text-slate-500 transition-transform ${isColumnsDropdownOpen ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M19 9l-7 7-7-7" }) })
1711
+ ]
1712
+ }
1713
+ ),
1714
+ isColumnsDropdownOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute right-0 top-full mt-1.5 w-56 bg-white border border-slate-200 rounded-xl shadow-xl z-50 p-1.5 dir-rtl animate-in fade-in slide-in-from-top-2 duration-150", children: [
1715
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "px-2 py-1.5 text-xs font-bold text-slate-500 border-b border-slate-100 mb-1 flex items-center justify-between", children: [
1716
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
1717
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D4\u05E6\u05D2\u05EA \u05E2\u05DE\u05D5\u05D3\u05D5\u05EA" }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-[10px] font-normal text-slate-400", children: [
1719
+ "(",
1720
+ customizableColumns.filter((c) => !c.isHidden).length,
1721
+ "/",
1722
+ customizableColumns.length,
1723
+ ")"
1724
+ ] })
1725
+ ] }),
1726
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1727
+ "button",
1728
+ {
1729
+ type: "button",
1730
+ onClick: handleShowAllColumns,
1731
+ className: "text-xs text-brand hover:text-brand-hover font-semibold hover:underline cursor-pointer",
1732
+ children: "\u05D4\u05E6\u05D2 \u05D4\u05DB\u05DC"
1733
+ }
1734
+ )
1735
+ ] }),
1736
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-h-60 overflow-y-auto space-y-0.5", children: customizableColumns.map((col) => {
1737
+ const isRequired = col.isRequired === true || String(col.isRequired) === "true";
1738
+ const isUnique = col.isUnique === true || String(col.isUnique) === "true";
1739
+ const isProtected = isRequired || isUnique;
1740
+ const isVisible = !col.isHidden;
1741
+ let protectedExplanation = "";
1742
+ if (isRequired && isUnique) {
1743
+ protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 \u05D5\u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
1744
+ } else if (isRequired) {
1745
+ protectedExplanation = "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
1746
+ } else if (isUnique) {
1747
+ protectedExplanation = "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9 - \u05DC\u05D0 \u05E0\u05D9\u05EA\u05DF \u05DC\u05D4\u05D5\u05E8\u05D9\u05D3 \u05E2\u05DE\u05D5\u05D3\u05D4 \u05D6\u05D5 \u05DE\u05D4\u05EA\u05E6\u05D5\u05D2\u05D4";
1748
+ }
1749
+ const badgeLabel = isRequired && isUnique ? "\u05D7\u05D5\u05D1\u05D4 + \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9" : isRequired ? "\u05E9\u05D3\u05D4 \u05D7\u05D5\u05D1\u05D4" : "\u05E9\u05D3\u05D4 \u05D9\u05D9\u05D7\u05D5\u05D3\u05D9";
1750
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1751
+ "div",
1752
+ {
1753
+ onClick: () => {
1754
+ if (!isProtected) {
1755
+ handleToggleColumnVisibility(col.name, !isVisible);
1756
+ }
1757
+ },
1758
+ title: isProtected ? protectedExplanation : void 0,
1759
+ className: `group flex items-center justify-between px-2.5 py-1.5 rounded-lg text-xs transition-colors select-none ${isProtected ? "opacity-75 bg-slate-50 border border-slate-100/70 cursor-not-allowed" : "hover:bg-slate-100 active:bg-slate-200 cursor-pointer"}`,
1760
+ children: [
1761
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2 min-w-0", children: [
1762
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1763
+ "input",
1764
+ {
1765
+ type: "checkbox",
1766
+ checked: isVisible,
1767
+ disabled: isProtected,
1768
+ onChange: () => {
1769
+ },
1770
+ className: "w-3.5 h-3.5 rounded border-slate-300 text-brand focus:ring-brand/20 cursor-pointer disabled:cursor-not-allowed disabled:opacity-60"
1771
+ }
1772
+ ),
1773
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `font-medium truncate ${isProtected ? "text-slate-500" : "text-slate-700"}`, children: col.name })
1774
+ ] }),
1775
+ isProtected && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1776
+ "div",
1777
+ {
1778
+ className: "flex items-center gap-1 px-1.5 py-0.5 rounded text-[10px] font-semibold bg-amber-50 text-amber-800 border border-amber-200/80 cursor-help",
1779
+ title: protectedExplanation,
1780
+ children: [
1781
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-3 h-3 text-amber-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: "2.2", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" }) }),
1782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: badgeLabel })
1783
+ ]
1784
+ }
1785
+ )
1786
+ ]
1787
+ },
1788
+ col.name
1789
+ );
1790
+ }) })
1791
+ ] })
1792
+ ] }),
1793
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "h-5 w-px bg-slate-300 mx-1 hidden sm:block" }),
1794
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "relative flex-1 sm:w-64 max-w-xs", children: [
1795
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1080
1796
  "input",
1081
1797
  {
1082
1798
  placeholder: "\u05D7\u05D9\u05E4\u05D5\u05E9 \u05D1\u05E8\u05E9\u05D5\u05DE\u05D5\u05EA...",
@@ -1086,36 +1802,45 @@ function TableBlockClient({
1086
1802
  className: "w-full h-9 px-3 pr-9 text-xs border border-slate-300 rounded-lg bg-white shadow-2xs focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 text-slate-800 disabled:opacity-50"
1087
1803
  }
1088
1804
  ),
1089
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
1805
+ searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1806
+ "button",
1807
+ {
1808
+ type: "button",
1809
+ onClick: () => setSearchQuery(""),
1810
+ className: "absolute right-2.5 top-2.5 text-slate-400 hover:text-slate-600 transition-colors p-0.5 rounded-full hover:bg-slate-100 cursor-pointer",
1811
+ title: "Clear search",
1812
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react4.X, { className: "w-3.5 h-3.5" })
1813
+ }
1814
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-slate-400 absolute right-2.5 top-2.5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) })
1090
1815
  ] })
1091
1816
  ] }),
1092
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-center gap-3", children: [
1093
- isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
1094
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
1817
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-3", children: [
1818
+ isUpdatingActive ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-blue-600 font-semibold flex items-center gap-1.5 bg-blue-50 border border-blue-200 px-3 py-1.5 rounded-lg animate-pulse", children: [
1819
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "w-2 h-2 rounded-full bg-blue-500 inline-block" }),
1095
1820
  "\u05DE\u05E2\u05D3\u05DB\u05DF..."
1096
- ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
1097
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
1821
+ ] }) : isSaveSuccess ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-xs text-emerald-700 font-semibold flex items-center gap-1.5 bg-emerald-50 border border-emerald-200 px-3 py-1.5 rounded-lg animate-in fade-in duration-200", children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-4 h-4 text-emerald-600 shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2.5", d: "M5 13l4 4L19 7" }) }),
1098
1823
  "\u05E2\u05D5\u05D3\u05DB\u05DF \u05D1\u05D4\u05E6\u05DC\u05D7\u05D4"
1099
- ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
1100
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1824
+ ] }) : hasChanges ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-xs font-semibold text-amber-700 animate-in fade-in", children: "\u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD \u05E9\u05DC\u05D0 \u05E0\u05E9\u05DE\u05E8\u05D5" }) : null,
1825
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1101
1826
  "button",
1102
1827
  {
1103
1828
  onClick: handleSave,
1104
1829
  disabled: isUpdatingActive || isLoading || !hasChanges,
1105
1830
  className: `h-9 px-4 text-xs font-bold rounded-lg shadow-2xs transition-all flex items-center justify-center cursor-pointer ${hasChanges && !isUpdatingActive && !isLoading ? "bg-brand hover:bg-brand-hover active:bg-[#00897b] text-white shadow-teal-500/20" : "opacity-50 grayscale bg-slate-200 text-slate-400 cursor-not-allowed"}`,
1106
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
1831
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: isUpdatingActive ? "\u05E9\u05D5\u05DE\u05E8..." : "\u05E9\u05DE\u05D9\u05E8\u05EA \u05E9\u05D9\u05E0\u05D5\u05D9\u05D9\u05DD" })
1107
1832
  }
1108
1833
  )
1109
1834
  ] })
1110
1835
  ] }),
1111
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "overflow-x-auto relative", children: [
1112
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
1113
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
1114
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
1836
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `overflow-x-auto relative min-h-[260px] flex-1 transition-opacity duration-200 ${isMounted ? "opacity-100" : "opacity-0"}`, children: [
1837
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "absolute inset-0 bg-white/80 backdrop-blur-xs z-20 flex flex-col items-center justify-center gap-2", children: [
1838
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "w-6 h-6 border-2 border-brand border-t-transparent rounded-full animate-spin" }),
1839
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-slate-600", children: "\u05D8\u05D5\u05E2\u05DF \u05E0\u05EA\u05D5\u05E0\u05D9\u05DD..." })
1115
1840
  ] }),
1116
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "w-full text-sm text-right border-collapse", children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
1118
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "w-full text-sm text-right border-collapse table-auto", children: [
1842
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { className: "bg-slate-100/80 text-slate-700 sticky top-0 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
1843
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "border-b border-l border-slate-200 p-2.5 w-10 text-center shrink-0", style: { width: 50, minWidth: 50, maxWidth: 50 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1119
1844
  "input",
1120
1845
  {
1121
1846
  type: "checkbox",
@@ -1125,13 +1850,83 @@ function TableBlockClient({
1125
1850
  className: "w-4 h-4 rounded border-slate-300 text-brand"
1126
1851
  }
1127
1852
  ) }),
1128
- filteredColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap min-w-[140px]", children: col.name }, col.name))
1853
+ filteredColumns.map((col) => {
1854
+ const isDragging = draggedColName === col.name;
1855
+ const isDragOver = dragOverColName === col.name;
1856
+ const currentWidth = columnWidths[col.name] || 200;
1857
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1858
+ "th",
1859
+ {
1860
+ style: { width: currentWidth, minWidth: currentWidth, maxWidth: currentWidth },
1861
+ draggable: !isLoading && !isUpdatingActive,
1862
+ onDragStart: (e) => {
1863
+ e.dataTransfer.setData("text/plain", col.name);
1864
+ e.dataTransfer.effectAllowed = "move";
1865
+ setDraggedColName(col.name);
1866
+ },
1867
+ onDragOver: (e) => {
1868
+ e.preventDefault();
1869
+ e.dataTransfer.dropEffect = "move";
1870
+ if (dragOverColName !== col.name) {
1871
+ setDragOverColName(col.name);
1872
+ }
1873
+ },
1874
+ onDragLeave: () => {
1875
+ if (dragOverColName === col.name) {
1876
+ setDragOverColName(null);
1877
+ }
1878
+ },
1879
+ onDrop: (e) => {
1880
+ e.preventDefault();
1881
+ if (draggedColName && draggedColName !== col.name) {
1882
+ handleColumnReorder(draggedColName, col.name);
1883
+ }
1884
+ setDraggedColName(null);
1885
+ setDragOverColName(null);
1886
+ },
1887
+ onDragEnd: () => {
1888
+ setDraggedColName(null);
1889
+ setDragOverColName(null);
1890
+ },
1891
+ className: `relative border-b border-l border-slate-200 px-4 py-2.5 font-semibold text-slate-700 whitespace-nowrap select-none cursor-grab active:cursor-grabbing transition-colors ${isDragging ? "opacity-40 bg-slate-200 border-dashed border-2 border-brand" : ""} ${isDragOver ? "bg-blue-50 border-r-4 border-r-brand text-brand font-bold" : "hover:bg-slate-200/60"}`,
1892
+ children: [
1893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1894
+ "div",
1895
+ {
1896
+ onMouseDown: (e) => {
1897
+ e.preventDefault();
1898
+ e.stopPropagation();
1899
+ setResizingCol({ name: col.name, startWidth: currentWidth, startX: e.clientX });
1900
+ },
1901
+ className: "absolute left-0 top-0 bottom-0 w-1.5 cursor-col-resize hover:bg-brand active:bg-brand-hover z-20",
1902
+ title: "\u05E9\u05E0\u05D4 \u05D2\u05D5\u05D3\u05DC \u05E2\u05DE\u05D5\u05D3\u05D4"
1903
+ }
1904
+ ),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center justify-between gap-2 group overflow-hidden", title: "\u05D2\u05E8\u05D5\u05E8 \u05DC\u05E9\u05D9\u05E0\u05D5\u05D9 \u05E1\u05D3\u05E8 \u05D4\u05E2\u05DE\u05D5\u05D3\u05D4", children: [
1906
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: col.name }),
1907
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1908
+ "svg",
1909
+ {
1910
+ className: "w-3.5 h-3.5 text-slate-400 opacity-40 group-hover:opacity-100 transition-opacity shrink-0 cursor-grab",
1911
+ fill: "none",
1912
+ viewBox: "0 0 24 24",
1913
+ stroke: "currentColor",
1914
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", d: "M8 9h.01M8 15h.01M16 9h.01M16 15h.01" })
1915
+ }
1916
+ )
1917
+ ] })
1918
+ ]
1919
+ },
1920
+ col.name
1921
+ );
1922
+ }),
1923
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("th", { className: "w-full min-w-[50px] border-b border-slate-200 pointer-events-none" })
1129
1924
  ] }) }),
1130
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { colSpan: filteredColumns.length + 1, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
1131
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
1132
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
1133
- ] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
1134
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1925
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { className: "bg-white", children: (isStateEmpty || filteredData.length === 0) && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { colSpan: filteredColumns.length + 2, className: "text-center py-12 text-slate-400", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col items-center justify-center gap-2", children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "w-8 h-8 text-slate-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "1.5", d: "M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4" }) }),
1927
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "\u05D0\u05D9\u05DF \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05DC\u05D4\u05E6\u05D2\u05D4." })
1928
+ ] }) }) }) : filteredData.map((row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { className: "hover:bg-blue-50/30 transition-colors group", children: [
1929
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1135
1930
  "input",
1136
1931
  {
1137
1932
  type: "checkbox",
@@ -1153,7 +1948,7 @@ function TableBlockClient({
1153
1948
  }
1154
1949
  }
1155
1950
  if (value === void 0) value = null;
1156
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1951
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-0 relative", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1157
1952
  InputComponent,
1158
1953
  {
1159
1954
  value,
@@ -1173,8 +1968,82 @@ function TableBlockClient({
1173
1968
  }
1174
1969
  }
1175
1970
  ) }, col.name);
1176
- })
1177
- ] }, row.id)) })
1971
+ }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-white pointer-events-none" })
1973
+ ] }, row.id)) }),
1974
+ showSummary && filteredData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tfoot", { className: "bg-slate-50 border-t-2 border-slate-300 sticky bottom-0 z-10 shadow-[0_-2px_4px_rgba(0,0,0,0.02)]", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("tr", { children: [
1975
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center font-bold text-slate-600 text-xs", children: '\u05E1\u05D4"\u05DB' }),
1976
+ filteredColumns.map((col) => {
1977
+ var _a;
1978
+ const typeUpper = (_a = col.type) == null ? void 0 : _a.toUpperCase();
1979
+ const isNumeric = typeUpper === "CURRENCY" || typeUpper === "NUMBER";
1980
+ const total = columnTotals[col.name];
1981
+ let displayVal = "";
1982
+ if (isNumeric && total !== void 0) {
1983
+ displayVal = new Intl.NumberFormat("en-US").format(total);
1984
+ if (typeUpper === "CURRENCY") {
1985
+ const symbol = getCurrencySymbol(col.currencySymbol);
1986
+ displayVal = symbol ? `${symbol} ${displayVal}` : displayVal;
1987
+ }
1988
+ }
1989
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-l border-slate-200 p-2 text-sm font-semibold text-slate-700 bg-slate-50 relative", children: isNumeric && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex items-center text-right justify-start", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "truncate", children: displayVal }) }) }, col.name);
1990
+ }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("td", { className: "border-b border-slate-200 bg-slate-50 pointer-events-none" })
1992
+ ] }) })
1993
+ ] })
1994
+ ] }),
1995
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex flex-col sm:flex-row items-center justify-between gap-3 px-4 py-3 bg-slate-50 border-t border-slate-200 text-xs text-slate-600 rounded-b-xl", children: [
1996
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-2", children: [
1997
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-medium text-slate-700", children: "\u05E9\u05D5\u05E8\u05D5\u05EA \u05DC\u05E2\u05DE\u05D5\u05D3:" }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1999
+ "select",
2000
+ {
2001
+ value: limit,
2002
+ onChange: (e) => handleLimitChange(Number(e.target.value)),
2003
+ disabled: isLoading || isUpdatingActive,
2004
+ className: "bg-white border border-slate-300 rounded-lg px-2.5 py-1 text-slate-700 font-semibold shadow-2xs cursor-pointer focus:outline-none focus:ring-2 focus:ring-brand disabled:opacity-50",
2005
+ children: [
2006
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 20, children: "20" }),
2007
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 50, children: "50" }),
2008
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: 100, children: "100" })
2009
+ ]
2010
+ }
2011
+ )
2012
+ ] }),
2013
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-4", children: [
2014
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "font-medium text-slate-600", children: [
2015
+ "\u05E2\u05DE\u05D5\u05D3 ",
2016
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: page }),
2017
+ " \u05DE\u05EA\u05D5\u05DA ",
2018
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { className: "text-slate-900", children: totalPages || 1 }),
2019
+ totalRecords > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "text-slate-500 font-normal", children: [
2020
+ " (",
2021
+ totalRecords,
2022
+ ' \u05E8\u05E9\u05D5\u05DE\u05D5\u05EA \u05D1\u05E1\u05D4"\u05DB)'
2023
+ ] })
2024
+ ] }),
2025
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2026
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2027
+ "button",
2028
+ {
2029
+ onClick: handlePrevPage,
2030
+ disabled: page <= 1 || isLoading || isUpdatingActive,
2031
+ className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
2032
+ title: "\u05E2\u05DE\u05D5\u05D3 \u05E7\u05D5\u05D3\u05DD",
2033
+ children: "\u05D4\u05E7\u05D5\u05D3\u05DD"
2034
+ }
2035
+ ),
2036
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2037
+ "button",
2038
+ {
2039
+ onClick: handleNextPage,
2040
+ disabled: page >= totalPages || isLoading || isUpdatingActive,
2041
+ className: "px-3 py-1.5 bg-white border border-slate-300 hover:bg-slate-100 font-semibold text-slate-700 rounded-lg shadow-2xs disabled:opacity-40 disabled:pointer-events-none transition-colors cursor-pointer",
2042
+ title: "\u05E2\u05DE\u05D5\u05D3 \u05D4\u05D1\u05D0",
2043
+ children: "\u05D4\u05D1\u05D0"
2044
+ }
2045
+ )
2046
+ ] })
1178
2047
  ] })
1179
2048
  ] })
1180
2049
  ]
@@ -1183,9 +2052,9 @@ function TableBlockClient({
1183
2052
  }
1184
2053
 
1185
2054
  // src/components/TableBlock/TableBlock.tsx
1186
- var import_jsx_runtime5 = require("react/jsx-runtime");
2055
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1187
2056
  function TableBlock(props) {
1188
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TableBlockClient, __spreadValues({}, props));
2057
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TableBlockClient, __spreadValues({}, props));
1189
2058
  }
1190
2059
 
1191
2060
  // src/registry.ts