@dreamtree-org/twreact-ui 1.0.72 → 1.0.73

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.esm.js CHANGED
@@ -4126,9 +4126,10 @@ var Table = function Table(_ref) {
4126
4126
  useEffect(function () {
4127
4127
  if (typeof pageNumber === "number" && pageNumber !== currentPage) {
4128
4128
  setCurrentPage(pageNumber);
4129
- onPageChange === null || onPageChange === void 0 || onPageChange(pageNumber);
4129
+ // Note: onPageChange is intentionally not called here to avoid loops
4130
+ // Parent should handle page changes via controlled component pattern
4130
4131
  }
4131
- }, [pageNumber, currentPage, onPageChange]);
4132
+ }, [pageNumber, currentPage]);
4132
4133
  useEffect(function () {
4133
4134
  setLimit(pageSize);
4134
4135
  }, [pageSize]);
@@ -4194,6 +4195,12 @@ var Table = function Table(_ref) {
4194
4195
  });
4195
4196
  return map;
4196
4197
  }, [filteredData]);
4198
+
4199
+ // Wrapper for setCurrentPage that also calls onPageChange
4200
+ var handlePageChange = useCallback(function (newPage) {
4201
+ setCurrentPage(newPage);
4202
+ onPageChange === null || onPageChange === void 0 || onPageChange(newPage);
4203
+ }, [onPageChange]);
4197
4204
  var toggleColumnVisibility = useCallback(function (key) {
4198
4205
  setColumnsState(function (prev) {
4199
4206
  return prev.map(function (c) {
@@ -4202,8 +4209,8 @@ var Table = function Table(_ref) {
4202
4209
  }) : c;
4203
4210
  });
4204
4211
  });
4205
- setCurrentPage(1);
4206
- }, []);
4212
+ handlePageChange(1);
4213
+ }, [handlePageChange]);
4207
4214
 
4208
4215
  // Handle actions
