@rufous/ui 0.2.82 → 0.2.84

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/main.cjs CHANGED
@@ -4303,7 +4303,9 @@ function DataGrid({
4303
4303
  pageSizeOptions = [5, 10, 25, 50],
4304
4304
  title,
4305
4305
  className,
4306
- sx
4306
+ sx,
4307
+ onRowDoubleClick,
4308
+ onCellDoubleClick
4307
4309
  }) {
4308
4310
  const sxClass = useSx(sx);
4309
4311
  const [columnOverrides, setColumnOverrides] = (0, import_react23.useState)({});
@@ -4343,9 +4345,10 @@ function DataGrid({
4343
4345
  const menuRef = (0, import_react23.useRef)(null);
4344
4346
  const [showManageColumns, setShowManageColumns] = (0, import_react23.useState)(false);
4345
4347
  const [showAdvancedFilter, setShowAdvancedFilter] = (0, import_react23.useState)(false);
4346
- const initialFilterCol = String(initialColumnsProp[0]?.field || initialColumnsProp[0]?.key || "");
4348
+ const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
4349
+ const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
4347
4350
  const [advancedFilters, setAdvancedFilters] = (0, import_react23.useState)([
4348
- { column: initialFilterCol, operator: getDefaultOperator(initialColumnsProp[0]?.type), value: "", logic: "AND" }
4351
+ { column: initialFilterCol, operator: getDefaultOperator(filterableColumnsProp[0]?.type), value: "", logic: "AND" }
4349
4352
  ]);
4350
4353
  const [colSearch, setColSearch] = (0, import_react23.useState)("");
4351
4354
  (0, import_react23.useEffect)(() => {
@@ -4614,6 +4617,7 @@ function DataGrid({
4614
4617
  return offset2;
4615
4618
  };
4616
4619
  const hasActiveFilters = advancedFilters.some((f) => f.value);
4620
+ const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
4617
4621
  return /* @__PURE__ */ import_react23.default.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-header" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-header-info" }, /* @__PURE__ */ import_react23.default.createElement("h2", null, title), /* @__PURE__ */ import_react23.default.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-header-actions" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Search, { size: 15 }), /* @__PURE__ */ import_react23.default.createElement(
4618
4622
  "input",
4619
4623
  {
@@ -4639,7 +4643,7 @@ function DataGrid({
4639
4643
  onClick: () => setShowManageColumns(true)
4640
4644
  },
4641
4645
  /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Columns, { size: 16 })
4642
- )), /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Download, { size: 14 }), " Export CSV"))), /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-table-wrap" }, /* @__PURE__ */ import_react23.default.createElement("table", { className: "dg-table" }, /* @__PURE__ */ import_react23.default.createElement("thead", null, /* @__PURE__ */ import_react23.default.createElement("tr", null, visibleColumns.map((col, idx) => {
4646
+ )), /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Download, { size: 14 }), " Export CSV"))), /* @__PURE__ */ import_react23.default.createElement("div", { className: `dg-table-wrap${paginatedData.length === 0 ? " dg-table-wrap--empty" : ""}` }, /* @__PURE__ */ import_react23.default.createElement("table", { className: "dg-table" }, /* @__PURE__ */ import_react23.default.createElement("thead", null, /* @__PURE__ */ import_react23.default.createElement("tr", null, visibleColumns.map((col, idx) => {
4643
4647
  const colField = String(col.field);
4644
4648
  const width = columnWidths[colField] || 200;
4645
4649
  const leftOffset = getLeftOffset(col, idx);
@@ -4681,7 +4685,7 @@ function DataGrid({
4681
4685
  }
4682
4686
  )))
4683
4687
  );
4684
- }), actions && /* @__PURE__ */ import_react23.default.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ import_react23.default.createElement("tbody", null, paginatedData.length === 0 ? /* @__PURE__ */ import_react23.default.createElement("tr", null, /* @__PURE__ */ import_react23.default.createElement("td", { colSpan: visibleColumns.length + (actions ? 1 : 0), className: "dg-empty" }, "No records found")) : paginatedData.map((item) => /* @__PURE__ */ import_react23.default.createElement("tr", { key: item.id, className: "dg-tbody-row" }, visibleColumns.map((col, idx) => {
4688
+ }), actions && /* @__PURE__ */ import_react23.default.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ import_react23.default.createElement("tbody", null, paginatedData.length > 0 && paginatedData.map((item) => /* @__PURE__ */ import_react23.default.createElement("tr", { key: item.id, className: "dg-tbody-row", onDoubleClick: () => onRowDoubleClick?.(item) }, visibleColumns.map((col, idx) => {
4685
4689
  const colField = String(col.field);
4686
4690
  const width = columnWidths[colField] || 200;
4687
4691
  const leftOffset = getLeftOffset(col, idx);
@@ -4691,7 +4695,8 @@ function DataGrid({
4691
4695
  {
4692
4696
  key: `${item.id}-${colField}`,
4693
4697
  className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""} ${col.cellClassName || ""}`,
4694
- style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex }
4698
+ style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
4699
+ onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] })
4695
4700
  },
4696
4701
  (() => {
4697
4702
  const field = String(col.field);
@@ -4720,7 +4725,7 @@ function DataGrid({
4720
4725
  },
4721
4726
  action.icon
4722
4727
  )))));
4723
- })())))))), /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ import_react23.default.createElement("span", null, "Rows per page:"), /* @__PURE__ */ import_react23.default.createElement(
4728
+ })()))))), paginatedData.length === 0 && /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-empty-state" }, /* @__PURE__ */ import_react23.default.createElement("svg", { className: "dg-empty-icon", viewBox: "0 0 200 160", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ import_react23.default.createElement("rect", { x: "20", y: "30", width: "160", height: "100", rx: "8", fill: "var(--hover-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "20", y: "30", width: "160", height: "28", rx: "8", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "20", y: "50", width: "160", height: "8", rx: "0", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "72", y1: "30", x2: "72", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "128", y1: "30", x2: "128", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "20", y1: "78", x2: "180", y2: "78", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "20", y1: "104", x2: "180", y2: "104", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "32", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "84", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "140", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "32", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "84", y: "113", width: "32", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ import_react23.default.createElement("rect", { x: "140", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ import_react23.default.createElement("circle", { cx: "148", cy: "108", r: "26", fill: "var(--surface-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ import_react23.default.createElement("circle", { cx: "145", cy: "105", r: "10", stroke: "var(--text-secondary)", strokeWidth: "2.5", opacity: "0.5" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "152", y1: "113", x2: "161", y2: "122", stroke: "var(--text-secondary)", strokeWidth: "2.5", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "141", y1: "101", x2: "149", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ import_react23.default.createElement("line", { x1: "149", y1: "101", x2: "141", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" })), /* @__PURE__ */ import_react23.default.createElement("p", { className: "dg-empty-title" }, "No data found"), /* @__PURE__ */ import_react23.default.createElement("p", { className: "dg-empty-subtitle" }, filterText || hasActiveFilters ? "Try adjusting your search or filters" : "No records to display"))), /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ import_react23.default.createElement("span", null, "Rows per page:"), /* @__PURE__ */ import_react23.default.createElement(
4724
4729
  "select",
4725
4730
  {
4726
4731
  value: pageSize,
@@ -4741,16 +4746,14 @@ function DataGrid({
4741
4746
  ...menuPosition.right !== void 0 ? { right: menuPosition.right } : {}
4742
4747
  }
4743
4748
  },
4744
- /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "asc") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ArrowUp, { size: 14 }), " Sort ascending"),
4745
- /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "desc") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ArrowDown, { size: 14 }), " Sort descending"),
4746
- /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-menu-divider" }),
4749
+ activeMenuCol?.sortable !== false && /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "asc") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ArrowUp, { size: 14 }), " Sort ascending"), /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "desc") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.ArrowDown, { size: 14 }), " Sort descending"), /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-menu-divider" })),
4747
4750
  (() => {
4748
- const col = resolvedColumns.find((c) => c.field === activeMenu);
4751
+ const col = activeMenuCol;
4749
4752
  if (!col) return null;
4750
4753
  return /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, col.pinned === "left" ? /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "left") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Pin, { size: 14, style: { transform: "rotate(0deg)", opacity: 0.5 } }), " Unpin") : /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "left") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Pin, { size: 14, style: { transform: "rotate(45deg)" } }), " Pin left"), col.pinned === "right" ? /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "right") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Pin, { size: 14, style: { transform: "rotate(0deg)", opacity: 0.5 } }), " Unpin") : /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "right") }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Pin, { size: 14, style: { transform: "rotate(-45deg)" } }), " Pin right"));
4751
4754
  })(),
4752
4755
  /* @__PURE__ */ import_react23.default.createElement("div", { className: "dg-menu-divider" }),
4753
- /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => {
4756
+ activeMenuCol?.filterable !== false && /* @__PURE__ */ import_react23.default.createElement("button", { className: "dg-menu-item", onClick: () => {
4754
4757
  setShowAdvancedFilter(true);
4755
4758
  setActiveMenu(null);
4756
4759
  } }, /* @__PURE__ */ import_react23.default.createElement(import_lucide_react2.Filter, { size: 14 }), " Filter\u2026"),
@@ -4814,7 +4817,7 @@ function DataGrid({
4814
4817
  setAdvancedFilters((p) => p.map((fi, i) => i === idx ? { ...fi, column: newColKey, operator: defaultOp, value: "" } : fi));
4815
4818
  }
4816
4819
  },
4817
- resolvedColumns.map((c) => /* @__PURE__ */ import_react23.default.createElement("option", { key: String(c.key), value: String(c.key) }, c.header))
4820
+ resolvedColumns.filter((c) => c.filterable !== false).map((c) => /* @__PURE__ */ import_react23.default.createElement("option", { key: String(c.key), value: String(c.key) }, c.header))
4818
4821
  ), (() => {
4819
4822
  const col = resolvedColumns.find((c) => String(c.key) === f.column);
4820
4823
  const operators = getOperatorsForType(col?.type);
@@ -4862,7 +4865,8 @@ function DataGrid({
4862
4865
  className: "dg-action-btn",
4863
4866
  style: { alignSelf: "flex-start", marginTop: 4 },
4864
4867
  onClick: () => {
4865
- const firstCol = resolvedColumns[0];
4868
+ const firstCol = resolvedColumns.find((c) => c.filterable !== false);
4869
+ if (!firstCol) return;
4866
4870
  const defaultOp = getDefaultOperator(firstCol?.type);
4867
4871
  setAdvancedFilters((p) => [...p, { column: String(firstCol.key), operator: defaultOp, value: "", logic: "AND" }]);
4868
4872
  }
@@ -4874,7 +4878,8 @@ function DataGrid({
4874
4878
  {
4875
4879
  className: "dg-action-btn",
4876
4880
  onClick: () => {
4877
- const firstCol = resolvedColumns[0];
4881
+ const firstCol = resolvedColumns.find((c) => c.filterable !== false);
4882
+ if (!firstCol) return;
4878
4883
  setAdvancedFilters([{ column: String(firstCol.key), operator: getDefaultOperator(firstCol?.type), value: "", logic: "AND" }]);
4879
4884
  }
4880
4885
  },
package/dist/main.css CHANGED
@@ -416,6 +416,10 @@
416
416
  overflow-x: auto;
417
417
  flex: 1;
418
418
  }
419
+ .dg-table-wrap--empty {
420
+ display: flex;
421
+ flex-direction: column;
422
+ }
419
423
  .dg-table {
420
424
  width: 100%;
421
425
  border-collapse: collapse;
@@ -880,11 +884,33 @@
880
884
  --tf-hover-border-color: var(--text-secondary);
881
885
  --tf-primary-color: var(--primary-color);
882
886
  }
883
- .dg-empty {
884
- padding: 60px 20px;
885
- text-align: center;
887
+ .dg-empty-state {
888
+ flex: 1;
889
+ display: flex;
890
+ flex-direction: column;
891
+ align-items: center;
892
+ justify-content: center;
893
+ padding: 40px 20px;
894
+ gap: 12px;
895
+ position: sticky;
896
+ left: 0;
897
+ min-height: 280px;
898
+ }
899
+ .dg-empty-icon {
900
+ width: min(30%, 180px);
901
+ height: auto;
902
+ }
903
+ .dg-empty-title {
904
+ margin: 0;
905
+ font-size: 1rem;
906
+ font-weight: 600;
886
907
  color: var(--text-secondary);
887
- font-size: 0.9rem;
908
+ }
909
+ .dg-empty-subtitle {
910
+ margin: 0;
911
+ font-size: 0.82rem;
912
+ color: var(--text-secondary);
913
+ opacity: 0.65;
888
914
  }
889
915
 
890
916
  /* lib/style.css */
package/dist/main.d.cts CHANGED
@@ -818,11 +818,17 @@ interface DataGridProps<T> {
818
818
  title?: string;
819
819
  className?: string;
820
820
  sx?: SxProp;
821
+ onRowDoubleClick?: (row: T) => void;
822
+ onCellDoubleClick?: (params: {
823
+ row: T;
824
+ field: string;
825
+ value: any;
826
+ }) => void;
821
827
  }
822
828
 
823
829
  declare function DataGrid<T extends {
824
830
  id: string | number;
825
- }>({ columns: initialColumnsProp, data, actions, pageSize: initialPageSize, pageSizeOptions, title, className, sx, }: DataGridProps<T>): React__default.JSX.Element;
831
+ }>({ columns: initialColumnsProp, data, actions, pageSize: initialPageSize, pageSizeOptions, title, className, sx, onRowDoubleClick, onCellDoubleClick, }: DataGridProps<T>): React__default.JSX.Element;
826
832
 
827
833
  type SelectOption = {
828
834
  value: string | number;
package/dist/main.d.ts CHANGED
@@ -818,11 +818,17 @@ interface DataGridProps<T> {
818
818
  title?: string;
819
819
  className?: string;
820
820
  sx?: SxProp;
821
+ onRowDoubleClick?: (row: T) => void;
822
+ onCellDoubleClick?: (params: {
823
+ row: T;
824
+ field: string;
825
+ value: any;
826
+ }) => void;
821
827
  }
822
828
 
823
829
  declare function DataGrid<T extends {
824
830
  id: string | number;
825
- }>({ columns: initialColumnsProp, data, actions, pageSize: initialPageSize, pageSizeOptions, title, className, sx, }: DataGridProps<T>): React__default.JSX.Element;
831
+ }>({ columns: initialColumnsProp, data, actions, pageSize: initialPageSize, pageSizeOptions, title, className, sx, onRowDoubleClick, onCellDoubleClick, }: DataGridProps<T>): React__default.JSX.Element;
826
832
 
827
833
  type SelectOption = {
828
834
  value: string | number;
package/dist/main.js CHANGED
@@ -4173,7 +4173,9 @@ function DataGrid({
4173
4173
  pageSizeOptions = [5, 10, 25, 50],
4174
4174
  title,
4175
4175
  className,
4176
- sx
4176
+ sx,
4177
+ onRowDoubleClick,
4178
+ onCellDoubleClick
4177
4179
  }) {
4178
4180
  const sxClass = useSx(sx);
4179
4181
  const [columnOverrides, setColumnOverrides] = useState9({});
@@ -4213,9 +4215,10 @@ function DataGrid({
4213
4215
  const menuRef = useRef9(null);
4214
4216
  const [showManageColumns, setShowManageColumns] = useState9(false);
4215
4217
  const [showAdvancedFilter, setShowAdvancedFilter] = useState9(false);
4216
- const initialFilterCol = String(initialColumnsProp[0]?.field || initialColumnsProp[0]?.key || "");
4218
+ const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
4219
+ const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
4217
4220
  const [advancedFilters, setAdvancedFilters] = useState9([
4218
- { column: initialFilterCol, operator: getDefaultOperator(initialColumnsProp[0]?.type), value: "", logic: "AND" }
4221
+ { column: initialFilterCol, operator: getDefaultOperator(filterableColumnsProp[0]?.type), value: "", logic: "AND" }
4219
4222
  ]);
4220
4223
  const [colSearch, setColSearch] = useState9("");
4221
4224
  useEffect9(() => {
@@ -4484,6 +4487,7 @@ function DataGrid({
4484
4487
  return offset2;
4485
4488
  };
4486
4489
  const hasActiveFilters = advancedFilters.some((f) => f.value);
4490
+ const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
4487
4491
  return /* @__PURE__ */ React75.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, /* @__PURE__ */ React75.createElement("div", { className: "dg-header" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-header-info" }, /* @__PURE__ */ React75.createElement("h2", null, title), /* @__PURE__ */ React75.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ React75.createElement("div", { className: "dg-header-actions" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ React75.createElement(Search, { size: 15 }), /* @__PURE__ */ React75.createElement(
4488
4492
  "input",
4489
4493
  {
@@ -4509,7 +4513,7 @@ function DataGrid({
4509
4513
  onClick: () => setShowManageColumns(true)
4510
4514
  },
4511
4515
  /* @__PURE__ */ React75.createElement(Columns, { size: 16 })
4512
- )), /* @__PURE__ */ React75.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }), " Export CSV"))), /* @__PURE__ */ React75.createElement("div", { className: "dg-table-wrap" }, /* @__PURE__ */ React75.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React75.createElement("thead", null, /* @__PURE__ */ React75.createElement("tr", null, visibleColumns.map((col, idx) => {
4516
+ )), /* @__PURE__ */ React75.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }), " Export CSV"))), /* @__PURE__ */ React75.createElement("div", { className: `dg-table-wrap${paginatedData.length === 0 ? " dg-table-wrap--empty" : ""}` }, /* @__PURE__ */ React75.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React75.createElement("thead", null, /* @__PURE__ */ React75.createElement("tr", null, visibleColumns.map((col, idx) => {
4513
4517
  const colField = String(col.field);
4514
4518
  const width = columnWidths[colField] || 200;
4515
4519
  const leftOffset = getLeftOffset(col, idx);
@@ -4551,7 +4555,7 @@ function DataGrid({
4551
4555
  }
4552
4556
  )))
4553
4557
  );
4554
- }), actions && /* @__PURE__ */ React75.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React75.createElement("tbody", null, paginatedData.length === 0 ? /* @__PURE__ */ React75.createElement("tr", null, /* @__PURE__ */ React75.createElement("td", { colSpan: visibleColumns.length + (actions ? 1 : 0), className: "dg-empty" }, "No records found")) : paginatedData.map((item) => /* @__PURE__ */ React75.createElement("tr", { key: item.id, className: "dg-tbody-row" }, visibleColumns.map((col, idx) => {
4558
+ }), actions && /* @__PURE__ */ React75.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React75.createElement("tbody", null, paginatedData.length > 0 && paginatedData.map((item) => /* @__PURE__ */ React75.createElement("tr", { key: item.id, className: "dg-tbody-row", onDoubleClick: () => onRowDoubleClick?.(item) }, visibleColumns.map((col, idx) => {
4555
4559
  const colField = String(col.field);
4556
4560
  const width = columnWidths[colField] || 200;
4557
4561
  const leftOffset = getLeftOffset(col, idx);
@@ -4561,7 +4565,8 @@ function DataGrid({
4561
4565
  {
4562
4566
  key: `${item.id}-${colField}`,
4563
4567
  className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""} ${col.cellClassName || ""}`,
4564
- style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex }
4568
+ style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
4569
+ onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] })
4565
4570
  },
4566
4571
  (() => {
4567
4572
  const field = String(col.field);
@@ -4590,7 +4595,7 @@ function DataGrid({
4590
4595
  },
4591
4596
  action.icon
4592
4597
  )))));
4593
- })())))))), /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ React75.createElement("span", null, "Rows per page:"), /* @__PURE__ */ React75.createElement(
4598
+ })()))))), paginatedData.length === 0 && /* @__PURE__ */ React75.createElement("div", { className: "dg-empty-state" }, /* @__PURE__ */ React75.createElement("svg", { className: "dg-empty-icon", viewBox: "0 0 200 160", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "30", width: "160", height: "100", rx: "8", fill: "var(--hover-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "30", width: "160", height: "28", rx: "8", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("rect", { x: "20", y: "50", width: "160", height: "8", rx: "0", fill: "var(--border-color)", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "72", y1: "30", x2: "72", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "128", y1: "30", x2: "128", y2: "130", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "20", y1: "78", x2: "180", y2: "78", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("line", { x1: "20", y1: "104", x2: "180", y2: "104", stroke: "var(--border-color)", strokeWidth: "1" }), /* @__PURE__ */ React75.createElement("rect", { x: "32", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "84", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "140", y: "87", width: "28", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.4" }), /* @__PURE__ */ React75.createElement("rect", { x: "32", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("rect", { x: "84", y: "113", width: "32", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("rect", { x: "140", y: "113", width: "20", height: "6", rx: "3", fill: "var(--border-color)", opacity: "0.3" }), /* @__PURE__ */ React75.createElement("circle", { cx: "148", cy: "108", r: "26", fill: "var(--surface-color)", stroke: "var(--border-color)", strokeWidth: "1.5" }), /* @__PURE__ */ React75.createElement("circle", { cx: "145", cy: "105", r: "10", stroke: "var(--text-secondary)", strokeWidth: "2.5", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "152", y1: "113", x2: "161", y2: "122", stroke: "var(--text-secondary)", strokeWidth: "2.5", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "141", y1: "101", x2: "149", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" }), /* @__PURE__ */ React75.createElement("line", { x1: "149", y1: "101", x2: "141", y2: "109", stroke: "var(--text-secondary)", strokeWidth: "2", strokeLinecap: "round", opacity: "0.5" })), /* @__PURE__ */ React75.createElement("p", { className: "dg-empty-title" }, "No data found"), /* @__PURE__ */ React75.createElement("p", { className: "dg-empty-subtitle" }, filterText || hasActiveFilters ? "Try adjusting your search or filters" : "No records to display"))), /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ React75.createElement("span", null, "Rows per page:"), /* @__PURE__ */ React75.createElement(
4594
4599
  "select",
4595
4600
  {
4596
4601
  value: pageSize,
@@ -4611,16 +4616,14 @@ function DataGrid({
4611
4616
  ...menuPosition.right !== void 0 ? { right: menuPosition.right } : {}
4612
4617
  }
4613
4618
  },
4614
- /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "asc") }, /* @__PURE__ */ React75.createElement(ArrowUp, { size: 14 }), " Sort ascending"),
4615
- /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "desc") }, /* @__PURE__ */ React75.createElement(ArrowDown, { size: 14 }), " Sort descending"),
4616
- /* @__PURE__ */ React75.createElement("div", { className: "dg-menu-divider" }),
4619
+ activeMenuCol?.sortable !== false && /* @__PURE__ */ React75.createElement(React75.Fragment, null, /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "asc") }, /* @__PURE__ */ React75.createElement(ArrowUp, { size: 14 }), " Sort ascending"), /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => handleSort(activeMenu, "desc") }, /* @__PURE__ */ React75.createElement(ArrowDown, { size: 14 }), " Sort descending"), /* @__PURE__ */ React75.createElement("div", { className: "dg-menu-divider" })),
4617
4620
  (() => {
4618
- const col = resolvedColumns.find((c) => c.field === activeMenu);
4621
+ const col = activeMenuCol;
4619
4622
  if (!col) return null;
4620
4623
  return /* @__PURE__ */ React75.createElement(React75.Fragment, null, col.pinned === "left" ? /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "left") }, /* @__PURE__ */ React75.createElement(Pin, { size: 14, style: { transform: "rotate(0deg)", opacity: 0.5 } }), " Unpin") : /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "left") }, /* @__PURE__ */ React75.createElement(Pin, { size: 14, style: { transform: "rotate(45deg)" } }), " Pin left"), col.pinned === "right" ? /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "right") }, /* @__PURE__ */ React75.createElement(Pin, { size: 14, style: { transform: "rotate(0deg)", opacity: 0.5 } }), " Unpin") : /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => togglePin(activeMenu, "right") }, /* @__PURE__ */ React75.createElement(Pin, { size: 14, style: { transform: "rotate(-45deg)" } }), " Pin right"));
