@juv/codego-react-ui 3.4.8 → 3.5.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.
@@ -69638,7 +69638,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
69638
69638
  var React28 = __toESM(require_react(), 1);
69639
69639
  var import_react_dom2 = __toESM(require_react_dom(), 1);
69640
69640
  var import_jsx_runtime32 = __toESM(require_jsx_runtime(), 1);
69641
- function useServerTable({ url: url2, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError }) {
69641
+ function useServerTable({ url: url2, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError, filter: filterFields, sort: sortKeys }) {
69642
69642
  const [data, setData] = React28.useState([]);
69643
69643
  const [columns, setColumns] = React28.useState([]);
69644
69644
  const [currentPage, setCurrentPage] = React28.useState(1);
@@ -69648,6 +69648,15 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
69648
69648
  const [tick, setTick] = React28.useState(0);
69649
69649
  const [searchValue, setSearchValue] = React28.useState("");
69650
69650
  const debounceTimer = React28.useRef(void 0);
69651
+ const [filterValues, setFilterValues] = React28.useState(() => {
69652
+ const init = {};
69653
+ filterFields?.forEach((f) => {
69654
+ init[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
69655
+ });
69656
+ return init;
69657
+ });
69658
+ const [sortKey, setSortKey] = React28.useState("");
69659
+ const [sortDir, setSortDir] = React28.useState("asc");
69651
69660
  React28.useEffect(() => {
69652
69661
  if (hardReload) hardReload.current = () => setTick((t) => t + 1);
69653
69662
  }, [hardReload]);
@@ -69656,13 +69665,32 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
69656
69665
  const id = setInterval(() => setTick((t) => t + 1), refreshInterval);
69657
69666
  return () => clearInterval(id);
69658
69667
  }, [refreshInterval]);
69668
+ const activeFilterParams = React28.useMemo(() => {
69669
+ const out = {};
69670
+ filterFields?.forEach((f) => {
69671
+ const v = filterValues[f.key];
69672
+ if (f.type === "checkbox" || f.type === "toggle") {
69673
+ if (v) out[f.key] = 1;
69674
+ } else if (f.type === "date-range") {
69675
+ if (v?.from) out[`${f.key}_from`] = v.from;
69676
+ if (v?.to) out[`${f.key}_to`] = v.to;
69677
+ } else if (v !== "" && v !== null && v !== void 0) {
69678
+ out[f.key] = v;
69679
+ }
69680
+ });
69681
+ if (sortKey) {
69682
+ out.sort = sortKey;
69683
+ out.direction = sortDir;
69684
+ }
69685
+ return out;
69686
+ }, [filterValues, sortKey, sortDir, filterFields]);
69659
69687
  React28.useEffect(() => {
69660
69688
  if (manual && tick === 0) return;
69661
69689
  let cancelled = false;
69662
69690
  setLoading(true);
69663
69691
  setError(null);
69664
69692
  axios_default.get(url2, {
69665
- params: { ...params, page: currentPage, search: searchValue }
69693
+ params: { ...params, ...activeFilterParams, page: currentPage, search: searchValue }
69666
69694
  }).then(({ data: res }) => {
69667
69695
  if (cancelled) return;
69668
69696
  const payload = encrypt ? decryptLaravelPayload(res, key) : res;
@@ -69708,15 +69736,184 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
69708
69736
  return () => {
69709
69737
  cancelled = true;
69710
69738
  };
69711
- }, [url2, currentPage, tick, JSON.stringify(params), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
69739
+ }, [url2, currentPage, tick, JSON.stringify(params), JSON.stringify(activeFilterParams), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
69712
69740
  const handleSearchChange = (value) => {
69713
69741
  setSearchValue(value);
69714
69742
  setCurrentPage(1);
69715
69743
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
69716
- debounceTimer.current = setTimeout(() => {
69717
- setTick((t) => t + 1);
69718
- }, debounce);
69744
+ debounceTimer.current = setTimeout(() => setTick((t) => t + 1), debounce);
69745
+ };
69746
+ const handleFilterChange = (key2, value) => {
69747
+ setFilterValues((prev) => ({ ...prev, [key2]: value }));
69748
+ setCurrentPage(1);
69749
+ setTick((t) => t + 1);
69750
+ };
69751
+ const handleClearFilters = () => {
69752
+ const reset = {};
69753
+ filterFields?.forEach((f) => {
69754
+ reset[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
69755
+ });
69756
+ setFilterValues(reset);
69757
+ setSortKey("");
69758
+ setSortDir("asc");
69759
+ setCurrentPage(1);
69760
+ setTick((t) => t + 1);
69719
69761
  };
69762
+ const hasActiveFilters = filterFields?.some((f) => {
69763
+ const v = filterValues[f.key];
69764
+ return f.type === "checkbox" || f.type === "toggle" ? !!v : v !== "" && v !== null && v !== void 0;
69765
+ }) || !!sortKey;
69766
+ const filterBar = filterFields?.length || sortKeys?.length ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-wrap items-end gap-3 rounded-xl border border-border bg-muted/30 px-4 py-3", children: [
69767
+ filterFields?.map((f) => {
69768
+ const label = f.label ?? f.key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
69769
+ const value = filterValues[f.key];
69770
+ const opts = (f.options ?? []).map(
69771
+ (o) => typeof o === "string" ? { label: o, value: o } : o
69772
+ );
69773
+ if (f.type === "checkbox") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
69774
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69775
+ "input",
69776
+ {
69777
+ type: "checkbox",
69778
+ checked: !!value,
69779
+ onChange: (e) => handleFilterChange(f.key, e.target.checked),
69780
+ className: "h-4 w-4 rounded accent-primary"
69781
+ }
69782
+ ),
69783
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs font-medium text-foreground", children: label })
69784
+ ] }, f.key);
69785
+ if (f.type === "toggle") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
69786
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69787
+ "button",
69788
+ {
69789
+ type: "button",
69790
+ role: "switch",
69791
+ "aria-checked": !!value,
69792
+ onClick: () => handleFilterChange(f.key, !value),
69793
+ className: cn(
69794
+ "relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors",
69795
+ value ? "bg-primary" : "bg-muted"
69796
+ ),
69797
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: cn(
69798
+ "pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
69799
+ value ? "translate-x-4" : "translate-x-0"
69800
+ ) })
69801
+ }
69802
+ ),
69803
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs font-medium text-foreground", children: label })
69804
+ ] }, f.key);
69805
+ if (f.type === "select") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
69806
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
69807
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
69808
+ "select",
69809
+ {
69810
+ value: value ?? "",
69811
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
69812
+ className: "h-8 min-w-[120px] rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
69813
+ children: [
69814
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: "", children: f.placeholder ?? `All ${label}` }),
69815
+ opts.map((o) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: o.value, children: o.label }, o.value))
69816
+ ]
69817
+ }
69818
+ )
69819
+ ] }, f.key);
69820
+ if (f.type === "date" || f.type === "date-time") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
69821
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
69822
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69823
+ "input",
69824
+ {
69825
+ type: f.type === "date-time" ? "datetime-local" : "date",
69826
+ value: value ?? "",
69827
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
69828
+ className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
69829
+ }
69830
+ )
69831
+ ] }, f.key);
69832
+ if (f.type === "date-range") return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
69833
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
69834
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-1.5", children: [
69835
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69836
+ "input",
69837
+ {
69838
+ type: "date",
69839
+ value: value?.from ?? "",
69840
+ onChange: (e) => handleFilterChange(f.key, { ...value, from: e.target.value }),
69841
+ className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
69842
+ }
69843
+ ),
69844
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs text-muted-foreground", children: "\u2013" }),
69845
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69846
+ "input",
69847
+ {
69848
+ type: "date",
69849
+ value: value?.to ?? "",
69850
+ onChange: (e) => handleFilterChange(f.key, { ...value, to: e.target.value }),
69851
+ className: "h-8 rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
69852
+ }
69853
+ )
69854
+ ] })
69855
+ ] }, f.key);
69856
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
69857
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
69858
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69859
+ "input",
69860
+ {
69861
+ type: "text",
69862
+ value: value ?? "",
69863
+ placeholder: f.placeholder ?? `Filter ${label}\u2026`,
69864
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
69865
+ className: "h-8 min-w-[140px] rounded-lg border border-border bg-background px-3 text-xs text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors"
69866
+ }
69867
+ )
69868
+ ] }, f.key);
69869
+ }),
69870
+ sortKeys?.length ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex flex-col gap-1", children: [
69871
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Sort by" }),
69872
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center gap-1.5", children: [
69873
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
69874
+ "select",
69875
+ {
69876
+ value: sortKey,
69877
+ onChange: (e) => {
69878
+ setSortKey(e.target.value);
69879
+ setCurrentPage(1);
69880
+ setTick((t) => t + 1);
69881
+ },
69882
+ className: "h-8 min-w-[120px] rounded-lg border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-ring transition-colors",
69883
+ children: [
69884
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: "", children: "Default" }),
69885
+ sortKeys.map((k) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("option", { value: k, children: k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) }, k))
69886
+ ]
69887
+ }
69888
+ ),
69889
+ sortKey && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
69890
+ "button",
69891
+ {
69892
+ type: "button",
69893
+ onClick: () => {
69894
+ setSortDir((d) => d === "asc" ? "desc" : "asc");
69895
+ setTick((t) => t + 1);
69896
+ },
69897
+ className: "flex h-8 w-8 items-center justify-center rounded-lg border border-border bg-background text-muted-foreground hover:text-foreground hover:bg-muted transition-colors",
69898
+ title: sortDir === "asc" ? "Ascending" : "Descending",
69899
+ children: sortDir === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ChevronDown, { className: "h-3.5 w-3.5" })
69900
+ }
69901
+ )
69902
+ ] })
69903
+ ] }) : null,
69904
+ hasActiveFilters && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
69905
+ "button",
69906
+ {
69907
+ type: "button",
69908
+ onClick: handleClearFilters,
69909
+ className: "flex h-8 items-center gap-1.5 self-end rounded-lg border border-border bg-background px-3 text-xs font-medium text-muted-foreground hover:bg-muted hover:text-foreground transition-colors",
69910
+ children: [
69911
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(X, { className: "h-3 w-3" }),
69912
+ " Clear"
69913
+ ]
69914
+ }
69915
+ )
69916
+ ] }) : null;
69720
69917
  return {
69721
69918
  data,
69722
69919
  columns,
@@ -69725,6 +69922,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
69725
69922
  serverPagination: pagination ? { pagination, currentPage, goToPage: (page) => setCurrentPage(page) } : null,
69726
69923
  loading,
69727
69924
  error,
69925
+ filterBar,
69728
69926
  goToPage: (page) => setCurrentPage(page),
69729
69927
  reload: () => setTick((t) => t + 1),
69730
69928
  refresh: () => setTick((t) => t + 1),
@@ -70434,6 +70632,9 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70434
70632
  renderExpanded,
70435
70633
  columnVisibility,
70436
70634
  onColumnVisibilityChange,
70635
+ columnVisibilityIcon,
70636
+ filterBar,
70637
+ filterableIcon,
70437
70638
  exportable = false,
70438
70639
  onExport,
70439
70640
  virtualized = false,
@@ -70454,6 +70655,8 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70454
70655
  const [sortKey, setSortKey] = React28.useState(null);
70455
70656
  const [sortDir, setSortDir] = React28.useState(null);
70456
70657
  const [bulkLoading, setBulkLoading] = React28.useState(false);
70658
+ const [bulkConfirm, setBulkConfirm] = React28.useState(null);
70659
+ const [filterBarOpen, setFilterBarOpen] = React28.useState(false);
70457
70660
  const [expandedIds, setExpandedIds] = React28.useState(/* @__PURE__ */ new Set());
70458
70661
  const [dragOverId, setDragOverId] = React28.useState(null);
70459
70662
  const [focusedRowIdx, setFocusedRowIdx] = React28.useState(-1);
@@ -70590,7 +70793,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70590
70793
  const unselectedCount = totalRows - selectedIds.length;
70591
70794
  const handleSelectAllRecords = () => setSelectedIds(filteredData.map((item) => String(item[idKey])));
70592
70795
  const handleUnselectAll = () => setSelectedIds([]);
70593
- const handleBulkDeleteSelected = async () => {
70796
+ const execBulkDeleteSelected = async () => {
70594
70797
  if (!bulkDeleteBaseUrl || selectedIds.length === 0) {
70595
70798
  onBulkDelete?.(selectedIds);
70596
70799
  setSelectedIds([]);
@@ -70612,7 +70815,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70612
70815
  setBulkLoading(false);
70613
70816
  }
70614
70817
  };
70615
- const handleDeleteAll = async () => {
70818
+ const execDeleteAll = async () => {
70616
70819
  if (!bulkDeleteBaseUrl) return;
70617
70820
  setBulkLoading(true);
70618
70821
  try {
@@ -70679,10 +70882,22 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70679
70882
  ]
70680
70883
  }
70681
70884
  ),
70885
+ unselectedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
70886
+ "button",
70887
+ {
70888
+ onClick: handleSelectAllRecords,
70889
+ disabled: bulkLoading,
70890
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors disabled:opacity-40",
70891
+ children: [
70892
+ "Select all ",
70893
+ unselectedCount
70894
+ ]
70895
+ }
70896
+ ),
70682
70897
  /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
70683
70898
  "button",
70684
70899
  {
70685
- onClick: handleBulkDeleteSelected,
70900
+ onClick: () => setBulkConfirm("selected"),
70686
70901
  disabled: bulkLoading,
70687
70902
  className: "inline-flex items-center gap-1.5 rounded-lg bg-danger/10 border border-danger/20 px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40",
70688
70903
  children: [
@@ -70692,30 +70907,29 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70692
70907
  " selected"
70693
70908
  ]
70694
70909
  }
70910
+ ),
70911
+ bulkDeleteBaseUrl && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
70912
+ "button",
70913
+ {
70914
+ onClick: () => setBulkConfirm("all"),
70915
+ disabled: bulkLoading,
70916
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-danger/10 border border-danger/20 px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40",
70917
+ children: [
70918
+ bulkLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Trash2, { className: "h-3.5 w-3.5" }),
70919
+ "Delete all"
70920
+ ]
70921
+ }
70695
70922
  )