4209
4216
  var handleOnAction = useCallback(function (action, row) {
@@ -4237,13 +4244,26 @@ var Table = function Table(_ref) {
4237
4244
  // Filtering
4238
4245
  var filteredData = useMemo(function () {
4239
4246
  if (serverSide || !filterable || !Object.keys(filters).length) return sortedData;
4240
- var q = (filters.global || "").toLowerCase();
4241
4247
  return sortedData.filter(function (row) {
4242
- return Object.values(row || {}).some(function (v) {
4243
- return String(v).toLowerCase().includes(q);
4248
+ // Apply global search filter if present
4249
+ if (filters.global) {
4250
+ var q = filters.global.toLowerCase();
4251
+ var matchesGlobal = Object.values(row || {}).some(function (v) {
4252
+ return String(v).toLowerCase().includes(q);
4253
+ });
4254
+ if (!matchesGlobal) return false;
4255
+ }
4256
+
4257
+ // Apply column-specific filters
4258
+ return visibleColumns.every(function (column) {
4259
+ var columnFilter = filters[column.key];
4260
+ if (!columnFilter) return true; // No filter for this column
4261
+
4262
+ var cellValue = row === null || row === void 0 ? void 0 : row[column.key];
4263
+ return String(cellValue || "").toLowerCase().includes(columnFilter.toLowerCase());
4244
4264
  });
4245
4265
  });
4246
- }, [sortedData, filters, filterable, serverSide]);
4266
+ }, [sortedData, filters, filterable, serverSide, visibleColumns]);
4247
4267
 
4248
4268
  // Pagination indices - memoized
4249
4269
  var _useMemo = useMemo(function () {
@@ -4330,8 +4350,8 @@ var Table = function Table(_ref) {
4330
4350
  onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
4331
4351
  return newFilters;
4332
4352
  });
4333
- setCurrentPage(1);
4334
- }, [onFilter, onFilterChange]);
4353
+ handlePageChange(1);
4354
+ }, [onFilter, onFilterChange, handlePageChange]);
4335
4355
  var renderCell = useCallback(function (column, row, globalIndex) {
4336
4356
  if (column.render) return column.render(row, globalIndex);
4337
4357
  return row === null || row === void 0 ? void 0 : row[column.key];
@@ -4360,9 +4380,9 @@ var Table = function Table(_ref) {
4360
4380
  setActionAnchor(null);
4361
4381
  };
4362
4382
  var onScrollResize = function onScrollResize() {
4363
- setOpenActionKey(function (k) {
4364
- return k ? k : null;
4365
- });
4383
+ // Close menu on scroll/resize to prevent positioning issues
4384
+ setOpenActionKey(null);
4385
+ setActionAnchor(null);
4366
4386
  };
4367
4387
  window.addEventListener("click", onDocClick);
4368
4388
  window.addEventListener("scroll", onScrollResize, true);
@@ -4379,6 +4399,7 @@ var Table = function Table(_ref) {
4379
4399
  var isFetchingRef = useRef(false);
4380
4400
  var isMountedRef = useRef(true);
4381
4401
  var onFetchRef = useRef(onFetch);
4402
+ var activeFetchIdRef = useRef(0);
4382
4403
 
4383
4404
  // Keep ref in sync with onFetch
4384
4405
  useEffect(function () {
@@ -4394,7 +4415,7 @@ var Table = function Table(_ref) {
4394
4415
  };
4395
4416
  }, []);
4396
4417
 
4397
- // Serialize fetch params for comparison
4418
+ // Serialize fetch params for comparison - serialize filters to avoid object reference issues
4398
4419
  var fetchParams = useMemo(function () {
4399
4420
  return {
4400
4421
  filters: filters,
@@ -4416,36 +4437,59 @@ var Table = function Table(_ref) {
4416
4437
  if (!isFetchingRef.current && prevFetchParamsRef.current !== fetchParamsString) {
4417
4438
  prevFetchParamsRef.current = fetchParamsString;
4418
4439
  isFetchingRef.current = true;
4419
- currentOnFetch({
4420
- setData: function setData(rows) {
4421
- // Only update if component is still mounted
4422
- if (isMountedRef.current && isFetchingRef.current) {
4423
- setTableData(Array.isArray(rows) ? rows : []);
4424
- isFetchingRef.current = false;
4440
+
4441
+ // Track fetch ID to prevent race conditions
4442
+ var fetchId = Date.now();
4443
+ activeFetchIdRef.current = fetchId;
4444
+ try {
4445
+ var result = currentOnFetch({
4446
+ setData: function setData(rows) {
4447
+ // Only update if component is still mounted and this is the active fetch
4448
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4449
+ setTableData(Array.isArray(rows) ? rows : []);
4450
+ // Don't set isFetchingRef to false here - let setLoading handle it
4451
+ }
4452
+ },
4453
+ setLoading: function setLoading(loading) {
4454
+ // Only update if component is still mounted and this is the active fetch
4455
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4456
+ _setLoading(loading);
4457
+ if (!loading) {
4458
+ isFetchingRef.current = false;
4459
+ }
4460
+ }
4461
+ },
4462
+ filters: fetchParams.filters,
4463
+ page: fetchParams.page,
4464
+ limit: fetchParams.limit,
4465
+ sort: {
4466
+ key: fetchParams.sortKey,
4467
+ direction: fetchParams.sortDirection
4425
4468
  }
4426
- },
4427
- setLoading: function setLoading(loading) {
4428
- // Only update if component is still mounted
4429
- if (isMountedRef.current) {
4430
- _setLoading(loading);
4431
- if (!loading && isFetchingRef.current) {
4469
+ });
4470
+
4471
+ // Handle promise if onFetch returns one
4472
+ if (result && typeof result.then === "function") {
4473
+ result["catch"](function (error) {
4474
+ console.error("Table onFetch error:", error);
4475
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4476
+ _setLoading(false);
4432
4477
  isFetchingRef.current = false;
4433
4478
  }
4434
- }
4435
- },
4436
- filters: fetchParams.filters,
4437
- page: fetchParams.page,
4438
- limit: fetchParams.limit,
4439
- sort: {
4440
- key: fetchParams.sortKey,
4441
- direction: fetchParams.sortDirection
4479
+ });
4442
4480
  }
4443
- });
4481
+ } catch (error) {
4482
+ console.error("Table onFetch error:", error);
4483
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4484
+ _setLoading(false);
4485
+ isFetchingRef.current = false;
4486
+ }
4487
+ }
4444
4488
  }
4445
4489
  } else if (!serverSide && Array.isArray(data)) {
4446
4490
  setTableData(data);
4447
4491
  }
4448
- }, [serverSide, data, fetchParamsString, fetchParams]);
4492
+ }, [serverSide, data, fetchParamsString]);
4449
4493
 
4450
4494
  // Global search
4451
4495
  useEffect(function () {
@@ -4464,9 +4508,9 @@ var Table = function Table(_ref) {
4464
4508
  var parsed = Number(nextLimit);
4465
4509
  if (!Number.isFinite(parsed) || parsed <= 0) return;
4466
4510
  setLimit(parsed);
4467
- setCurrentPage(1);
4511
+ handlePageChange(1);
4468
4512
  onLimitChange === null || onLimitChange === void 0 || onLimitChange(parsed);
4469
- }, [onLimitChange]);
4513
+ }, [onLimitChange, handlePageChange]);
4470
4514
 
