@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.
package/dist/index.js CHANGED
@@ -6359,7 +6359,7 @@ import { createPortal as createPortal3 } from "react-dom";
6359
6359
  import axios3 from "axios";
6360
6360
  import { ChevronLeft as ChevronLeft6, ChevronRight as ChevronRight8, Search as Search5, Trash2 as Trash22, ChevronsUpDown, ChevronUp, ChevronDown as ChevronDown4, X as X9, Eye as Eye2, Pencil as Pencil2, Trash as Trash3, Loader2 as Loader22 } from "lucide-react";
6361
6361
  import { Fragment as Fragment12, jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
6362
- function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError }) {
6362
+ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOverrides, debounce = 300, transform, manual = false, refresh: refreshEnabled = false, refreshInterval = 0, hardReload, onSuccess, onError, filter: filterFields, sort: sortKeys }) {
6363
6363
  const [data, setData] = React28.useState([]);
6364
6364
  const [columns, setColumns] = React28.useState([]);
6365
6365
  const [currentPage, setCurrentPage] = React28.useState(1);
@@ -6369,6 +6369,15 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
6369
6369
  const [tick, setTick] = React28.useState(0);
6370
6370
  const [searchValue, setSearchValue] = React28.useState("");
6371
6371
  const debounceTimer = React28.useRef(void 0);
6372
+ const [filterValues, setFilterValues] = React28.useState(() => {
6373
+ const init = {};
6374
+ filterFields?.forEach((f) => {
6375
+ init[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
6376
+ });
6377
+ return init;
6378
+ });
6379
+ const [sortKey, setSortKey] = React28.useState("");
6380
+ const [sortDir, setSortDir] = React28.useState("asc");
6372
6381
  React28.useEffect(() => {
6373
6382
  if (hardReload) hardReload.current = () => setTick((t) => t + 1);
6374
6383
  }, [hardReload]);
@@ -6377,13 +6386,32 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
6377
6386
  const id = setInterval(() => setTick((t) => t + 1), refreshInterval);
6378
6387
  return () => clearInterval(id);
6379
6388
  }, [refreshInterval]);
