@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.js CHANGED
@@ -4146,9 +4146,10 @@ var Table = function Table(_ref) {
4146
4146
  React.useEffect(function () {
4147
4147
  if (typeof pageNumber === "number" && pageNumber !== currentPage) {
4148
4148
  setCurrentPage(pageNumber);
4149
- onPageChange === null || onPageChange === void 0 || onPageChange(pageNumber);
4149
+ // Note: onPageChange is intentionally not called here to avoid loops
4150
+ // Parent should handle page changes via controlled component pattern
4150
4151
  }
4151
- }, [pageNumber, currentPage, onPageChange]);
4152
+ }, [pageNumber, currentPage]);
4152
4153
  React.useEffect(function () {
4153
4154
  setLimit(pageSize);
4154
4155
  }, [pageSize]);
@@ -4214,6 +4215,12 @@ var Table = function Table(_ref) {
4214
4215
  });
4215
4216
  return map;
4216
4217
  }, [filteredData]);
4218
+
4219
+ // Wrapper for setCurrentPage that also calls onPageChange
4220
+ var handlePageChange = React.useCallback(function (newPage) {
4221
+ setCurrentPage(newPage);
4222
+ onPageChange === null || onPageChange === void 0 || onPageChange(newPage);
4223
+ }, [onPageChange]);
4217
4224
  var toggleColumnVisibility = React.useCallback(function (key) {
4218
4225
  setColumnsState(function (prev) {
4219
4226
  return prev.map(function (c) {
@@ -4222,8 +4229,8 @@ var Table = function Table(_ref) {
4222
4229
  }) : c;
4223
4230
  });
4224
4231
  });
4225
- setCurrentPage(1);
4226
- }, []);
4232
+ handlePageChange(1);
4233
+ }, [handlePageChange]);
4227
4234
 
4228
4235
  // Handle actions