4471
4515
  // Memoize limit options
4472
4516
  var limitOptionsMemo = useMemo(function () {
@@ -4503,9 +4547,9 @@ var Table = function Table(_ref) {
4503
4547
  var _getRowMetadata = getRowMetadata(row, rowIndexInPage),
4504
4548
  globalIndex = _getRowMetadata.globalIndex,
4505
4549
  key = _getRowMetadata.key,
4506
- actionCellKey = _getRowMetadata.actionCellKey;
4507
- _getRowMetadata.extraRowClass;
4508
- var stripeBg = _getRowMetadata.stripeBg;
4550
+ actionCellKey = _getRowMetadata.actionCellKey,
4551
+ extraRowClass = _getRowMetadata.extraRowClass,
4552
+ stripeBg = _getRowMetadata.stripeBg;
4509
4553
  return /*#__PURE__*/React__default.createElement("div", {
4510
4554
  key: key,
4511
4555
  style: stripeBg ? {
@@ -4515,7 +4559,7 @@ var Table = function Table(_ref) {
4515
4559
  "cursor-pointer": !!onRowClick,
4516
4560
  "bg-primary-50 border-primary-200": selectedRows.has(key),
4517
4561
  "hover:shadow-md": !selectedRows.has(key)
4518
- }, safeExtraRowClass),
4562
+ }, extraRowClass),
4519
4563
  onClick: function onClick() {
4520
4564
  return onRowClick === null || onRowClick === void 0 ? void 0 : onRowClick(row, globalIndex);
4521
4565
  }
@@ -4592,10 +4636,10 @@ var Table = function Table(_ref) {
4592
4636
  row: row,
4593
4637
  index: globalIndex
4594
4638
  })));
4595
- }, [getRowMetadata, hasDetails, selectable, showSerial, withAction, expandedRows, selectedRows, onRowClick, visibleColumns, renderCell, cellClass, DetailsComponent, actionsToUse, actionAnchor, openActionKey, handleOnAction, actionMenuRef]);
4639
+ }, [getRowMetadata, hasDetails, selectable, showSerial, withAction, expandedRows, selectedRows, onRowClick, visibleColumns, renderCell, cellClass, DetailsComponent, actionsToUse, actionAnchor, openActionKey, handleOnAction, actionMenuRef, toggleActions, toggleExpandRow, handleSelectRow]);
4596
4640
 
4597
4641
  // Render mobile filters
4598
- var renderMobileFilters = function renderMobileFilters() {
4642
+ var renderMobileFilters = useCallback(function () {
4599
4643
  return /*#__PURE__*/React__default.createElement("div", {
4600
4644
  className: "mb-4 p-3 bg-gray-50 rounded-lg"
4601
4645
  }, /*#__PURE__*/React__default.createElement("div", {
@@ -4637,7 +4681,7 @@ var Table = function Table(_ref) {
4637
4681
  }
4638
4682
  }));
4639
4683
  })));