70696
70923
  ] }),
70697
- selectable && unselectedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
70698
- "button",
70699
- {
70700
- onClick: handleSelectAllRecords,
70701
- disabled: bulkLoading,
70702
- className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors disabled:opacity-40",
70703
- children: [
70704
- "Select all ",
70705
- unselectedCount
70706
- ]
70707
- }
70708
- ),
70709
- selectable && bulkDeleteBaseUrl && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
70924
+ filterBar && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
70710
70925
  "button",
70711
70926
  {
70712
- onClick: handleDeleteAll,
70713
- disabled: bulkLoading,
70714
- className: "inline-flex items-center gap-1.5 rounded-lg bg-danger/10 border border-danger/20 px-3 py-1.5 text-xs font-medium text-danger hover:bg-danger/20 transition-colors disabled:opacity-40",
70715
- children: [
70716
- bulkLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Trash2, { className: "h-3.5 w-3.5" }),
70717
- "Delete all"
70718
- ]
70927
+ onClick: () => setFilterBarOpen((o) => !o),
70928
+ className: cn(
70929
+ "inline-flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
70930
+ filterBarOpen ? "border-primary bg-primary/10 text-primary hover:bg-primary/20" : "border-border bg-muted/50 text-muted-foreground hover:bg-muted"
70931
+ ),
70932
+ children: filterableIcon ?? "Filter"
70719
70933
  }