4229
4236
  var handleOnAction = React.useCallback(function (action, row) {
@@ -4257,13 +4264,26 @@ var Table = function Table(_ref) {
4257
4264
  // Filtering
4258
4265
  var filteredData = React.useMemo(function () {
4259
4266
  if (serverSide || !filterable || !Object.keys(filters).length) return sortedData;
4260
- var q = (filters.global || "").toLowerCase();
4261
4267
  return sortedData.filter(function (row) {
4262
- return Object.values(row || {}).some(function (v) {
4263
- return String(v).toLowerCase().includes(q);
4268
+ // Apply global search filter if present
4269
+ if (filters.global) {
4270
+ var q = filters.global.toLowerCase();
4271
+ var matchesGlobal = Object.values(row || {}).some(function (v) {
4272
+ return String(v).toLowerCase().includes(q);
4273
+ });
4274
+ if (!matchesGlobal) return false;
4275
+ }
4276
+
4277
+ // Apply column-specific filters
4278
+ return visibleColumns.every(function (column) {
4279
+ var columnFilter = filters[column.key];
4280
+ if (!columnFilter) return true; // No filter for this column
4281
+
4282
+ var cellValue = row === null || row === void 0 ? void 0 : row[column.key];
4283
+ return String(cellValue || "").toLowerCase().includes(columnFilter.toLowerCase());
4264
4284
  });
4265
4285
  });
4266
- }, [sortedData, filters, filterable, serverSide]);
4286
+ }, [sortedData, filters, filterable, serverSide, visibleColumns]);
4267
4287
 
4268
4288
  // Pagination indices - memoized
4269
4289
  var _useMemo = React.useMemo(function () {
@@ -4350,8 +4370,8 @@ var Table = function Table(_ref) {
4350
4370
  onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
4351
4371
  return newFilters;
4352
4372
  });
4353
- setCurrentPage(1);
4354
- }, [onFilter, onFilterChange]);
4373
+ handlePageChange(1);
4374
+ }, [onFilter, onFilterChange, handlePageChange]);
4355
4375
  var renderCell = React.useCallback(function (column, row, globalIndex) {
4356
4376
  if (column.render) return column.render(row, globalIndex);
4357
4377
  return row === null || row === void 0 ? void 0 : row[column.key];
@@ -4380,9 +4400,9 @@ var Table = function Table(_ref) {
4380
4400
  setActionAnchor(null);
4381
4401
  };
4382
4402
  var onScrollResize = function onScrollResize() {
4383
- setOpenActionKey(function (k) {
4384
- return k ? k : null;
4385
- });
4403
+ // Close menu on scroll/resize to prevent positioning issues
4404
+ setOpenActionKey(null);
4405
+ setActionAnchor(null);
4386
4406
  };
4387
4407
  window.addEventListener("click", onDocClick);
4388
4408
  window.addEventListener("scroll", onScrollResize, true);
@@ -4399,6 +4419,7 @@ var Table = function Table(_ref) {
4399
4419
  var isFetchingRef = React.useRef(false);
4400
4420
  var isMountedRef = React.useRef(true);
4401
4421
  var onFetchRef = React.useRef(onFetch);
4422
+ var activeFetchIdRef = React.useRef(0);
4402
4423
 
4403
4424
  // Keep ref in sync with onFetch
4404
4425
  React.useEffect(function () {
@@ -4414,7 +4435,7 @@ var Table = function Table(_ref) {
4414
4435
  };
4415
4436
  }, []);
4416
4437
 
4417
- // Serialize fetch params for comparison
4438
+ // Serialize fetch params for comparison - serialize filters to avoid object reference issues
4418
4439
  var fetchParams = React.useMemo(function () {
4419
4440
  return {
4420
4441
  filters: filters,
@@ -4436,36 +4457,59 @@ var Table = function Table(_ref) {
4436
4457
  if (!isFetchingRef.current && prevFetchParamsRef.current !== fetchParamsString) {
4437
4458
  prevFetchParamsRef.current = fetchParamsString;
4438
4459
  isFetchingRef.current = true;
4439
- currentOnFetch({
4440
- setData: function setData(rows) {
4441
- // Only update if component is still mounted
4442
- if (isMountedRef.current && isFetchingRef.current) {
4443
- setTableData(Array.isArray(rows) ? rows : []);
4444
- isFetchingRef.current = false;
4460
+
4461
+ // Track fetch ID to prevent race conditions
4462
+ var fetchId = Date.now();
4463
+ activeFetchIdRef.current = fetchId;
4464
+ try {
4465
+ var result = currentOnFetch({
4466
+ setData: function setData(rows) {
4467
+ // Only update if component is still mounted and this is the active fetch
4468
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4469
+ setTableData(Array.isArray(rows) ? rows : []);
4470
+ // Don't set isFetchingRef to false here - let setLoading handle it
4471
+ }
4472
+ },
4473
+ setLoading: function setLoading(loading) {
4474
+ // Only update if component is still mounted and this is the active fetch
4475
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4476
+ _setLoading(loading);
4477
+ if (!loading) {
4478
+ isFetchingRef.current = false;
4479
+ }
4480
+ }
4481
+ },
4482
+ filters: fetchParams.filters,
4483
+ page: fetchParams.page,
4484
+ limit: fetchParams.limit,
4485
+ sort: {
4486
+ key: fetchParams.sortKey,
4487
+ direction: fetchParams.sortDirection
4445
4488
  }
4446
- },
4447
- setLoading: function setLoading(loading) {
4448
- // Only update if component is still mounted
4449
- if (isMountedRef.current) {
4450
- _setLoading(loading);
4451
- if (!loading && isFetchingRef.current) {
4489
+ });
4490
+
4491
+ // Handle promise if onFetch returns one
4492
+ if (result && typeof result.then === "function") {
4493
+ result["catch"](function (error) {
4494
+ console.error("Table onFetch error:", error);
4495
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4496
+ _setLoading(false);
4452
4497
  isFetchingRef.current = false;
4453
4498
  }
4454
- }
4455
- },
4456
- filters: fetchParams.filters,
4457
- page: fetchParams.page,
4458
- limit: fetchParams.limit,
4459
- sort: {
4460
- key: fetchParams.sortKey,
4461
- direction: fetchParams.sortDirection
4499
+ });
4462
4500
  }
4463
- });
4501
+ } catch (error) {
4502
+ console.error("Table onFetch error:", error);
4503
+ if (isMountedRef.current && activeFetchIdRef.current === fetchId) {
4504
+ _setLoading(false);
4505
+ isFetchingRef.current = false;
4506
+ }
4507
+ }
4464
4508
  }
4465
4509
  } else if (!serverSide && Array.isArray(data)) {
4466
4510
  setTableData(data);
4467
4511
  }
4468
- }, [serverSide, data, fetchParamsString, fetchParams]);
4512
+ }, [serverSide, data, fetchParamsString]);
4469
4513
 
4470
4514
  // Global search
4471
4515
  React.useEffect(function () {
@@ -4484,9 +4528,9 @@ var Table = function Table(_ref) {
4484
4528
  var parsed = Number(nextLimit);
4485
4529
  if (!Number.isFinite(parsed) || parsed <= 0) return;
4486
4530
  setLimit(parsed);
4487
- setCurrentPage(1);
4531
+ handlePageChange(1);
4488
4532
  onLimitChange === null || onLimitChange === void 0 || onLimitChange(parsed);
4489
- }, [onLimitChange]);
4533
+ }, [onLimitChange, handlePageChange]);
4490
4534
 
4491
4535
  // Memoize limit options
4492
4536
  var limitOptionsMemo = React.useMemo(function () {
@@ -4523,9 +4567,9 @@ var Table = function Table(_ref) {
4523
4567
  var _getRowMetadata = getRowMetadata(row, rowIndexInPage),
4524
4568
  globalIndex = _getRowMetadata.globalIndex,
4525
4569
  key = _getRowMetadata.key,
4526
- actionCellKey = _getRowMetadata.actionCellKey;
4527
- _getRowMetadata.extraRowClass;
4528
- var stripeBg = _getRowMetadata.stripeBg;
4570
+ actionCellKey = _getRowMetadata.actionCellKey,
4571
+ extraRowClass = _getRowMetadata.extraRowClass,
4572
+ stripeBg = _getRowMetadata.stripeBg;
4529
4573
  return /*#__PURE__*/React.createElement("div", {
4530
4574
  key: key,
4531
4575
  style: stripeBg ? {
@@ -4535,7 +4579,7 @@ var Table = function Table(_ref) {
4535
4579
  "cursor-pointer": !!onRowClick,
4536
4580
  "bg-primary-50 border-primary-200": selectedRows.has(key),
4537
4581
  "hover:shadow-md": !selectedRows.has(key)
4538
- }, safeExtraRowClass),
4582
+ }, extraRowClass),
4539
4583
  onClick: function onClick() {
4540
4584
  return onRowClick === null || onRowClick === void 0 ? void 0 : onRowClick(row, globalIndex);
4541
4585
  }
@@ -4612,10 +4656,10 @@ var Table = function Table(_ref) {
4612
4656
  row: row,
4613
4657
  index: globalIndex
4614
4658
  })));
4615
- }, [getRowMetadata, hasDetails, selectable, showSerial, withAction, expandedRows, selectedRows, onRowClick, visibleColumns, renderCell, cellClass, DetailsComponent, actionsToUse, actionAnchor, openActionKey, handleOnAction, actionMenuRef]);
4659
+ }, [getRowMetadata, hasDetails, selectable, showSerial, withAction, expandedRows, selectedRows, onRowClick, visibleColumns, renderCell, cellClass, DetailsComponent, actionsToUse, actionAnchor, openActionKey, handleOnAction, actionMenuRef, toggleActions, toggleExpandRow, handleSelectRow]);
4616
4660
 