4640
- };
4684
+ }, [showMobileFilters, globalSearch, searchInput, onGlobalKeyDown, filterable, visibleColumns, filters, handleFilter, setShowMobileFilters, setSearchInput]);
4641
4685
 
4642
4686
  // Render
4643
4687
  return /*#__PURE__*/React__default.createElement("div", {
@@ -4680,9 +4724,7 @@ var Table = function Table(_ref) {
4680
4724
  className: "rounded-lg md:rounded-md border border-gray-300 p-2 disabled:opacity-50 hover:bg-gray-50",
4681
4725
  disabled: currentPage === 1,
4682
4726
  onClick: function onClick() {
4683
- return setCurrentPage(function (p) {
4684
- return Math.max(1, p - 1);
4685
- });
4727
+ return handlePageChange(Math.max(1, currentPage - 1));
4686
4728
  },
4687
4729
  "aria-label": "Previous page"
4688
4730
  }, /*#__PURE__*/React__default.createElement(ChevronLeft, {
@@ -4691,9 +4733,7 @@ var Table = function Table(_ref) {
4691
4733
  className: "rounded-lg md:rounded-md border border-gray-300 p-2 disabled:opacity-50 hover:bg-gray-50",
4692
4734
  disabled: currentPage === totalPages,
4693
4735
  onClick: function onClick() {
4694
- return setCurrentPage(function (p) {
4695
- return Math.min(totalPages, p + 1);
4696
- });
4736
+ return handlePageChange(Math.min(totalPages, currentPage + 1));
4697
4737
  },
4698
4738
  "aria-label": "Next page"
4699
4739
  }, /*#__PURE__*/React__default.createElement(ChevronRight, {
@@ -4950,9 +4990,7 @@ var Table = function Table(_ref) {
4950
4990
  className: "rounded-lg md:rounded-md border border-gray-300 px-4 py-2 text-sm disabled:opacity-50 hover:bg-gray-50",
4951
4991
  disabled: currentPage === 1,
4952
4992
  onClick: function onClick() {
4953
- return setCurrentPage(function (p) {
4954
- return Math.max(1, p - 1);
4955
- });
4993
+ return handlePageChange(Math.max(1, currentPage - 1));
4956
4994
  }
4957
4995
  }, "Previous"), /*#__PURE__*/React__default.createElement("div", {
4958
4996
  className: "flex items-center gap-1"
@@ -4964,16 +5002,14 @@ var Table = function Table(_ref) {
4964
5002
  "border border-gray-300 hover:bg-gray-50": pageNum !== currentPage
4965
5003
  }),
4966
5004
  onClick: function onClick() {
4967
- return setCurrentPage(pageNum);
5005
+ return handlePageChange(pageNum);
4968
5006
  }
4969
5007
  }, pageNum);
4970
5008
  })), /*#__PURE__*/React__default.createElement("button", {
4971
5009
  className: "rounded-lg md:rounded-md border border-gray-300 px-4 py-2 text-sm disabled:opacity-50 hover:bg-gray-50",
4972
5010
  disabled: currentPage === totalPages,
4973
5011
  onClick: function onClick() {
4974
- return setCurrentPage(function (p) {
4975
- return Math.min(totalPages, p + 1);
4976
- });
5012
+ return handlePageChange(Math.min(totalPages, currentPage + 1));
4977
5013
  }
4978
5014
  }, "Next")))));
4979
5015
  };
@@ -5089,7 +5125,8 @@ function ActionMenuPortal(_ref2) {
5089
5125
  window.removeEventListener("scroll", onScrollOrResize, true);
5090
5126
  };
5091
5127
  // Recompute when anchor element changes or actions change (content height may change).
5092
- }, [anchorElem, actions, menuRef]);
5128
+ // Note: menuRef is a ref object and never changes, so it's safe to include
5129
+ }, [anchorElem, actions]);
5093
5130
  return /*#__PURE__*/createPortal(/*#__PURE__*/React__default.createElement("div", {
5094
5131
  ref: menuRef,
5095
5132
  style: {