70720
70934
  ),
70721
70935
  exportable && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative group", children: [
@@ -70731,7 +70945,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70731
70945
  )) })
70732
70946
  ] }),
70733
70947
  columnVisibility && onColumnVisibilityChange && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative group", children: [
70734
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: "Columns" }),
70948
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { className: "inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/50 px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-muted transition-colors", children: columnVisibilityIcon ?? "Columns" }),
70735
70949
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "absolute right-0 top-full mt-1 z-20 hidden group-hover:flex flex-col min-w-[150px] rounded-xl border border-border bg-card shadow-lg overflow-hidden p-2 gap-1", children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("label", { className: "flex items-center gap-2 px-2 py-1 rounded-lg hover:bg-muted cursor-pointer text-xs", children: [
70736
70950
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
70737
70951
  "input",
@@ -70753,6 +70967,7 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
70753
70967
  ] })
70754
70968
  ] })
70755
70969
  ] }),
70970
+ filterBar && filterBarOpen && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { children: filterBar }),
70756
70971
  loading && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-center py-12 text-muted-foreground gap-2", children: [
70757
70972
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(LoaderCircle, { className: "h-5 w-5 animate-spin" }),
70758
70973
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-sm", children: "Loading\u2026" })
@@ -71146,6 +71361,37 @@ ${n2.shaderPreludeCode.vertexSource}`, define: n2.shaderDefine }, defaultProject
71146
71361
  }
71147
71362
  }
71148
71363
  }
71364
+ ),
71365
+ bulkConfirm && (0, import_react_dom2.createPortal)(
71366
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
71367
+ "div",
71368
+ {
71369
+ className: "fixed inset-0 z-50 flex items-center justify-center p-4",
71370
+ style: { background: "rgba(0,0,0,0.5)" },
71371
+ onMouseDown: (e) => {
71372
+ if (e.target === e.currentTarget) setBulkConfirm(null);
71373
+ },
71374
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "relative w-full max-w-md rounded-2xl border border-border bg-card shadow-2xl flex flex-col", children: [
71375
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border", children: [
71376
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h2", { className: "text-base font-semibold", children: "Confirm Delete" }),
71377
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("button", { onClick: () => setBulkConfirm(null), className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(X, { className: "h-4 w-4" }) })
71378
+ ] }),
71379
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-6 py-4", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm text-muted-foreground", children: bulkConfirm === "selected" ? `Are you sure you want to delete ${selectedIds.length} selected record${selectedIds.length !== 1 ? "s" : ""}? This action cannot be undone.` : "Are you sure you want to delete all records? This action cannot be undone." }) }),
71380
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "px-6 py-4 border-t border-border flex justify-end gap-2", children: [
71381
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Button, { variant: "outline", size: "sm", onClick: () => setBulkConfirm(null), disabled: bulkLoading, children: "Cancel" }),
71382
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(Button, { variant: "danger", size: "sm", disabled: bulkLoading, onClick: async () => {
71383
+ if (bulkConfirm === "selected") await execBulkDeleteSelected();
71384
+ else await execDeleteAll();
71385
+ setBulkConfirm(null);
71386
+ }, children: [
71387
+ bulkLoading && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(LoaderCircle, { className: "h-3.5 w-3.5 mr-1.5 animate-spin" }),
71388
+ bulkLoading ? "Deleting\u2026" : "Delete"
71389
+ ] })
71390
+ ] })
71391
+ ] })
71392
+ }
71393
+ ),
71394
+ document.body
71149
71395
  )
71150
71396
  ] });
71151
71397
  }