4617
4661
  // Render mobile filters
4618
- var renderMobileFilters = function renderMobileFilters() {
4662
+ var renderMobileFilters = React.useCallback(function () {
4619
4663
  return /*#__PURE__*/React.createElement("div", {
4620
4664
  className: "mb-4 p-3 bg-gray-50 rounded-lg"
4621
4665
  }, /*#__PURE__*/React.createElement("div", {
@@ -4657,7 +4701,7 @@ var Table = function Table(_ref) {
4657
4701
  }
4658
4702
  }));
4659
4703
  })));
4660
- };
4704
+ }, [showMobileFilters, globalSearch, searchInput, onGlobalKeyDown, filterable, visibleColumns, filters, handleFilter, setShowMobileFilters, setSearchInput]);
4661
4705
 
4662
4706
  // Render
4663
4707
  return /*#__PURE__*/React.createElement("div", {
@@ -4700,9 +4744,7 @@ var Table = function Table(_ref) {
4700
4744
  className: "rounded-lg md:rounded-md border border-gray-300 p-2 disabled:opacity-50 hover:bg-gray-50",
4701
4745
  disabled: currentPage === 1,
4702
4746
  onClick: function onClick() {
4703
- return setCurrentPage(function (p) {
4704
- return Math.max(1, p - 1);
4705
- });
4747
+ return handlePageChange(Math.max(1, currentPage - 1));
4706
4748
  },
4707
4749
  "aria-label": "Previous page"
4708
4750
  }, /*#__PURE__*/React.createElement(ChevronLeft, {
@@ -4711,9 +4753,7 @@ var Table = function Table(_ref) {
4711
4753
  className: "rounded-lg md:rounded-md border border-gray-300 p-2 disabled:opacity-50 hover:bg-gray-50",
4712
4754
  disabled: currentPage === totalPages,
4713
4755
  onClick: function onClick() {
4714
- return setCurrentPage(function (p) {
4715
- return Math.min(totalPages, p + 1);
4716
- });
4756
+ return handlePageChange(Math.min(totalPages, currentPage + 1));
4717
4757
  },
4718
4758
  "aria-label": "Next page"
4719
4759
  }, /*#__PURE__*/React.createElement(ChevronRight, {
@@ -4970,9 +5010,7 @@ var Table = function Table(_ref) {
4970
5010
  className: "rounded-lg md:rounded-md border border-gray-300 px-4 py-2 text-sm disabled:opacity-50 hover:bg-gray-50",
4971
5011
  disabled: currentPage === 1,
4972
5012
  onClick: function onClick() {
4973
- return setCurrentPage(function (p) {
4974
- return Math.max(1, p - 1);
4975
- });
5013
+ return handlePageChange(Math.max(1, currentPage - 1));
4976
5014
  }
4977
5015
  }, "Previous"), /*#__PURE__*/React.createElement("div", {
4978
5016
  className: "flex items-center gap-1"
@@ -4984,16 +5022,14 @@ var Table = function Table(_ref) {
4984
5022
  "border border-gray-300 hover:bg-gray-50": pageNum !== currentPage
4985
5023
  }),
4986
5024
  onClick: function onClick() {
4987
- return setCurrentPage(pageNum);
5025
+ return handlePageChange(pageNum);
4988
5026
  }
4989
5027
  }, pageNum);
4990
5028
  })), /*#__PURE__*/React.createElement("button", {
4991
5029
  className: "rounded-lg md:rounded-md border border-gray-300 px-4 py-2 text-sm disabled:opacity-50 hover:bg-gray-50",
4992
5030
  disabled: currentPage === totalPages,
4993
5031
  onClick: function onClick() {
4994
- return setCurrentPage(function (p) {
4995
- return Math.min(totalPages, p + 1);
4996
- });
5032
+ return handlePageChange(Math.min(totalPages, currentPage + 1));
4997
5033
  }
4998
5034
  }, "Next")))));
4999
5035
  };
@@ -5109,7 +5145,8 @@ function ActionMenuPortal(_ref2) {
5109
5145
  window.removeEventListener("scroll", onScrollOrResize, true);
5110
5146
  };
5111
5147
  // Recompute when anchor element changes or actions change (content height may change).
5112
- }, [anchorElem, actions, menuRef]);
5148
+ // Note: menuRef is a ref object and never changes, so it's safe to include
5149
+ }, [anchorElem, actions]);
5113
5150
  return /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
5114
5151
  ref: menuRef,
5115
5152
  style: {