6389
+ const activeFilterParams = React28.useMemo(() => {
6390
+ const out = {};
6391
+ filterFields?.forEach((f) => {
6392
+ const v = filterValues[f.key];
6393
+ if (f.type === "checkbox" || f.type === "toggle") {
6394
+ if (v) out[f.key] = 1;
6395
+ } else if (f.type === "date-range") {
6396
+ if (v?.from) out[`${f.key}_from`] = v.from;
6397
+ if (v?.to) out[`${f.key}_to`] = v.to;
6398
+ } else if (v !== "" && v !== null && v !== void 0) {
6399
+ out[f.key] = v;
6400
+ }
6401
+ });
6402
+ if (sortKey) {
6403
+ out.sort = sortKey;
6404
+ out.direction = sortDir;
6405
+ }
6406
+ return out;
6407
+ }, [filterValues, sortKey, sortDir, filterFields]);
6380
6408
  React28.useEffect(() => {
6381
6409
  if (manual && tick === 0) return;
6382
6410
  let cancelled = false;
6383
6411
  setLoading(true);
6384
6412
  setError(null);
6385
6413
  axios3.get(url, {
6386
- params: { ...params, page: currentPage, search: searchValue }
6414
+ params: { ...params, ...activeFilterParams, page: currentPage, search: searchValue }
6387
6415
  }).then(({ data: res }) => {
6388
6416
  if (cancelled) return;
6389
6417
  const payload = encrypt ? decryptLaravelPayload(res, key) : res;
@@ -6429,15 +6457,184 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
6429
6457
  return () => {
6430
6458
  cancelled = true;
6431
6459
  };
6432
- }, [url, currentPage, tick, JSON.stringify(params), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
6460
+ }, [url, currentPage, tick, JSON.stringify(params), JSON.stringify(activeFilterParams), encrypt, decryptPayloadLog, JSON.stringify(columnOverrides), searchValue]);
6433
6461
  const handleSearchChange = (value) => {
6434
6462
  setSearchValue(value);
6435
6463
  setCurrentPage(1);
6436
6464
  if (debounceTimer.current) clearTimeout(debounceTimer.current);
6437
- debounceTimer.current = setTimeout(() => {
6438
- setTick((t) => t + 1);
6439
- }, debounce);
6465
+ debounceTimer.current = setTimeout(() => setTick((t) => t + 1), debounce);
6466
+ };
6467
+ const handleFilterChange = (key2, value) => {
6468
+ setFilterValues((prev) => ({ ...prev, [key2]: value }));
6469
+ setCurrentPage(1);
6470
+ setTick((t) => t + 1);
6471
+ };
6472
+ const handleClearFilters = () => {
6473
+ const reset = {};
6474
+ filterFields?.forEach((f) => {
6475
+ reset[f.key] = f.type === "checkbox" || f.type === "toggle" ? false : "";
6476
+ });
6477
+ setFilterValues(reset);
6478
+ setSortKey("");
6479
+ setSortDir("asc");
6480
+ setCurrentPage(1);
6481
+ setTick((t) => t + 1);
6440
6482
  };
6483
+ const hasActiveFilters = filterFields?.some((f) => {
6484
+ const v = filterValues[f.key];
6485
+ return f.type === "checkbox" || f.type === "toggle" ? !!v : v !== "" && v !== null && v !== void 0;
6486
+ }) || !!sortKey;
6487
+ const filterBar = filterFields?.length || sortKeys?.length ? /* @__PURE__ */ jsxs30("div", { className: "flex flex-wrap items-end gap-3 rounded-xl border border-border bg-muted/30 px-4 py-3", children: [
6488
+ filterFields?.map((f) => {
6489
+ const label = f.label ?? f.key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
6490
+ const value = filterValues[f.key];
6491
+ const opts = (f.options ?? []).map(
6492
+ (o) => typeof o === "string" ? { label: o, value: o } : o
6493
+ );
6494
+ if (f.type === "checkbox") return /* @__PURE__ */ jsxs30("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
6495
+ /* @__PURE__ */ jsx32(
6496
+ "input",
6497
+ {
6498
+ type: "checkbox",
6499
+ checked: !!value,
6500
+ onChange: (e) => handleFilterChange(f.key, e.target.checked),
6501
+ className: "h-4 w-4 rounded accent-primary"
6502
+ }
6503
+ ),
6504
+ /* @__PURE__ */ jsx32("span", { className: "text-xs font-medium text-foreground", children: label })
6505
+ ] }, f.key);
6506
+ if (f.type === "toggle") return /* @__PURE__ */ jsxs30("label", { className: "flex items-center gap-2 cursor-pointer select-none", children: [
6507
+ /* @__PURE__ */ jsx32(
6508
+ "button",
6509
+ {
6510
+ type: "button",
6511
+ role: "switch",
6512
+ "aria-checked": !!value,
6513
+ onClick: () => handleFilterChange(f.key, !value),
6514
+ className: cn(
6515
+ "relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors",
6516
+ value ? "bg-primary" : "bg-muted"
6517
+ ),
6518
+ children: /* @__PURE__ */ jsx32("span", { className: cn(
6519
+ "pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform",
6520
+ value ? "translate-x-4" : "translate-x-0"
6521
+ ) })
6522
+ }
6523
+ ),
6524
+ /* @__PURE__ */ jsx32("span", { className: "text-xs font-medium text-foreground", children: label })
6525
+ ] }, f.key);
6526
+ if (f.type === "select") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
6527
+ /* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
6528
+ /* @__PURE__ */ jsxs30(
6529
+ "select",
6530
+ {
6531
+ value: value ?? "",
6532
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
6533
+ 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",
6534
+ children: [
6535
+ /* @__PURE__ */ jsx32("option", { value: "", children: f.placeholder ?? `All ${label}` }),
6536
+ opts.map((o) => /* @__PURE__ */ jsx32("option", { value: o.value, children: o.label }, o.value))
6537
+ ]
6538
+ }
6539
+ )
6540
+ ] }, f.key);
6541
+ if (f.type === "date" || f.type === "date-time") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
6542
+ /* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
6543
+ /* @__PURE__ */ jsx32(
6544
+ "input",
6545
+ {
6546
+ type: f.type === "date-time" ? "datetime-local" : "date",
6547
+ value: value ?? "",
6548
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
6549
+ 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"
6550
+ }
6551
+ )
6552
+ ] }, f.key);
6553
+ if (f.type === "date-range") return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
6554
+ /* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
6555
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
6556
+ /* @__PURE__ */ jsx32(
6557
+ "input",
6558
+ {
6559
+ type: "date",
6560
+ value: value?.from ?? "",
6561
+ onChange: (e) => handleFilterChange(f.key, { ...value, from: e.target.value }),
6562
+ 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"
6563
+ }
6564
+ ),
6565
+ /* @__PURE__ */ jsx32("span", { className: "text-xs text-muted-foreground", children: "\u2013" }),
6566
+ /* @__PURE__ */ jsx32(
6567
+ "input",
6568
+ {
6569
+ type: "date",
6570
+ value: value?.to ?? "",
6571
+ onChange: (e) => handleFilterChange(f.key, { ...value, to: e.target.value }),
6572
+ 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"
6573
+ }
6574
+ )
6575
+ ] })
6576
+ ] }, f.key);
6577
+ return /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
6578
+ /* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: label }),
6579
+ /* @__PURE__ */ jsx32(
6580
+ "input",
6581
+ {
6582
+ type: "text",
6583
+ value: value ?? "",
6584
+ placeholder: f.placeholder ?? `Filter ${label}\u2026`,
6585
+ onChange: (e) => handleFilterChange(f.key, e.target.value),
6586
+ 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"
6587
+ }
6588
+ )
6589
+ ] }, f.key);
6590
+ }),
6591
+ sortKeys?.length ? /* @__PURE__ */ jsxs30("div", { className: "flex flex-col gap-1", children: [
6592
+ /* @__PURE__ */ jsx32("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: "Sort by" }),
6593
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-1.5", children: [
6594
+ /* @__PURE__ */ jsxs30(
6595
+ "select",
6596
+ {
6597
+ value: sortKey,
6598
+ onChange: (e) => {
6599
+ setSortKey(e.target.value);
6600
+ setCurrentPage(1);
6601
+ setTick((t) => t + 1);
6602
+ },
6603
+ 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",
6604
+ children: [
6605
+ /* @__PURE__ */ jsx32("option", { value: "", children: "Default" }),
6606
+ sortKeys.map((k) => /* @__PURE__ */ jsx32("option", { value: k, children: k.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()) }, k))
6607
+ ]
6608
+ }
6609
+ ),
6610
+ sortKey && /* @__PURE__ */ jsx32(
6611
+ "button",
6612
+ {
6613
+ type: "button",
6614
+ onClick: () => {
6615
+ setSortDir((d) => d === "asc" ? "desc" : "asc");
6616
+ setTick((t) => t + 1);
6617
+ },
6618
+ 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",
6619
+ title: sortDir === "asc" ? "Ascending" : "Descending",
6620
+ children: sortDir === "asc" ? /* @__PURE__ */ jsx32(ChevronUp, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx32(ChevronDown4, { className: "h-3.5 w-3.5" })
6621
+ }
6622
+ )
6623
+ ] })
6624
+ ] }) : null,
6625
+ hasActiveFilters && /* @__PURE__ */ jsxs30(
6626
+ "button",
6627
+ {
6628
+ type: "button",
6629
+ onClick: handleClearFilters,
6630
+ 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",
6631
+ children: [
6632
+ /* @__PURE__ */ jsx32(X9, { className: "h-3 w-3" }),
6633
+ " Clear"
6634
+ ]
6635
+ }
6636
+ )
6637
+ ] }) : null;
6441
6638
  return {
6442
6639
  data,
6443
6640
  columns,
@@ -6446,6 +6643,7 @@ function useServerTable({ url, params, encrypt, key, decryptPayloadLog, columnOv
6446
6643
  serverPagination: pagination ? { pagination, currentPage, goToPage: (page) => setCurrentPage(page) } : null,
6447
6644
  loading,
6448
6645
  error,
6646
+ filterBar,
6449
6647
  goToPage: (page) => setCurrentPage(page),
6450
6648
  reload: () => setTick((t) => t + 1),
6451
6649
  refresh: () => setTick((t) => t + 1),
@@ -7155,6 +7353,9 @@ function Table({
7155
7353
  renderExpanded,
7156
7354
  columnVisibility,
7157
7355
  onColumnVisibilityChange,
7356
+ columnVisibilityIcon,
7357
+ filterBar,
7358
+ filterableIcon,
7158
7359
  exportable = false,
7159
7360
  onExport,
7160
7361
  virtualized = false,
@@ -7175,6 +7376,8 @@ function Table({
7175
7376
  const [sortKey, setSortKey] = React28.useState(null);
7176
7377
  const [sortDir, setSortDir] = React28.useState(null);
7177
7378
  const [bulkLoading, setBulkLoading] = React28.useState(false);
7379
+ const [bulkConfirm, setBulkConfirm] = React28.useState(null);
7380
+ const [filterBarOpen, setFilterBarOpen] = React28.useState(false);
7178
7381
  const [expandedIds, setExpandedIds] = React28.useState(/* @__PURE__ */ new Set());
7179
7382
  const [dragOverId, setDragOverId] = React28.useState(null);
7180
7383
  const [focusedRowIdx, setFocusedRowIdx] = React28.useState(-1);
@@ -7311,7 +7514,7 @@ function Table({
7311
7514
  const unselectedCount = totalRows - selectedIds.length;
7312
7515
  const handleSelectAllRecords = () => setSelectedIds(filteredData.map((item) => String(item[idKey])));
7313
7516
  const handleUnselectAll = () => setSelectedIds([]);
7314
- const handleBulkDeleteSelected = async () => {
7517
+ const execBulkDeleteSelected = async () => {
7315
7518
  if (!bulkDeleteBaseUrl || selectedIds.length === 0) {
7316
7519
  onBulkDelete?.(selectedIds);
7317
7520
  setSelectedIds([]);
@@ -7333,7 +7536,7 @@ function Table({
7333
7536
  setBulkLoading(false);
7334
7537
  }
7335
7538
  };
7336
- const handleDeleteAll = async () => {
7539
+ const execDeleteAll = async () => {
7337
7540
  if (!bulkDeleteBaseUrl) return;
7338
7541
  setBulkLoading(true);
7339
7542
  try {
@@ -7400,10 +7603,22 @@ function Table({
7400
7603
  ]
7401
7604
  }
7402
7605
  ),
7606
+ unselectedCount > 0 && /* @__PURE__ */ jsxs30(
7607
+ "button",
7608
+ {
7609
+ onClick: handleSelectAllRecords,
7610
+ disabled: bulkLoading,
7611
+ 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",
7612
+ children: [
7613
+ "Select all ",
7614
+ unselectedCount
7615
+ ]
7616
+ }
7617
+ ),
7403
7618
  /* @__PURE__ */ jsxs30(
7404
7619
  "button",
7405
7620
  {
7406
- onClick: handleBulkDeleteSelected,
7621
+ onClick: () => setBulkConfirm("selected"),
7407
7622
  disabled: bulkLoading,
7408
7623
  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",
7409
7624
  children: [
@@ -7413,30 +7628,29 @@ function Table({
7413
7628
  " selected"
7414
7629
  ]
7415
7630
  }
7631
+ ),
7632
+ bulkDeleteBaseUrl && /* @__PURE__ */ jsxs30(
7633
+ "button",
7634
+ {
7635
+ onClick: () => setBulkConfirm("all"),
7636
+ disabled: bulkLoading,
7637
+ 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",
7638
+ children: [
7639
+ bulkLoading ? /* @__PURE__ */ jsx32(Loader22, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx32(Trash22, { className: "h-3.5 w-3.5" }),
7640
+ "Delete all"
7641
+ ]
7642
+ }
7416
7643
  )
7417
7644
  ] }),
7418
- selectable && unselectedCount > 0 && /* @__PURE__ */ jsxs30(
7419
- "button",
7420
- {
7421
- onClick: handleSelectAllRecords,
7422
- disabled: bulkLoading,
7423
- 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",
7424
- children: [
7425
- "Select all ",
7426
- unselectedCount
7427
- ]
7428
- }
7429
- ),
7430
- selectable && bulkDeleteBaseUrl && /* @__PURE__ */ jsxs30(
7645
+ filterBar && /* @__PURE__ */ jsx32(
7431
7646
  "button",
7432
7647
  {
7433
- onClick: handleDeleteAll,
7434
- disabled: bulkLoading,
7435
- 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",
7436
- children: [
7437
- bulkLoading ? /* @__PURE__ */ jsx32(Loader22, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx32(Trash22, { className: "h-3.5 w-3.5" }),
7438
- "Delete all"
7439
- ]
7648
+ onClick: () => setFilterBarOpen((o) => !o),
7649
+ className: cn(
7650
+ "inline-flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium transition-colors",
7651
+ filterBarOpen ? "border-primary bg-primary/10 text-primary hover:bg-primary/20" : "border-border bg-muted/50 text-muted-foreground hover:bg-muted"
7652
+ ),
7653
+ children: filterableIcon ?? "Filter"
7440
7654
  }
7441
7655
  ),
7442
7656
  exportable && /* @__PURE__ */ jsxs30("div", { className: "relative group", children: [
@@ -7452,7 +7666,7 @@ function Table({
7452
7666
  )) })
7453
7667
  ] }),
7454
7668
  columnVisibility && onColumnVisibilityChange && /* @__PURE__ */ jsxs30("div", { className: "relative group", children: [
7455
- /* @__PURE__ */ jsx32("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" }),
7669
+ /* @__PURE__ */ jsx32("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" }),
7456
7670
  /* @__PURE__ */ jsx32("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__ */ jsxs30("label", { className: "flex items-center gap-2 px-2 py-1 rounded-lg hover:bg-muted cursor-pointer text-xs", children: [
7457
7671
  /* @__PURE__ */ jsx32(
7458
7672
  "input",
@@ -7474,6 +7688,7 @@ function Table({
7474
7688
  ] })
7475
7689
  ] })
7476
7690
  ] }),
7691
+ filterBar && filterBarOpen && /* @__PURE__ */ jsx32("div", { children: filterBar }),
7477
7692
  loading && /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-center py-12 text-muted-foreground gap-2", children: [
7478
7693
  /* @__PURE__ */ jsx32(Loader22, { className: "h-5 w-5 animate-spin" }),
7479
7694
  /* @__PURE__ */ jsx32("span", { className: "text-sm", children: "Loading\u2026" })
@@ -7867,6 +8082,37 @@ function Table({
7867
8082
  }
7868
8083
  }
7869
8084
  }
8085
+ ),
8086
+ bulkConfirm && createPortal3(
8087
+ /* @__PURE__ */ jsx32(
8088
+ "div",
8089
+ {
8090
+ className: "fixed inset-0 z-50 flex items-center justify-center p-4",
8091
+ style: { background: "rgba(0,0,0,0.5)" },
8092
+ onMouseDown: (e) => {
8093
+ if (e.target === e.currentTarget) setBulkConfirm(null);
8094
+ },
8095
+ children: /* @__PURE__ */ jsxs30("div", { className: "relative w-full max-w-md rounded-2xl border border-border bg-card shadow-2xl flex flex-col", children: [
8096
+ /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between px-6 py-4 border-b border-border", children: [
8097
+ /* @__PURE__ */ jsx32("h2", { className: "text-base font-semibold", children: "Confirm Delete" }),
8098
+ /* @__PURE__ */ jsx32("button", { onClick: () => setBulkConfirm(null), className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx32(X9, { className: "h-4 w-4" }) })
8099
+ ] }),
8100
+ /* @__PURE__ */ jsx32("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx32("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." }) }),
8101
+ /* @__PURE__ */ jsxs30("div", { className: "px-6 py-4 border-t border-border flex justify-end gap-2", children: [
8102
+ /* @__PURE__ */ jsx32(Button, { variant: "outline", size: "sm", onClick: () => setBulkConfirm(null), disabled: bulkLoading, children: "Cancel" }),
8103
+ /* @__PURE__ */ jsxs30(Button, { variant: "danger", size: "sm", disabled: bulkLoading, onClick: async () => {
8104
+ if (bulkConfirm === "selected") await execBulkDeleteSelected();
8105
+ else await execDeleteAll();
8106
+ setBulkConfirm(null);
8107
+ }, children: [
8108
+ bulkLoading && /* @__PURE__ */ jsx32(Loader22, { className: "h-3.5 w-3.5 mr-1.5 animate-spin" }),
8109
+ bulkLoading ? "Deleting\u2026" : "Delete"
8110
+ ] })
8111
+ ] })
8112
+ ] })
8113
+ }
8114
+ ),
8115
+ document.body
7870
8116
  )
7871
8117
  ] });
7872
8118
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "registry": "https://registry.npmjs.org/",
5
5
  "access": "public"
6
6
  },
7
- "version": "3.4.8",
7
+ "version": "3.5.0",
8
8
  "description": "Reusable React UI components",
9
9
  "license": "MIT",
10
10
  "main": "dist/index.js",