@rufous/ui 0.3.23 → 0.3.25

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.js CHANGED
@@ -1687,6 +1687,7 @@ var TextField = forwardRef3(({
1687
1687
  slotProps,
1688
1688
  InputProps,
1689
1689
  numberVariant,
1690
+ step: stepProp,
1690
1691
  multiline = false,
1691
1692
  rows,
1692
1693
  maxRows,
@@ -1822,7 +1823,7 @@ var TextField = forwardRef3(({
1822
1823
  required,
1823
1824
  disabled,
1824
1825
  readOnly,
1825
- step: type === "number" && numberVariant ? STEP_BY_VARIANT[numberVariant] : void 0,
1826
+ step: type === "number" ? stepProp ?? (numberVariant ? STEP_BY_VARIANT[numberVariant] : void 0) : void 0,
1826
1827
  min: type === "number" && numberVariant ? MIN_BY_VARIANT[numberVariant] : void 0,
1827
1828
  ...slotProps?.input,
1828
1829
  ...props,
@@ -4472,8 +4473,57 @@ import {
4472
4473
  ArrowDown,
4473
4474
  Trash2,
4474
4475
  Plus,
4475
- ChevronsUpDown
4476
+ ChevronsUpDown,
4477
+ Layers
4476
4478
  } from "lucide-react";
4479
+ function getAllGroupIds(rows, fields, getKey, depth = 0, parentId = "") {
4480
+ if (!fields.length || !rows.length) return [];
4481
+ const [field, ...rest] = fields;
4482
+ const buckets = /* @__PURE__ */ new Map();
4483
+ rows.forEach((row) => {
4484
+ const k = getKey(row, field) || "(Blank)";
4485
+ if (!buckets.has(k)) buckets.set(k, []);
4486
+ buckets.get(k).push(row);
4487
+ });
4488
+ const out = [];
4489
+ buckets.forEach((children, k) => {
4490
+ const id = `${parentId}::${field}::${k}`;
4491
+ out.push({ id, field, key: k, depth, count: children.length });
4492
+ if (rest.length) out.push(...getAllGroupIds(children, rest, getKey, depth + 1, id));
4493
+ });
4494
+ return out;
4495
+ }
4496
+ function buildFlatEntries(rows, fields, getKey, expanded, depth = 0, parentId = "") {
4497
+ if (!fields.length) return rows.map((row) => ({ kind: "data", row, depth }));
4498
+ const [field, ...rest] = fields;
4499
+ const buckets = /* @__PURE__ */ new Map();
4500
+ rows.forEach((row) => {
4501
+ const k = getKey(row, field) || "(Blank)";
4502
+ if (!buckets.has(k)) buckets.set(k, []);
4503
+ buckets.get(k).push(row);
4504
+ });
4505
+ const out = [];
4506
+ buckets.forEach((children, k) => {
4507
+ const id = `${parentId}::${field}::${k}`;
4508
+ out.push({ kind: "group", id, field, key: k, depth, leafCount: children.length });
4509
+ if (expanded.has(id)) {
4510
+ out.push(...buildFlatEntries(children, rest, getKey, expanded, depth + 1, id));
4511
+ }
4512
+ });
4513
+ return out;
4514
+ }
4515
+ function buildTreeEntries(rows, getChildren, expanded, depth = 0) {
4516
+ const out = [];
4517
+ rows.forEach((row) => {
4518
+ const children = getChildren(row) ?? [];
4519
+ const hasChildren = children.length > 0;
4520
+ out.push({ kind: "data", row, depth, hasChildren });
4521
+ if (hasChildren && expanded.has(row.id)) {
4522
+ out.push(...buildTreeEntries(children, getChildren, expanded, depth + 1));
4523
+ }
4524
+ });
4525
+ return out;
4526
+ }
4477
4527
  function FilterSelect({
4478
4528
  value,
4479
4529
  onChange,
@@ -4571,7 +4621,21 @@ function DataGrid({
4571
4621
  searchableColumns,
4572
4622
  onSearchChange,
4573
4623
  onFiltersChange,
4574
- hideTopExport = false
4624
+ initialFilters,
4625
+ toolbarOptions,
4626
+ customToolbar,
4627
+ customFooter,
4628
+ hideTopExport = false,
4629
+ rowGroupingModel,
4630
+ defaultRowGroupingModel,
4631
+ onRowGroupingModelChange,
4632
+ rowGroupingColumnMode = "single",
4633
+ groupingColDef,
4634
+ defaultGroupingExpansionDepth = 0,
4635
+ isGroupExpandedByDefault,
4636
+ disableRowGrouping = false,
4637
+ treeData = false,
4638
+ getChildRows
4575
4639
  }) {
4576
4640
  const sxClass = useSx(sx);
4577
4641
  const [editingCell, setEditingCell] = useState9(null);
@@ -4631,10 +4695,46 @@ function DataGrid({
4631
4695
  const [focusFilterIdx, setFocusFilterIdx] = useState9(-1);
4632
4696
  const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
4633
4697
  const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
4634
- const [advancedFilters, setAdvancedFilters] = useState9([
4635
- { column: initialFilterCol, operator: getDefaultOperator(filterableColumnsProp[0]?.type), value: "", logic: "AND" }
4636
- ]);
4698
+ const [advancedFilters, setAdvancedFilters] = useState9(() => {
4699
+ if (initialFilters && initialFilters.length > 0) return initialFilters;
4700
+ return [{ column: initialFilterCol, operator: getDefaultOperator(filterableColumnsProp[0]?.type), value: "", logic: "AND" }];
4701
+ });
4637
4702
  const [colSearch, setColSearch] = useState9("");
4703
+ const [internalGroupingModel, setInternalGroupingModel] = useState9(
4704
+ defaultRowGroupingModel ?? []
4705
+ );
4706
+ const activeGroupingModel = rowGroupingModel ?? internalGroupingModel;
4707
+ const isGroupingActive = activeGroupingModel.length > 0;
4708
+ const setGroupingModel = (model) => {
4709
+ if (!rowGroupingModel) setInternalGroupingModel(model);
4710
+ onRowGroupingModelChange?.(model);
4711
+ };
4712
+ const addToGrouping = (field) => {
4713
+ if (activeGroupingModel.includes(field)) return;
4714
+ setGroupingModel([...activeGroupingModel, field]);
4715
+ };
4716
+ const removeFromGrouping = (field) => {
4717
+ setGroupingModel(activeGroupingModel.filter((f) => f !== field));
4718
+ };
4719
+ const [expandedGroups, setExpandedGroups] = useState9(/* @__PURE__ */ new Set());
4720
+ const prevGroupModelKeyRef = useRef10("");
4721
+ const toggleGroup = (groupId) => {
4722
+ setExpandedGroups((prev) => {
4723
+ const next = new Set(prev);
4724
+ if (next.has(groupId)) next.delete(groupId);
4725
+ else next.add(groupId);
4726
+ return next;
4727
+ });
4728
+ };
4729
+ const [treeExpandedRows, setTreeExpandedRows] = useState9(/* @__PURE__ */ new Set());
4730
+ const toggleTreeRow = (id) => {
4731
+ setTreeExpandedRows((prev) => {
4732
+ const next = new Set(prev);
4733
+ if (next.has(id)) next.delete(id);
4734
+ else next.add(id);
4735
+ return next;
4736
+ });
4737
+ };
4638
4738
  useEffect9(() => {
4639
4739
  const handleMouseMove = (e) => {
4640
4740
  if (!resizingColumn) return;
@@ -4677,6 +4777,13 @@ function DataGrid({
4677
4777
  return next;
4678
4778
  });
4679
4779
  }, [initialColumnsProp]);
4780
+ const getGroupValue = (item, field) => {
4781
+ const col = resolvedColumns.find((c) => String(c.field) === field || String(c.key) === field);
4782
+ const raw = item[field];
4783
+ if (col?.groupingValueGetter) return String(col.groupingValueGetter(raw, item) ?? "");
4784
+ if (col?.valueGetter) return String(col.valueGetter({ value: raw, row: item, field }) ?? "");
4785
+ return raw == null ? "" : String(raw);
4786
+ };
4680
4787
  const onFiltersChangeRef = useRef10(onFiltersChange);
4681
4788
  useEffect9(() => {
4682
4789
  onFiltersChangeRef.current = onFiltersChange;
@@ -4864,14 +4971,36 @@ function DataGrid({
4864
4971
  return 0;
4865
4972
  });
4866
4973
  }, [filteredData, sortField, sortDirection, resolvedColumns]);
4974
+ useEffect9(() => {
4975
+ const key = activeGroupingModel.join("\0");
4976
+ if (key === prevGroupModelKeyRef.current) return;
4977
+ prevGroupModelKeyRef.current = key;
4978
+ if (!activeGroupingModel.length) {
4979
+ setExpandedGroups(/* @__PURE__ */ new Set());
4980
+ return;
4981
+ }
4982
+ const allGroups = getAllGroupIds(sortedData, activeGroupingModel, getGroupValue);
4983
+ setExpandedGroups(new Set(
4984
+ allGroups.filter((g) => isGroupExpandedByDefault ? isGroupExpandedByDefault({ id: g.id, field: g.field, key: g.key, depth: g.depth, count: g.count }) : defaultGroupingExpansionDepth === -1 || g.depth < defaultGroupingExpansionDepth).map((g) => g.id)
4985
+ ));
4986
+ }, [activeGroupingModel.join("\0")]);
4987
+ const resolveChildren = getChildRows ?? ((row) => row.children ?? null);
4988
+ const flatEntries = useMemo2(() => {
4989
+ if (treeData) {
4990
+ return buildTreeEntries(sortedData, resolveChildren, treeExpandedRows);
4991
+ }
4992
+ if (!isGroupingActive) return null;
4993
+ return buildFlatEntries(sortedData, activeGroupingModel, getGroupValue, expandedGroups);
4994
+ }, [treeData, isGroupingActive, sortedData, activeGroupingModel.join("\0"), expandedGroups, treeExpandedRows]);
4867
4995
  const isServer = paginationMode === "server";
4868
- const totalRows = isServer ? rowCount ?? data.length : filteredData.length;
4996
+ const totalRows = isServer ? rowCount ?? data.length : flatEntries ? flatEntries.length : filteredData.length;
4869
4997
  const totalPages = Math.max(1, Math.ceil(totalRows / activePageSize));
4870
- const paginatedData = useMemo2(() => {
4871
- if (isServer) return data;
4998
+ const displayRows = useMemo2(() => {
4999
+ if (isServer) return data.map((row) => ({ kind: "data", row, depth: 0 }));
5000
+ const source = flatEntries ?? sortedData.map((row) => ({ kind: "data", row, depth: 0 }));
4872
5001
  const start = (activePage - 1) * activePageSize;
4873
- return sortedData.slice(start, start + activePageSize);
4874
- }, [isServer, data, sortedData, activePage, activePageSize]);
5002
+ return source.slice(start, start + activePageSize);
5003
+ }, [isServer, data, flatEntries, sortedData, activePage, activePageSize]);
4875
5004
  const handleExport = () => {
4876
5005
  const exportableCols = resolvedColumns.filter((c) => !c.hidden && c.isExportable !== false);
4877
5006
  const headers = exportableCols.map((c) => c.headerName).join(",");
@@ -4921,8 +5050,57 @@ function DataGrid({
4921
5050
  const left = resolvedColumns.filter((c) => !c.hidden && c.pinned === "left");
4922
5051
  const mid = resolvedColumns.filter((c) => !c.hidden && !c.pinned);
4923
5052
  const right = resolvedColumns.filter((c) => !c.hidden && c.pinned === "right");
4924
- return [...left, ...mid, ...right];
4925
- }, [resolvedColumns]);
5053
+ const dataCols = [...left, ...mid, ...right];
5054
+ if (treeData) {
5055
+ const treeCol = {
5056
+ key: "__tree__",
5057
+ field: "__tree__",
5058
+ header: "",
5059
+ headerName: "",
5060
+ width: 44,
5061
+ sortable: false,
5062
+ filterable: false,
5063
+ disableColumnMenu: true,
5064
+ hideable: false
5065
+ };
5066
+ return [treeCol, ...dataCols];
5067
+ }
5068
+ if (!isGroupingActive) return dataCols;
5069
+ if (rowGroupingColumnMode === "multiple") {
5070
+ const groupCols = activeGroupingModel.map((gField, i) => {
5071
+ const src = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
5072
+ const def2 = typeof groupingColDef === "function" ? groupingColDef(gField) : groupingColDef;
5073
+ return {
5074
+ key: `__group_${i}__`,
5075
+ field: `__group_${i}__`,
5076
+ header: def2?.headerName ?? src?.header ?? src?.headerName ?? gField,
5077
+ headerName: def2?.headerName ?? src?.header ?? src?.headerName ?? gField,
5078
+ width: def2?.width ?? 160,
5079
+ sortable: false,
5080
+ filterable: false,
5081
+ disableColumnMenu: true,
5082
+ hideable: false,
5083
+ __groupField: gField,
5084
+ __groupIndex: i
5085
+ };
5086
+ });
5087
+ return [...groupCols, ...dataCols];
5088
+ }
5089
+ const def = typeof groupingColDef === "function" ? groupingColDef(activeGroupingModel[0]) : groupingColDef;
5090
+ const singleSrc = resolvedColumns.find((c) => String(c.field) === activeGroupingModel[0] || String(c.key) === activeGroupingModel[0]);
5091
+ const singleGroupCol = {
5092
+ key: "__group__",
5093
+ field: "__group__",
5094
+ header: def?.headerName ?? (activeGroupingModel.length === 1 ? singleSrc?.header ?? singleSrc?.headerName ?? "Group" : "Group"),
5095
+ headerName: def?.headerName ?? (activeGroupingModel.length === 1 ? singleSrc?.header ?? singleSrc?.headerName ?? "Group" : "Group"),
5096
+ width: def?.width ?? 200,
5097
+ sortable: false,
5098
+ filterable: false,
5099
+ disableColumnMenu: true,
5100
+ hideable: false
5101
+ };
5102
+ return [singleGroupCol, ...dataCols];
5103
+ }, [resolvedColumns, isGroupingActive, activeGroupingModel, rowGroupingColumnMode, groupingColDef]);
4926
5104
  const getLeftOffset = (col, idx) => {
4927
5105
  if (col.pinned !== "left") return void 0;
4928
5106
  let offset2 = 0;
@@ -4957,7 +5135,14 @@ function DataGrid({
4957
5135
  };
4958
5136
  const activeMenuCol = activeMenu ? resolvedColumns.find((c) => String(c.field) === activeMenu) : null;
4959
5137
  const alignClass = (align) => align === "center" ? "dg-slot--center" : align === "right" ? "dg-slot--right" : "dg-slot--left";
4960
- 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(
5138
+ const tOpts = toolbarOptions ?? {};
5139
+ const showSearch = !tOpts.hideSearch;
5140
+ const showFilterBtn = !tOpts.hideFilter;
5141
+ const showColumnsBtn = !tOpts.hideColumns;
5142
+ const showExportBtn = !tOpts.hideExport && !hideTopExport;
5143
+ const showTitle = !tOpts.hideTitle;
5144
+ const showRecordCount = !tOpts.hideRecordCount;
5145
+ return /* @__PURE__ */ React75.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ React75.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ React75.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ React75.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ React75.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ React75.createElement(React75.Fragment, null, showSearch && /* @__PURE__ */ React75.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ React75.createElement(Search, { size: 15 }), /* @__PURE__ */ React75.createElement(
4961
5146
  "input",
4962
5147
  {
4963
5148
  className: "dg-search",
@@ -4968,23 +5153,35 @@ function DataGrid({
4968
5153
  setCurrentPage(1);
4969
5154
  }
4970
5155
  }
4971
- )), /* @__PURE__ */ React75.createElement(Tooltip, { title: "Filters", placement: "top" }, /* @__PURE__ */ React75.createElement(
5156
+ )), showFilterBtn && /* @__PURE__ */ React75.createElement(Tooltip, { title: "Filters", placement: "top" }, /* @__PURE__ */ React75.createElement(
4972
5157
  "button",
4973
5158
  {
4974
5159
  className: `dg-icon-btn ${hasActiveFilters ? "active" : ""}`,
4975
5160
  onClick: () => setShowAdvancedFilter(true)
4976
5161
  },
4977
5162
  /* @__PURE__ */ React75.createElement(Filter, { size: 16 })
4978
- )), /* @__PURE__ */ React75.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React75.createElement(
5163
+ )), showColumnsBtn && /* @__PURE__ */ React75.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React75.createElement(
4979
5164
  "button",
4980
5165
  {
4981
5166
  className: "dg-icon-btn",
4982
5167
  onClick: () => setShowManageColumns(true)
4983
5168
  },
4984
5169
  /* @__PURE__ */ React75.createElement(Columns, { size: 16 })
4985
- )), !hideTopExport && /* @__PURE__ */ React75.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }), " Export CSV"), headerActions && /* @__PURE__ */ React75.createElement("div", { className: `dg-header-slot ${alignClass(headerActions.align)}` }, headerActions.content))), /* @__PURE__ */ React75.createElement("div", { className: `dg-toolbar ${alignClass(toolbarContent?.align)}` }, toolbarContent?.content || ""), /* @__PURE__ */ React75.createElement("div", { className: `dg-table-wrap${paginatedData.length === 0 && !loading ? " dg-table-wrap--empty" : ""}` }, loading && /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-overlay" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-spinner" })), /* @__PURE__ */ React75.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React75.createElement("thead", null, /* @__PURE__ */ React75.createElement("tr", null, visibleColumns.map((col, idx) => {
5170
+ )), showExportBtn && /* @__PURE__ */ React75.createElement("button", { className: "dg-action-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }), " Export CSV")), headerActions && /* @__PURE__ */ React75.createElement("div", { className: `dg-header-slot ${alignClass(headerActions.align)}` }, headerActions.content))), !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-toolbar ${alignClass(toolbarContent?.align)}` }, toolbarContent?.content || ""), isGroupingActive && /* @__PURE__ */ React75.createElement("div", { className: "dg-grouping-bar" }, /* @__PURE__ */ React75.createElement("span", { className: "dg-grouping-bar-label" }, "Grouped by"), activeGroupingModel.map((gField) => {
5171
+ const col = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
5172
+ return /* @__PURE__ */ React75.createElement("div", { key: gField, className: "dg-group-chip" }, /* @__PURE__ */ React75.createElement(Layers, { size: 11 }), /* @__PURE__ */ React75.createElement("span", null, col?.header ?? col?.headerName ?? gField), !disableRowGrouping && /* @__PURE__ */ React75.createElement(
5173
+ "button",
5174
+ {
5175
+ className: "dg-group-chip-remove",
5176
+ onClick: () => removeFromGrouping(gField),
5177
+ title: `Remove grouping by ${col?.header ?? gField}`
5178
+ },
5179
+ /* @__PURE__ */ React75.createElement(X2, { size: 10 })
5180
+ ));
5181
+ })), /* @__PURE__ */ React75.createElement("div", { className: `dg-table-wrap${filteredData.length === 0 && !loading ? " dg-table-wrap--empty" : ""} ${tOpts.hideHeader ? "rm-top-border" : ""} ${tOpts.hideFooter ? "rm-bottom-border" : ""}` }, loading && /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-overlay" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-loading-spinner" })), /* @__PURE__ */ React75.createElement("table", { className: "dg-table" }, /* @__PURE__ */ React75.createElement("thead", null, /* @__PURE__ */ React75.createElement("tr", null, visibleColumns.map((col, idx) => {
4986
5182
  const colField = String(col.field);
4987
- const width = columnWidths[colField] || 200;
5183
+ const colNativeWidth = col.width ? typeof col.width === "number" ? col.width : parseInt(String(col.width)) : 200;
5184
+ const width = columnWidths[colField] || colNativeWidth;
4988
5185
  const leftOffset = getLeftOffset(col, idx);
4989
5186
  const rightOffset = getRightOffset(col, idx);
4990
5187
  const isSorted = sortField === col.field;
@@ -5035,79 +5232,150 @@ function DataGrid({
5035
5232
  }
5036
5233
  )))
5037
5234
  );
5038
- }), 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) => {
5039
- const colField = String(col.field);
5040
- const width = columnWidths[colField] || 200;
5041
- const leftOffset = getLeftOffset(col, idx);
5042
- const rightOffset = getRightOffset(col, idx);
5043
- return /* @__PURE__ */ React75.createElement(
5044
- "td",
5045
- {
5046
- key: `${item.id}-${colField}`,
5047
- className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""}${col.editable ? " dg-td--editable" : ""} ${col.cellClassName || ""}`,
5048
- style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
5049
- onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] }),
5050
- onClick: col.editable ? () => {
5051
- const field = String(col.field);
5052
- const rawValue = item[col.field || ""];
5053
- const value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
5054
- setEditingCell({ rowId: item.id, field, value });
5055
- } : void 0
5056
- },
5057
- (() => {
5058
- const field = String(col.field);
5059
- const rawValue = item[col.field || ""];
5060
- let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
5061
- if (col.editable && editingCell?.rowId === item.id && editingCell?.field === field) {
5062
- const inputType = col.type === "number" ? "number" : col.type === "date" ? "date" : "text";
5063
- const commit = (finalValue) => {
5064
- setEditingCell(null);
5065
- col.onEnter?.({ value: finalValue, row: item, field });
5066
- };
5067
- return /* @__PURE__ */ React75.createElement(
5068
- "input",
5235
+ }), actions && /* @__PURE__ */ React75.createElement("th", { style: { width: 0, padding: 0 } }))), /* @__PURE__ */ React75.createElement("tbody", null, displayRows.length > 0 && displayRows.map((entry) => {
5236
+ if (entry.kind === "group") {
5237
+ const isExpanded = expandedGroups.has(entry.id);
5238
+ const colDef = typeof groupingColDef === "function" ? groupingColDef(entry.field) : groupingColDef;
5239
+ const fieldLabel = resolvedColumns.find(
5240
+ (c) => String(c.field) === entry.field || String(c.key) === entry.field
5241
+ )?.header ?? entry.field;
5242
+ const totalCols = visibleColumns.length + (actions ? 1 : 0);
5243
+ return /* @__PURE__ */ React75.createElement("tr", { key: entry.id, className: "dg-group-row" }, /* @__PURE__ */ React75.createElement("td", { colSpan: totalCols, className: "dg-group-cell" }, /* @__PURE__ */ React75.createElement(
5244
+ "div",
5245
+ {
5246
+ className: "dg-group-cell-inner",
5247
+ style: { paddingLeft: entry.depth * 20 },
5248
+ onClick: () => toggleGroup(entry.id)
5249
+ },
5250
+ /* @__PURE__ */ React75.createElement("button", { className: "dg-group-toggle", onClick: (e) => {
5251
+ e.stopPropagation();
5252
+ toggleGroup(entry.id);
5253
+ } }, isExpanded ? /* @__PURE__ */ React75.createElement(ChevronDown, { size: 15 }) : /* @__PURE__ */ React75.createElement(ChevronRight, { size: 15 })),
5254
+ activeGroupingModel.length > 1 && /* @__PURE__ */ React75.createElement("span", { className: "dg-group-field-label" }, fieldLabel, ":"),
5255
+ colDef?.renderCell ? colDef.renderCell({ groupKey: entry.key, field: entry.field, depth: entry.depth, leafCount: entry.leafCount }) : /* @__PURE__ */ React75.createElement("span", { className: "dg-group-key" }, entry.key),
5256
+ !colDef?.hideDescendantCount && /* @__PURE__ */ React75.createElement("span", { className: "dg-group-count" }, entry.leafCount)
5257
+ )));
5258
+ }
5259
+ const item = entry.row;
5260
+ const rowDepth = entry.depth;
5261
+ return /* @__PURE__ */ React75.createElement("tr", { key: item.id, className: "dg-tbody-row", onDoubleClick: () => onRowDoubleClick?.(item) }, visibleColumns.map((col, idx) => {
5262
+ const colField = String(col.field);
5263
+ if (colField === "__tree__") {
5264
+ const treeColWidth = columnWidths["__tree__"] || 44;
5265
+ const isExpanded = treeExpandedRows.has(item.id);
5266
+ return /* @__PURE__ */ React75.createElement(
5267
+ "td",
5268
+ {
5269
+ key: `${item.id}-__tree__`,
5270
+ className: "dg-tree-cell",
5271
+ style: { width: treeColWidth, minWidth: treeColWidth, maxWidth: treeColWidth }
5272
+ },
5273
+ /* @__PURE__ */ React75.createElement("div", { className: "dg-tree-cell-inner", style: { paddingLeft: rowDepth * 20 } }, entry.hasChildren ? /* @__PURE__ */ React75.createElement(
5274
+ "button",
5069
5275
  {
5070
- className: "dg-cell-editor",
5071
- type: inputType,
5072
- autoFocus: true,
5073
- defaultValue: editingCell.value ?? "",
5074
- onClick: (e) => e.stopPropagation(),
5075
- onKeyDown: (e) => {
5076
- if (e.key === "Enter") commit(e.target.value);
5077
- if (e.key === "Escape") setEditingCell(null);
5078
- },
5079
- onBlur: (e) => {
5080
- const finalValue = e.target.value;
5081
- setEditingCell(null);
5082
- col.onBlur?.({ value: finalValue, row: item, field });
5276
+ className: "dg-group-toggle",
5277
+ onClick: (e) => {
5278
+ e.stopPropagation();
5279
+ toggleTreeRow(item.id);
5083
5280
  }
5084
- }
5085
- );
5086
- }
5087
- const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
5088
- if (col.renderCell) {
5089
- return col.renderCell({ value, row: item, field });
5090
- }
5091
- if (col.render) {
5092
- return col.render(value, item);
5281
+ },
5282
+ isExpanded ? /* @__PURE__ */ React75.createElement(ChevronDown, { size: 15 }) : /* @__PURE__ */ React75.createElement(ChevronRight, { size: 15 })
5283
+ ) : /* @__PURE__ */ React75.createElement("span", { style: { display: "inline-block", width: 22 } }))
5284
+ );
5285
+ }
5286
+ if (colField === "__group__" || colField.startsWith("__group_")) {
5287
+ const colDef = typeof groupingColDef === "function" ? groupingColDef(colField) : groupingColDef;
5288
+ const leafField = colDef?.leafField;
5289
+ let leafContent = null;
5290
+ if (leafField) {
5291
+ const leafCol = resolvedColumns.find((c) => String(c.field) === leafField || String(c.key) === leafField);
5292
+ if (leafCol) {
5293
+ const raw = item[String(leafCol.field)];
5294
+ let val = leafCol.valueGetter ? leafCol.valueGetter({ value: raw, row: item, field: leafField }) : raw;
5295
+ if (leafCol.valueFormatter) val = leafCol.valueFormatter({ value: val, row: item, field: leafField });
5296
+ if (leafCol.renderCell) leafContent = leafCol.renderCell({ value: val, row: item, field: leafField });
5297
+ else leafContent = val == null ? "" : String(val);
5298
+ }
5093
5299
  }
5094
- return String(formattedValue ?? "");
5095
- })()
5096
- );
5097
- }), actions && /* @__PURE__ */ React75.createElement("td", { className: "dg-row-actions-cell" }, (() => {
5098
- const resolvedActions = typeof actions === "function" ? actions(item) : actions;
5099
- const visibleActions = resolvedActions.filter((a) => !a.show || a.show(item));
5100
- if (visibleActions.length === 0) return null;
5101
- return /* @__PURE__ */ React75.createElement("div", { className: "dg-row-actions" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-action-group" }, visibleActions.map((action, i) => /* @__PURE__ */ React75.createElement(Tooltip, { key: i, title: action.label, placement: "top" }, /* @__PURE__ */ React75.createElement(
5102
- "button",
5103
- {
5104
- className: "dg-row-action-btn",
5105
- style: { color: action.color || "var(--text-secondary)" },
5106
- onClick: () => action.onClick(item)
5107
- },
5108
- action.icon
5109
- )))));
5110
- })()))))), 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"))), pagination && /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-page-info" }, /* @__PURE__ */ React75.createElement(Tooltip, { title: "Export CSV", placement: "top" }, /* @__PURE__ */ React75.createElement("button", { className: "dg-icon-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }))), /* @__PURE__ */ React75.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ React75.createElement("span", null, "Rows per page:"), /* @__PURE__ */ React75.createElement(
5300
+ const groupColWidth = columnWidths[colField] || 200;
5301
+ return /* @__PURE__ */ React75.createElement(
5302
+ "td",
5303
+ {
5304
+ key: `${item.id}-${colField}`,
5305
+ className: "dg-group-leaf-cell",
5306
+ style: { width: groupColWidth, minWidth: groupColWidth, maxWidth: groupColWidth, paddingLeft: rowDepth * 20 + 32 }
5307
+ },
5308
+ leafContent
5309
+ );
5310
+ }
5311
+ const width = columnWidths[colField] || 200;
5312
+ const leftOffset = getLeftOffset(col, idx);
5313
+ const rightOffset = getRightOffset(col, idx);
5314
+ return /* @__PURE__ */ React75.createElement(
5315
+ "td",
5316
+ {
5317
+ key: `${item.id}-${colField}`,
5318
+ className: `dg-td${col.pinned === "left" ? " pinned-left" : col.pinned === "right" ? " pinned-right" : ""}${col.editable ? " dg-td--editable" : ""} ${col.cellClassName || ""}`,
5319
+ style: { width, minWidth: width, maxWidth: width, left: leftOffset, right: rightOffset, flex: col.flex },
5320
+ onDoubleClick: () => onCellDoubleClick?.({ row: item, field: colField, value: item[col.field || ""] }),
5321
+ onClick: col.editable ? () => {
5322
+ const field = String(col.field);
5323
+ const rawValue = item[col.field || ""];
5324
+ const value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
5325
+ setEditingCell({ rowId: item.id, field, value });
5326
+ } : void 0
5327
+ },
5328
+ (() => {
5329
+ const field = String(col.field);
5330
+ const rawValue = item[col.field || ""];
5331
+ let value = col.valueGetter ? col.valueGetter({ value: rawValue, row: item, field }) : rawValue;
5332
+ if (col.editable && editingCell?.rowId === item.id && editingCell?.field === field) {
5333
+ const inputType = col.type === "number" ? "number" : col.type === "date" ? "date" : "text";
5334
+ const commit = (finalValue) => {
5335
+ setEditingCell(null);
5336
+ col.onEnter?.({ value: finalValue, row: item, field });
5337
+ };
5338
+ return /* @__PURE__ */ React75.createElement(
5339
+ "input",
5340
+ {
5341
+ className: "dg-cell-editor",
5342
+ type: inputType,
5343
+ autoFocus: true,
5344
+ defaultValue: editingCell.value ?? "",
5345
+ onClick: (e) => e.stopPropagation(),
5346
+ onKeyDown: (e) => {
5347
+ if (e.key === "Enter") commit(e.target.value);
5348
+ if (e.key === "Escape") setEditingCell(null);
5349
+ },
5350
+ onBlur: (e) => {
5351
+ const finalValue = e.target.value;
5352
+ setEditingCell(null);
5353
+ col.onBlur?.({ value: finalValue, row: item, field });
5354
+ }
5355
+ }
5356
+ );
5357
+ }
5358
+ const formattedValue = col.valueFormatter ? col.valueFormatter({ value, row: item, field }) : value;
5359
+ if (col.renderCell) return col.renderCell({ value, row: item, field });
5360
+ if (col.render) return col.render(value, item);
5361
+ return String(formattedValue ?? "");
5362
+ })()
5363
+ );
5364
+ }), actions && /* @__PURE__ */ React75.createElement("td", { className: "dg-row-actions-cell" }, (() => {
5365
+ const resolvedActions = typeof actions === "function" ? actions(item) : actions;
5366
+ const visibleActions = resolvedActions.filter((a) => !a.show || a.show(item));
5367
+ if (visibleActions.length === 0) return null;
5368
+ return /* @__PURE__ */ React75.createElement("div", { className: "dg-row-actions" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-action-group" }, visibleActions.map((action, i) => /* @__PURE__ */ React75.createElement(Tooltip, { key: i, title: action.label, placement: "top" }, /* @__PURE__ */ React75.createElement(
5369
+ "button",
5370
+ {
5371
+ className: "dg-row-action-btn",
5372
+ style: { color: action.color || "var(--text-secondary)" },
5373
+ onClick: () => action.onClick(item)
5374
+ },
5375
+ action.icon
5376
+ )))));
5377
+ })()));
5378
+ }))), filteredData.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"))), customFooter ? /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination dg-pagination--custom" }, customFooter) : pagination && !tOpts.hideFooter && /* @__PURE__ */ React75.createElement("div", { className: "dg-pagination" }, /* @__PURE__ */ React75.createElement("div", { className: "dg-page-info" }, !tOpts.hideBottomExport && !tOpts.hideExport && /* @__PURE__ */ React75.createElement(Tooltip, { title: "Export CSV", placement: "top" }, /* @__PURE__ */ React75.createElement("button", { className: "dg-icon-btn", onClick: handleExport }, /* @__PURE__ */ React75.createElement(Download, { size: 14 }))), /* @__PURE__ */ React75.createElement("div", { className: "dg-per-page" }, /* @__PURE__ */ React75.createElement("span", null, "Rows per page:"), /* @__PURE__ */ React75.createElement(
5111
5379
  FilterSelect,
5112
5380
  {
5113
5381
  placement: "top",
@@ -5148,6 +5416,17 @@ function DataGrid({
5148
5416
  setShowAdvancedFilter(true);
5149
5417
  setActiveMenu(null);
5150
5418
  } }, /* @__PURE__ */ React75.createElement(Filter, { size: 14 }), " Filter\u2026"),
5419
+ !disableRowGrouping && activeMenuCol?.groupable !== false && (() => {
5420
+ const gField = String(activeMenuCol?.field ?? "");
5421
+ const isGrouped = activeGroupingModel.includes(gField);
5422
+ return isGrouped ? /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
5423
+ removeFromGrouping(gField);
5424
+ setActiveMenu(null);
5425
+ } }, /* @__PURE__ */ React75.createElement(Layers, { size: 14 }), " Ungroup") : /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
5426
+ addToGrouping(gField);
5427
+ setActiveMenu(null);
5428
+ } }, /* @__PURE__ */ React75.createElement(Layers, { size: 14 }), " Group by");
5429
+ })(),
5151
5430
  /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => toggleHide(activeMenu) }, /* @__PURE__ */ React75.createElement(EyeOff, { size: 14 }), " Hide column"),
5152
5431
  /* @__PURE__ */ React75.createElement("button", { className: "dg-menu-item", onClick: () => {
5153
5432
  setShowManageColumns(true);
@@ -8979,21 +9258,24 @@ import React106, {
8979
9258
  } from "react";
8980
9259
  import ReactDOM10 from "react-dom";
8981
9260
  import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2, X as X3, Search as Search2, Check, Minus } from "lucide-react";
9261
+ function nodeId(node) {
9262
+ return node.id ?? node._id;
9263
+ }
8982
9264
  function collectDescendants(node) {
8983
- const ids = [String(node.id)];
9265
+ const ids = [String(nodeId(node))];
8984
9266
  node.children?.forEach((c) => ids.push(...collectDescendants(c)));
8985
9267
  return ids;
8986
9268
  }
8987
9269
  function findNodeById(nodes, id) {
8988
9270
  for (const node of nodes) {
8989
- if (String(node.id) === id) return node;
9271
+ if (String(nodeId(node)) === id) return node;
8990
9272
  const found = findNodeById(node.children ?? [], id);
8991
9273
  if (found) return found;
8992
9274
  }
8993
9275
  return null;
8994
9276
  }
8995
9277
  function getNodeState(node, selected) {
8996
- if (selected.has(String(node.id))) return "checked";
9278
+ if (selected.has(String(nodeId(node)))) return "checked";
8997
9279
  if (!node.children?.length) return "unchecked";
8998
9280
  const states = node.children.map((c) => getNodeState(c, selected));
8999
9281
  if (states.every((s2) => s2 === "checked")) return "checked";
@@ -9015,7 +9297,7 @@ function getTopLevelSelected(nodes, selected) {
9015
9297
  function getAllSelected(nodes, selected) {
9016
9298
  const result = [];
9017
9299
  for (const node of nodes) {
9018
- if (selected.has(String(node.id))) result.push(node);
9300
+ if (selected.has(String(nodeId(node)))) result.push(node);
9019
9301
  if (node.children?.length) result.push(...getAllSelected(node.children, selected));
9020
9302
  }
9021
9303
  return result;
@@ -9053,10 +9335,10 @@ function TreeNodeItem({
9053
9335
  onSelect,
9054
9336
  isFiltering
9055
9337
  }) {
9056
- const nodeId = String(node.id);
9338
+ const nid = String(nodeId(node));
9057
9339
  const hasChildren = !!node.children?.length;
9058
- const isExpanded = isFiltering || expanded.has(nodeId);
9059
- const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nodeId) ? "checked" : "unchecked";
9340
+ const isExpanded = isFiltering || expanded.has(nid);
9341
+ const state = allowChildSelection ? getNodeState(node, selected) : selected.has(nid) ? "checked" : "unchecked";
9060
9342
  return /* @__PURE__ */ React106.createElement("div", { className: "rf-tsn" }, /* @__PURE__ */ React106.createElement(
9061
9343
  "div",
9062
9344
  {
@@ -9071,7 +9353,7 @@ function TreeNodeItem({
9071
9353
  className: "rf-tsn__expand",
9072
9354
  onClick: (e) => {
9073
9355
  e.stopPropagation();
9074
- onToggleExpand(nodeId);
9356
+ onToggleExpand(nid);
9075
9357
  }
9076
9358
  },
9077
9359
  isExpanded ? /* @__PURE__ */ React106.createElement(ChevronDown2, { size: 14 }) : /* @__PURE__ */ React106.createElement(ChevronRight2, { size: 14 })
@@ -9220,7 +9502,7 @@ function TreeSelect({
9220
9502
  };
9221
9503
  }, [open, computePosition3]);
9222
9504
  const handleSelect = (node) => {
9223
- const nodeId = String(node.id);
9505
+ const nid = String(nodeId(node));
9224
9506
  if (isMultiple) {
9225
9507
  const newSet = new Set(selectedSet);
9226
9508
  if (allowChildSelection) {
@@ -9234,21 +9516,21 @@ function TreeSelect({
9234
9516
  onNodeSelect?.({ node });
9235
9517
  }
9236
9518
  } else {
9237
- if (newSet.has(nodeId)) {
9238
- newSet.delete(nodeId);
9519
+ if (newSet.has(nid)) {
9520
+ newSet.delete(nid);
9239
9521
  onNodeUnselect?.({ node });
9240
9522
  } else {
9241
- newSet.add(nodeId);
9523
+ newSet.add(nid);
9242
9524
  onNodeSelect?.({ node });
9243
9525
  }
9244
9526
  }
9245
- onChange?.({ value: setToRecord(newSet) });
9527
+ onChange?.({ value: setToRecord(newSet), node });
9246
9528
  } else {
9247
- if (selectedSet.has(nodeId)) {
9248
- onChange?.({ value: null });
9529
+ if (selectedSet.has(nid)) {
9530
+ onChange?.({ value: null, node: null });
9249
9531
  onNodeUnselect?.({ node });
9250
9532
  } else {
9251
- onChange?.({ value: node.id });
9533
+ onChange?.({ value: nodeId(node), node });
9252
9534
  onNodeSelect?.({ node });
9253
9535
  closeDropdown();
9254
9536
  }
@@ -9263,7 +9545,7 @@ function TreeSelect({
9263
9545
  };
9264
9546
  const handleClear = (e) => {
9265
9547
  e.stopPropagation();
9266
- onChange?.({ value: isMultiple ? {} : null });
9548
+ onChange?.({ value: isMultiple ? {} : null, node: null });
9267
9549
  };
9268
9550
  const handleRemoveTag = (e, node) => {
9269
9551
  e.stopPropagation();
@@ -9688,10 +9970,13 @@ function SmartSelect({
9688
9970
  return [...selected, ...filteredUnselected];
9689
9971
  }
9690
9972
  if (value != null) {
9973
+ const selectedKey = getValue(value);
9691
9974
  const selectedLabel = getOptionLabel(value);
9692
- if (inputValue2 === selectedLabel) {
9693
- const selectedKey = getValue(value);
9975
+ const inOpts = opts.some((o) => getValue(o) === selectedKey);
9976
+ const selectedFallback = inOpts ? [] : [value];
9977
+ if (!inputValue2 || inputValue2 === selectedLabel) {
9694
9978
  return [
9979
+ ...selectedFallback,
9695
9980
  ...opts.filter((o) => getValue(o) === selectedKey),
9696
9981
  ...opts.filter((o) => getValue(o) !== selectedKey)
9697
9982
  ];