4621
4624
  })(),
4622
4625
  /* @__PURE__ */ React75.createElement("div", { className: "dg-menu-divider" }),
4623
- /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
4626
+ activeMenuCol?.filterable !== false && /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
4624
4627
  setShowAdvancedFilter(true);
4625
4628
  setActiveMenu(null);
4626
4629
  } }, /* @__PURE__ */ React75.createElement(Filter, { size: 14 }), " Filter\u2026"),
@@ -4684,7 +4687,7 @@ function DataGrid({
4684
4687
  setAdvancedFilters((p) => p.map((fi, i) => i === idx ? { ...fi, column: newColKey, operator: defaultOp, value: "" } : fi));
4685
4688
  }
4686
4689
  },
4687
- resolvedColumns.map((c) => /* @__PURE__ */ React75.createElement("option", { key: String(c.key), value: String(c.key) }, c.header))
4690
+ resolvedColumns.filter((c) => c.filterable !== false).map((c) => /* @__PURE__ */ React75.createElement("option", { key: String(c.key), value: String(c.key) }, c.header))
4688
4691
  ), (() => {
4689
4692
  const col = resolvedColumns.find((c) => String(c.key) === f.column);
4690
4693
  const operators = getOperatorsForType(col?.type);
@@ -4732,7 +4735,8 @@ function DataGrid({
4732
4735
  className: "dg-action-btn",
4733
4736
  style: { alignSelf: "flex-start", marginTop: 4 },
4734
4737
  onClick: () => {
4735
- const firstCol = resolvedColumns[0];
4738
+ const firstCol = resolvedColumns.find((c) => c.filterable !== false);
4739
+ if (!firstCol) return;
4736
4740
  const defaultOp = getDefaultOperator(firstCol?.type);
4737
4741
  setAdvancedFilters((p) => [...p, { column: String(firstCol.key), operator: defaultOp, value: "", logic: "AND" }]);
4738
4742
  }
@@ -4744,7 +4748,8 @@ function DataGrid({
4744
4748
  {
4745
4749
  className: "dg-action-btn",
4746
4750
  onClick: () => {
4747
- const firstCol = resolvedColumns[0];
4751
+ const firstCol = resolvedColumns.find((c) => c.filterable !== false);
4752
+ if (!firstCol) return;
4748
4753
  setAdvancedFilters([{ column: String(firstCol.key), operator: getDefaultOperator(firstCol?.type), value: "", logic: "AND" }]);
4749
4754
  }
4750
4755
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.2.82",
4
+ "version": "0.2.84",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",