@dreamtree-org/twreact-ui 1.0.70 → 1.0.72

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
@@ -3883,9 +3883,101 @@ var Select = /*#__PURE__*/React.forwardRef(function (_ref, forwardedRef) {
3883
3883
  }, error));
3884
3884
  });
3885
3885
 
3886
- var _excluded$k = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "stripedColors", "responsiveBreakpoint"];
3886
+ var _excluded$k = ["data", "columns", "sortable", "filterable", "selectable", "pagination", "pageSize", "onSort", "onFilter", "onFetch", "onFilterChange", "onSelectionChange", "onRowClick", "hasDetails", "DetailsComponent", "className", "withAction", "onAction", "actions", "showSerial", "cellClass", "rowClass", "globalSearch", "limitOptions", "showLimitSelector", "onLimitChange", "showReloadButton", "renderReloadButton", "onReload", "stripedRows", "stripedColors", "responsiveBreakpoint", "serverSide", "totalRecords", "pageNumber", "onPageChange"];
3887
3887
  function ownKeys$9(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3888
3888
  function _objectSpread$9(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$9(Object(t), true).forEach(function (r) { _defineProperty$4(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$9(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3889
+
3890
+ // Constants moved outside component
3891
+ var DEFAULT_ACTIONS = [{
3892
+ name: "edit",
3893
+ label: "Edit",
3894
+ onClick: function onClick() {
3895
+ console.log("Edit action clicked");
3896
+ },
3897
+ icon: /*#__PURE__*/React.createElement(PenSquare, {
3898
+ size: 16
3899
+ })
3900
+ }, {
3901
+ name: "delete",
3902
+ label: "Delete",
3903
+ onClick: function onClick() {
3904
+ console.log("Delete action clicked");
3905
+ },
3906
+ icon: /*#__PURE__*/React.createElement(Trash, {
3907
+ size: 16
3908
+ })
3909
+ }, {
3910
+ name: "view",
3911
+ label: "View",
3912
+ onClick: function onClick() {
3913
+ console.log("View action clicked");
3914
+ },
3915
+ icon: /*#__PURE__*/React.createElement(Eye, {
3916
+ size: 16
3917
+ })
3918
+ }];
3919
+ var RESIZE_DEBOUNCE_MS = 150;
3920
+ var MENU_PLACEMENT_THRESHOLD = 160;
3921
+
3922
+ // Helper functions
3923
+ var getRowKey = function getRowKey(row, globalIndex) {
3924
+ if ((row === null || row === void 0 ? void 0 : row.id) != null) return String(row.id);
3925
+ if ((row === null || row === void 0 ? void 0 : row._id) != null) return String(row._id);
3926
+ return String(globalIndex);
3927
+ };
3928
+
3929
+ // Calculate pagination numbers
3930
+ var getPaginationNumbers = function getPaginationNumbers(currentPage, totalPages) {
3931
+ var maxVisible = 5;
3932
+ if (totalPages <= maxVisible) {
3933
+ return Array.from({
3934
+ length: totalPages
3935
+ }, function (_, i) {
3936
+ return i + 1;
3937
+ });
3938
+ }
3939
+ if (currentPage <= 3) {
3940
+ return Array.from({
3941
+ length: maxVisible
3942
+ }, function (_, i) {
3943
+ return i + 1;
3944
+ });
3945
+ }
3946
+ if (currentPage >= totalPages - 2) {
3947
+ return Array.from({
3948
+ length: maxVisible
3949
+ }, function (_, i) {
3950
+ return totalPages - 4 + i;
3951
+ });
3952
+ }
3953
+ return Array.from({
3954
+ length: maxVisible
3955
+ }, function (_, i) {
3956
+ return currentPage - 2 + i;
3957
+ });
3958
+ };
3959
+
3960
+ // Empty and Loading state components
3961
+ var EmptyState = function EmptyState() {
3962
+ return /*#__PURE__*/React.createElement("div", {
3963
+ className: "flex flex-col items-center gap-2"
3964
+ }, /*#__PURE__*/React.createElement("div", {
3965
+ className: "text-gray-400"
3966
+ }, /*#__PURE__*/React.createElement(List, {
3967
+ className: "h-8 w-8"
3968
+ })), /*#__PURE__*/React.createElement("span", {
3969
+ className: "text-sm text-gray-500"
3970
+ }, "No results found."));
3971
+ };
3972
+ var LoadingState = function LoadingState() {
3973
+ return /*#__PURE__*/React.createElement("div", {
3974
+ className: "flex flex-col items-center gap-2"
3975
+ }, /*#__PURE__*/React.createElement("div", {
3976
+ className: "h-6 w-6 animate-spin rounded-full border-2 border-primary-600 border-t-transparent"
3977
+ }), /*#__PURE__*/React.createElement("span", {
3978
+ className: "text-sm text-gray-500"
3979
+ }, "Loading..."));
3980
+ };
3889
3981
  var Table = function Table(_ref) {
3890
3982
  var _ref$data = _ref.data,
3891
3983
  data = _ref$data === void 0 ? [] : _ref$data,
@@ -3937,6 +4029,12 @@ var Table = function Table(_ref) {
3937
4029
  stripedColors = _ref$stripedColors === void 0 ? ["#ffffff", "#f7fafc"] : _ref$stripedColors,
3938
4030
  _ref$responsiveBreakp = _ref.responsiveBreakpoint,
3939
4031
  responsiveBreakpoint = _ref$responsiveBreakp === void 0 ? 768 : _ref$responsiveBreakp,
4032
+ _ref$serverSide = _ref.serverSide,
4033
+ serverSide = _ref$serverSide === void 0 ? false : _ref$serverSide,
4034
+ _ref$totalRecords = _ref.totalRecords,
4035
+ totalRecords = _ref$totalRecords === void 0 ? 0 : _ref$totalRecords,
4036
+ pageNumber = _ref.pageNumber,
4037
+ onPageChange = _ref.onPageChange,
3940
4038
  props = _objectWithoutProperties$1(_ref, _excluded$k);
3941
4039
  // State for responsive view
3942
4040
  var _useState = React.useState(false),
@@ -3945,14 +4043,16 @@ var Table = function Table(_ref) {
3945
4043
  setIsMobileView = _useState2[1];
3946
4044
 
3947
4045
  // Keep original table data / loading
3948
- var _useState3 = React.useState(Array.isArray(data) ? data : []),
4046
+ var _useState3 = React.useState(function () {
4047
+ return Array.isArray(data) ? data : [];
4048
+ }),
3949
4049
  _useState4 = _slicedToArray(_useState3, 2),
3950
4050
  tableData = _useState4[0],
3951
4051
  setTableData = _useState4[1];
3952
4052
  var _useState5 = React.useState(false),
3953
4053
  _useState6 = _slicedToArray(_useState5, 2),
3954
4054
  loading = _useState6[0],
3955
- setLoading = _useState6[1];
4055
+ _setLoading = _useState6[1];
3956
4056
 
3957
4057
  // Column visibility state
3958
4058
  var _useState7 = React.useState(function () {
@@ -3964,10 +4064,26 @@ var Table = function Table(_ref) {
3964
4064
  columnsState = _useState8[0],
3965
4065
  setColumnsState = _useState8[1];
3966
4066
  React.useEffect(function () {
3967
- // Sync when prop changes
3968
- setColumnsState(Array.isArray(columns) ? columns.map(function (c) {
3969
- return _objectSpread$9({}, c);
3970
- }) : []);
4067
+ // Sync when prop changes - only update if columns actually changed
4068
+ if (Array.isArray(columns)) {
4069
+ setColumnsState(function (prev) {
4070
+ var prevKeys = new Set(prev.map(function (c) {
4071
+ return c.key;
4072
+ }));
4073
+ var newKeys = new Set(columns.map(function (c) {
4074
+ return c.key;
4075
+ }));
4076
+ var keysChanged = prevKeys.size !== newKeys.size || _toConsumableArray$1(prevKeys).some(function (k) {
4077
+ return !newKeys.has(k);
4078
+ });
4079
+ if (keysChanged) {
4080
+ return columns.map(function (c) {
4081
+ return _objectSpread$9({}, c);
4082
+ });
4083
+ }
4084
+ return prev;
4085
+ });
4086
+ }
3971
4087
  }, [columns]);
3972
4088
 
3973
4089
  // Popover state for column toggler
@@ -3998,7 +4114,7 @@ var Table = function Table(_ref) {
3998
4114
  _useState16 = _slicedToArray(_useState15, 2),
3999
4115
  expandedRows = _useState16[0],
4000
4116
  setExpandedRows = _useState16[1];
4001
- var _useState17 = React.useState(1),
4117
+ var _useState17 = React.useState(typeof pageNumber === "number" ? pageNumber : 1),
4002
4118
  _useState18 = _slicedToArray(_useState17, 2),
4003
4119
  currentPage = _useState18[0],
4004
4120
  setCurrentPage = _useState18[1];
@@ -4027,34 +4143,43 @@ var Table = function Table(_ref) {
4027
4143
  _useState28 = _slicedToArray(_useState27, 2),
4028
4144
  openActionKey = _useState28[0],
4029
4145
  setOpenActionKey = _useState28[1];
4030
- var openRef = React.useRef(null);
4146
+ React.useEffect(function () {
4147
+ if (typeof pageNumber === "number" && pageNumber !== currentPage) {
4148
+ setCurrentPage(pageNumber);
4149
+ onPageChange === null || onPageChange === void 0 || onPageChange(pageNumber);
4150
+ }
4151
+ }, [pageNumber, currentPage, onPageChange]);
4152
+ React.useEffect(function () {
4153
+ setLimit(pageSize);
4154
+ }, [pageSize]);
4031
4155
 
4032
- // Check if mobile view
4156
+ // Check if mobile view with debouncing
4033
4157
  React.useEffect(function () {
4158
+ var timeoutId;
4034
4159
  var checkMobile = function checkMobile() {
4035
4160
  setIsMobileView(window.innerWidth < responsiveBreakpoint);
4036
4161
  };
4162
+ var debouncedCheck = function debouncedCheck() {
4163
+ clearTimeout(timeoutId);
4164
+ timeoutId = setTimeout(checkMobile, RESIZE_DEBOUNCE_MS);
4165
+ };
4037
4166
 
4038
4167
  // Initial check
4039
4168
  checkMobile();
4040
4169
 
4041
- // Add event listener
4042
- window.addEventListener("resize", checkMobile);
4170
+ // Add event listener with debouncing
4171
+ window.addEventListener("resize", debouncedCheck);
4043
4172
  return function () {
4044
- window.removeEventListener("resize", checkMobile);
4173
+ clearTimeout(timeoutId);
4174
+ window.removeEventListener("resize", debouncedCheck);
4045
4175
  };
4046
4176
  }, [responsiveBreakpoint]);
4047
- var isValidList = function isValidList(d) {
4048
- return Array.isArray(d);
4049
- };
4050
- var setDataForExternal = function setDataForExternal(newData) {
4051
- if (isValidList(newData)) setTableData(newData);else setTableData([]);
4052
- };
4053
4177
 
4054
4178
  // Close column menu when clicking outside
4055
4179
  React.useEffect(function () {
4180
+ if (!showColumnMenu) return;
4056
4181
  var onDocClick = function onDocClick(e) {
4057
- if (showColumnMenu && columnMenuRef.current && !columnMenuRef.current.contains(e.target) && columnToggleBtnRef.current && !columnToggleBtnRef.current.contains(e.target)) {
4182
+ if (columnMenuRef.current && !columnMenuRef.current.contains(e.target) && columnToggleBtnRef.current && !columnToggleBtnRef.current.contains(e.target)) {
4058
4183
  setShowColumnMenu(false);
4059
4184
  }
4060
4185
  };
@@ -4064,26 +4189,32 @@ var Table = function Table(_ref) {
4064
4189
  };
4065
4190
  }, [showColumnMenu]);
4066
4191
 
4067
- // Close per-row actionmenu when clicking outside
4068
- React.useEffect(function () {
4069
- var handler = function handler(e) {
4070
- if (openActionKey && openRef.current && !openRef.current.contains(e.target)) {
4071
- setOpenActionKey(null);
4072
- }
4073
- };
4074
- document.addEventListener("click", handler);
4075
- return function () {
4076
- return document.removeEventListener("click", handler);
4077
- };
4078
- }, [openActionKey]);
4079
-
4080
4192
  // Visible columns derived from columnsState
4081
4193
  var visibleColumns = React.useMemo(function () {
4082
4194
  return columnsState.filter(function (col) {
4083
4195
  return col.isVisible !== false;
4084
4196
  });
4085
4197
  }, [columnsState]);
4086
- var toggleColumnVisibility = function toggleColumnVisibility(key) {
4198
+
4199
+ // Memoize actions
4200
+ var actionsToUse = React.useMemo(function () {
4201
+ return actions !== null && actions !== void 0 ? actions : DEFAULT_ACTIONS;
4202
+ }, [actions]);
4203
+
4204
+ // Memoize visible count
4205
+ var visibleCount = React.useMemo(function () {
4206
+ return (showSerial ? 1 : 0) + visibleColumns.length + (selectable ? 1 : 0) + (hasDetails ? 1 : 0) + (withAction ? 1 : 0);
4207
+ }, [showSerial, visibleColumns.length, selectable, hasDetails, withAction]);
4208
+
4209
+ // Memoize key-to-row mapping for selection
4210
+ var keyToRowMap = React.useMemo(function () {
4211
+ var map = new Map();
4212
+ filteredData.forEach(function (row, i) {
4213
+ map.set(getRowKey(row, i), row);
4214
+ });
4215
+ return map;
4216
+ }, [filteredData]);
4217
+ var toggleColumnVisibility = React.useCallback(function (key) {
4087
4218
  setColumnsState(function (prev) {
4088
4219
  return prev.map(function (c) {
4089
4220
  return c.key === key ? _objectSpread$9(_objectSpread$9({}, c), {}, {
@@ -4092,127 +4223,73 @@ var Table = function Table(_ref) {
4092
4223
  });
4093
4224
  });
4094
4225
  setCurrentPage(1);
4095
- };
4226
+ }, []);
4096
4227
 
4097
4228
  // Handle actions
4098
- var handleOnAction = function handleOnAction(action, row) {
4229
+ var handleOnAction = React.useCallback(function (action, row) {
4099
4230
  var _action$onClick;
4100
4231
  (_action$onClick = action.onClick) === null || _action$onClick === void 0 || _action$onClick.call(action, {
4101
4232
  action: action,
4102
4233
  row: row
4103
4234
  });
4104
- onAction && onAction({
4235
+ onAction === null || onAction === void 0 || onAction({
4105
4236
  action: action,
4106
4237
  row: row
4107
4238
  });
4108
4239
  setOpenActionKey(null);
4109
4240
  setActionAnchor(null);
4110
- };
4111
- var defaultActions = [{
4112
- name: "edit",
4113
- label: "Edit",
4114
- onClick: function onClick() {
4115
- console.log("Edit action clicked");
4116
- },
4117
- icon: /*#__PURE__*/React.createElement(PenSquare, {
4118
- size: 16
4119
- })
4120
- }, {
4121
- name: "delete",
4122
- label: "Delete",
4123
- onClick: function onClick() {
4124
- console.log("Delete action clicked");
4125
- },
4126
- icon: /*#__PURE__*/React.createElement(Trash, {
4127
- size: 16
4128
- })
4129
- }, {
4130
- name: "view",
4131
- label: "View",
4132
- onClick: function onClick() {
4133
- console.log("View action clicked");
4134
- },
4135
- icon: /*#__PURE__*/React.createElement(Eye, {
4136
- size: 16
4137
- })
4138
- }];
4139
- var actionsToUse = actions !== undefined ? actions : defaultActions;
4140
- var getRowKey = function getRowKey(row, globalIndex) {
4141
- if (row == null) return String(globalIndex);
4142
- if (row.id !== undefined && row.id !== null) return String(row.id);
4143
- if (row._id !== undefined && row._id !== null) return String(row._id);
4144
- return String(globalIndex);
4145
- };
4241
+ }, [onAction]);
4146
4242
 
4147
4243
  // Sorting
4148
4244
  var sortedData = React.useMemo(function () {
4149
- if (!sortConfig.key) return tableData;
4245
+ if (serverSide || !sortConfig.key) return tableData;
4150
4246
  var key = sortConfig.key,
4151
4247
  direction = sortConfig.direction;
4152
4248
  return _toConsumableArray$1(tableData).sort(function (a, b) {
4153
- var aValue = a === null || a === void 0 ? void 0 : a[key];
4154
- var bValue = b === null || b === void 0 ? void 0 : b[key];
4155
- if (aValue == null && bValue == null) return 0;
4156
- if (aValue == null) return direction === "asc" ? -1 : 1;
4157
- if (bValue == null) return direction === "asc" ? 1 : -1;
4158
- if (typeof aValue === "number" && typeof bValue === "number") {
4159
- return direction === "asc" ? aValue - bValue : bValue - aValue;
4160
- }
4161
- var aStr = String(aValue).toLowerCase();
4162
- var bStr = String(bValue).toLowerCase();
4163
- if (aStr < bStr) return direction === "asc" ? -1 : 1;
4164
- if (aStr > bStr) return direction === "asc" ? 1 : -1;
4165
- return 0;
4249
+ var av = a === null || a === void 0 ? void 0 : a[key];
4250
+ var bv = b === null || b === void 0 ? void 0 : b[key];
4251
+ if (av == null || bv == null) return 0;
4252
+ if (typeof av === "number") return direction === "asc" ? av - bv : bv - av;
4253
+ return direction === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
4166
4254
  });
4167
- }, [tableData, sortConfig]);
4255
+ }, [tableData, sortConfig, serverSide]);
4168
4256
 
4169
4257
  // Filtering
4170
4258
  var filteredData = React.useMemo(function () {
4171
- if (!filterable || Object.keys(filters).length === 0) return sortedData;
4172
- var globalQuery = String(filters.global || "").trim().toLowerCase();
4259
+ if (serverSide || !filterable || !Object.keys(filters).length) return sortedData;
4260
+ var q = (filters.global || "").toLowerCase();
4173
4261
  return sortedData.filter(function (row) {
4174
- // Per-column filters
4175
- var perColumnOk = Object.entries(filters).every(function (_ref2) {
4176
- var _ref3 = _slicedToArray(_ref2, 2),
4177
- key = _ref3[0],
4178
- value = _ref3[1];
4179
- if (key === "global") return true;
4180
- if (!value) return true;
4181
- var cell = row === null || row === void 0 ? void 0 : row[key];
4182
- if (cell == null) return false;
4183
- return String(cell).toLowerCase().includes(String(value).toLowerCase());
4262
+ return Object.values(row || {}).some(function (v) {
4263
+ return String(v).toLowerCase().includes(q);
4184
4264
  });
4185
- if (!perColumnOk) return false;
4186
-
4187
- // Global filter
4188
- if (globalQuery) {
4189
- var matchesVisible = visibleColumns.some(function (col) {
4190
- var v = row === null || row === void 0 ? void 0 : row[col.key];
4191
- if (v == null) return false;
4192
- return String(v).toLowerCase().includes(globalQuery);
4193
- });
4194
- if (matchesVisible) return true;
4195
- return Object.values(row || {}).some(function (v) {
4196
- return v != null ? String(v).toLowerCase().includes(globalQuery) : false;
4197
- });
4198
- }
4199
- return true;
4200
4265
  });
4201
- }, [sortedData, filters, filterable, visibleColumns]);
4266
+ }, [sortedData, filters, filterable, serverSide]);
4202
4267
 
4203
- // Pagination indices
4204
- var startIndex = pagination ? (currentPage - 1) * limit : 0;
4205
- var endIndex = pagination ? startIndex + limit : filteredData.length;
4268
+ // Pagination indices - memoized
4269
+ var _useMemo = React.useMemo(function () {
4270
+ var start = pagination ? (currentPage - 1) * limit : 0;
4271
+ var end = pagination ? start + limit : filteredData.length;
4272
+ return {
4273
+ startIndex: start,
4274
+ endIndex: end
4275
+ };
4276
+ }, [pagination, currentPage, limit, filteredData.length]),
4277
+ startIndex = _useMemo.startIndex,
4278
+ endIndex = _useMemo.endIndex;
4206
4279
 
4207
4280
  // Paginated view
4208
4281
  var paginatedData = React.useMemo(function () {
4209
- if (!pagination) return filteredData;
4210
- return filteredData.slice(startIndex, endIndex);
4211
- }, [filteredData, startIndex, endIndex, pagination]);
4212
- var totalPages = Math.max(1, Math.ceil(filteredData.length / limit));
4282
+ if (!pagination || serverSide) return filteredData;
4283
+ var start = (currentPage - 1) * limit;
4284
+ return filteredData.slice(start, start + limit);
4285
+ }, [filteredData, pagination, serverSide, currentPage, limit]);
4286
+ var totalPages = React.useMemo(function () {
4287
+ if (!pagination) return 1;
4288
+ return serverSide ? Math.max(1, Math.ceil((totalRecords || 0) / limit)) : Math.max(1, Math.ceil(filteredData.length / limit));
4289
+ }, [pagination, serverSide, totalRecords, filteredData.length, limit]);
4213
4290
 
4214
4291
  // Sorting handler
4215
- var handleSort = function handleSort(key) {
4292
+ var handleSort = React.useCallback(function (key) {
4216
4293
  if (!sortable) return;
4217
4294
  var direction = sortConfig.key === key && sortConfig.direction === "asc" ? "desc" : "asc";
4218
4295
  setSortConfig({
@@ -4220,10 +4297,10 @@ var Table = function Table(_ref) {
4220
4297
  direction: direction
4221
4298
  });
4222
4299
  onSort === null || onSort === void 0 || onSort(key, direction);
4223
- };
4300
+ }, [sortable, sortConfig, onSort]);
4224
4301
 
4225
- // Selection handlers
4226
- var handleSelectAll = function handleSelectAll() {
4302
+ // Selection handlers - optimized with memoized keyToRowMap
4303
+ var handleSelectAll = React.useCallback(function () {
4227
4304
  var newSelection = new Set(selectedRows);
4228
4305
  var pageRowKeys = paginatedData.map(function (r, i) {
4229
4306
  return getRowKey(r, startIndex + i);
@@ -4241,50 +4318,45 @@ var Table = function Table(_ref) {
4241
4318
  });
4242
4319
  }
4243
4320
  setSelectedRows(newSelection);
4244
- var keyToRow = new Map(filteredData.map(function (r, i) {
4245
- return [getRowKey(r, i), r];
4246
- }));
4247
4321
  var selectedData = Array.from(newSelection).map(function (k) {
4248
- return keyToRow.get(k);
4322
+ return keyToRowMap.get(k);
4249
4323
  }).filter(Boolean);
4250
4324
  onSelectionChange === null || onSelectionChange === void 0 || onSelectionChange(selectedData);
4251
- };
4252
- var handleSelectRow = function handleSelectRow(row, rowIndexInPage) {
4325
+ }, [selectedRows, paginatedData, startIndex, keyToRowMap, onSelectionChange]);
4326
+ var handleSelectRow = React.useCallback(function (row, rowIndexInPage) {
4253
4327
  var globalIndex = startIndex + rowIndexInPage;
4254
4328
  var key = getRowKey(row, globalIndex);
4255
4329
  var newSelection = new Set(selectedRows);
4256
4330
  if (newSelection.has(key)) newSelection["delete"](key);else newSelection.add(key);
4257
4331
  setSelectedRows(newSelection);
4258
- var keyToRow = new Map(filteredData.map(function (r, i) {
4259
- return [getRowKey(r, i), r];
4260
- }));
4261
4332
  var selectedData = Array.from(newSelection).map(function (k) {
4262
- return keyToRow.get(k);
4333
+ return keyToRowMap.get(k);
4263
4334
  }).filter(Boolean);
4264
4335
  onSelectionChange === null || onSelectionChange === void 0 || onSelectionChange(selectedData);
4265
- };
4266
- var toggleExpandRow = function toggleExpandRow(row, rowIndexInPage) {
4336
+ }, [startIndex, selectedRows, keyToRowMap, onSelectionChange]);
4337
+ var toggleExpandRow = React.useCallback(function (row, rowIndexInPage) {
4267
4338
  var globalIndex = startIndex + rowIndexInPage;
4268
4339
  var key = getRowKey(row, globalIndex);
4269
- var newExpanded = new Set(expandedRows);
4270
- if (newExpanded.has(key)) newExpanded["delete"](key);else newExpanded.add(key);
4271
- setExpandedRows(newExpanded);
4272
- };
4273
- var handleFilter = function handleFilter(key, value) {
4274
- var newFilters = _objectSpread$9(_objectSpread$9({}, filters), {}, _defineProperty$4({}, key, value));
4275
- setFilters(newFilters);
4276
- onFilter === null || onFilter === void 0 || onFilter(newFilters);
4277
- onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
4340
+ setExpandedRows(function (prev) {
4341
+ var newExpanded = new Set(prev);
4342
+ if (newExpanded.has(key)) newExpanded["delete"](key);else newExpanded.add(key);
4343
+ return newExpanded;
4344
+ });
4345
+ }, [startIndex]);
4346
+ var handleFilter = React.useCallback(function (key, value) {
4347
+ setFilters(function (prev) {
4348
+ var newFilters = _objectSpread$9(_objectSpread$9({}, prev), {}, _defineProperty$4({}, key, value));
4349
+ onFilter === null || onFilter === void 0 || onFilter(newFilters);
4350
+ onFilterChange === null || onFilterChange === void 0 || onFilterChange(newFilters);
4351
+ return newFilters;
4352
+ });
4278
4353
  setCurrentPage(1);
4279
- };
4280
- var renderCell = function renderCell(column, row, globalIndex) {
4354
+ }, [onFilter, onFilterChange]);
4355
+ var renderCell = React.useCallback(function (column, row, globalIndex) {
4281
4356
  if (column.render) return column.render(row, globalIndex);
4282
4357
  return row === null || row === void 0 ? void 0 : row[column.key];
4283
- };
4284
-
4285
- // UI counts
4286
- var visibleCount = (showSerial ? 1 : 0) + visibleColumns.length + (selectable ? 1 : 0) + (hasDetails ? 1 : 0) + (withAction ? 1 : 0);
4287
- var toggleActions = function toggleActions(e, actionCellKey, row) {
4358
+ }, []);
4359
+ var toggleActions = React.useCallback(function (e, actionCellKey, row) {
4288
4360
  e.stopPropagation();
4289
4361
  if (actionAnchor && actionAnchor.key === actionCellKey) {
4290
4362
  setOpenActionKey(null);
@@ -4297,7 +4369,7 @@ var Table = function Table(_ref) {
4297
4369
  row: row
4298
4370
  });
4299
4371
  }
4300
- };
4372
+ }, [actionAnchor]);
4301
4373
  React.useEffect(function () {
4302
4374
  if (!actionAnchor) return;
4303
4375
  var onDocClick = function onDocClick(ev) {
@@ -4321,58 +4393,139 @@ var Table = function Table(_ref) {
4321
4393
  window.removeEventListener("resize", onScrollResize);
4322
4394
  };
4323
4395
  }, [actionAnchor]);
4396
+
4397
+ // Track previous fetch params to prevent unnecessary calls
4398
+ var prevFetchParamsRef = React.useRef(null);
4399
+ var isFetchingRef = React.useRef(false);
4400
+ var isMountedRef = React.useRef(true);
4401
+ var onFetchRef = React.useRef(onFetch);
4402
+
4403
+ // Keep ref in sync with onFetch
4324
4404
  React.useEffect(function () {
4325
- if (!onFetch) return;
4326
- onFetch({
4327
- setData: setDataForExternal,
4405
+ onFetchRef.current = onFetch;
4406
+ }, [onFetch]);
4407
+
4408
+ // Track mount status
4409
+ React.useEffect(function () {
4410
+ isMountedRef.current = true;
4411
+ return function () {
4412
+ isMountedRef.current = false;
4413
+ isFetchingRef.current = false;
4414
+ };
4415
+ }, []);
4416
+
4417
+ // Serialize fetch params for comparison
4418
+ var fetchParams = React.useMemo(function () {
4419
+ return {
4328
4420
  filters: filters,
4329
- setLoading: setLoading,
4330
- pagination: {
4331
- currentPage: currentPage,
4332
- limit: limit,
4333
- totalPages: totalPages,
4334
- nextRecords: paginatedData
4335
- }
4336
- });
4337
- }, [filters, currentPage, limit]);
4421
+ page: currentPage,
4422
+ limit: limit,
4423
+ sortKey: sortConfig.key,
4424
+ sortDirection: sortConfig.direction
4425
+ };
4426
+ }, [filters, currentPage, limit, sortConfig.key, sortConfig.direction]);
4427
+ var fetchParamsString = React.useMemo(function () {
4428
+ return JSON.stringify(fetchParams);
4429
+ }, [fetchParams]);
4430
+
4431
+ // Consolidated data sync effect
4338
4432
  React.useEffect(function () {
4339
- if (!onFetch && isValidList(data)) setTableData(data);
4340
- }, [data, onFetch]);
4433
+ var currentOnFetch = onFetchRef.current;
4434
+ if (currentOnFetch) {
4435
+ // Only fetch if params actually changed and not already fetching
4436
+ if (!isFetchingRef.current && prevFetchParamsRef.current !== fetchParamsString) {
4437
+ prevFetchParamsRef.current = fetchParamsString;
4438
+ 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;
4445
+ }
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) {
4452
+ isFetchingRef.current = false;
4453
+ }
4454
+ }
4455
+ },
4456
+ filters: fetchParams.filters,
4457
+ page: fetchParams.page,
4458
+ limit: fetchParams.limit,
4459
+ sort: {
4460
+ key: fetchParams.sortKey,
4461
+ direction: fetchParams.sortDirection
4462
+ }
4463
+ });
4464
+ }
4465
+ } else if (!serverSide && Array.isArray(data)) {
4466
+ setTableData(data);
4467
+ }
4468
+ }, [serverSide, data, fetchParamsString, fetchParams]);
4341
4469
 
4342
4470
  // Global search
4343
4471
  React.useEffect(function () {
4344
4472
  setSearchInput(filters.global || "");
4345
4473
  }, [filters.global]);
4346
- var applyGlobalSearch = function applyGlobalSearch() {
4474
+ var applyGlobalSearch = React.useCallback(function () {
4347
4475
  handleFilter("global", searchInput);
4348
- };
4349
- var onGlobalKeyDown = function onGlobalKeyDown(e) {
4476
+ }, [handleFilter, searchInput]);
4477
+ var onGlobalKeyDown = React.useCallback(function (e) {
4350
4478
  if (e.key === "Enter") {
4351
4479
  e.preventDefault();
4352
4480
  applyGlobalSearch();
4353
4481
  }
4354
- };
4355
- React.useEffect(function () {
4356
- setLimit(pageSize);
4357
- }, [pageSize]);
4358
- var handleLimitChange = function handleLimitChange(nextLimit) {
4482
+ }, [applyGlobalSearch]);
4483
+ var handleLimitChange = React.useCallback(function (nextLimit) {
4359
4484
  var parsed = Number(nextLimit);
4360
4485
  if (!Number.isFinite(parsed) || parsed <= 0) return;
4361
4486
  setLimit(parsed);
4487
+ setCurrentPage(1);
4362
4488
  onLimitChange === null || onLimitChange === void 0 || onLimitChange(parsed);
4363
- };
4489
+ }, [onLimitChange]);
4364
4490
 
4365
- // Render mobile card
4366
- var renderMobileCard = function renderMobileCard(row, rowIndexInPage) {
4491
+ // Memoize limit options
4492
+ var limitOptionsMemo = React.useMemo(function () {
4493
+ var opts = Array.isArray(limitOptions) && limitOptions.length > 0 ? limitOptions : [25, 50, 100];
4494
+ return opts.map(function (opt) {
4495
+ return {
4496
+ label: String(opt),
4497
+ value: opt
4498
+ };
4499
+ });
4500
+ }, [limitOptions]);
4501
+
4502
+ // Extract row metadata computation
4503
+ var getRowMetadata = React.useCallback(function (row, rowIndexInPage) {
4367
4504
  var globalIndex = startIndex + rowIndexInPage;
4368
4505
  var key = getRowKey(row, globalIndex);
4369
4506
  var actionCellKey = "actions-".concat(key);
4370
- var extraRowClass = typeof rowClass === "function" ? rowClass({
4507
+ var extraRowClass = typeof rowClass === "function" ? (rowClass({
4371
4508
  row: row,
4372
4509
  rowIndex: globalIndex
4373
- }) : "";
4374
- var safeExtraRowClass = typeof extraRowClass === "string" ? extraRowClass.trim() : "";
4510
+ }) || "").trim() : "";
4375
4511
  var stripeBg = stripedRows && !selectedRows.has(key) ? stripedColors[globalIndex % stripedColors.length] : undefined;
4512
+ return {
4513
+ globalIndex: globalIndex,
4514
+ key: key,
4515
+ actionCellKey: actionCellKey,
4516
+ extraRowClass: extraRowClass,
4517
+ stripeBg: stripeBg
4518
+ };
4519
+ }, [startIndex, rowClass, stripedRows, selectedRows, stripedColors]);
4520
+
4521
+ // Render mobile card
4522
+ var renderMobileCard = React.useCallback(function (row, rowIndexInPage) {
4523
+ var _getRowMetadata = getRowMetadata(row, rowIndexInPage),
4524
+ globalIndex = _getRowMetadata.globalIndex,
4525
+ key = _getRowMetadata.key,
4526
+ actionCellKey = _getRowMetadata.actionCellKey;
4527
+ _getRowMetadata.extraRowClass;
4528
+ var stripeBg = _getRowMetadata.stripeBg;
4376
4529
  return /*#__PURE__*/React.createElement("div", {
4377
4530
  key: key,
4378
4531
  style: stripeBg ? {
@@ -4439,16 +4592,15 @@ var Table = function Table(_ref) {
4439
4592
  }), document.body))), /*#__PURE__*/React.createElement("div", {
4440
4593
  className: "p-4"
4441
4594
  }, visibleColumns.map(function (column, colIndex) {
4442
- var extraCellClass = typeof cellClass === "function" ? cellClass({
4595
+ var extraCellClass = typeof cellClass === "function" ? (cellClass({
4443
4596
  row: row,
4444
4597
  rowIndex: globalIndex,
4445
4598
  column: column,
4446
4599
  columnIndex: colIndex
4447
- }) : "";
4448
- var safeExtraCellClass = typeof extraCellClass === "string" ? extraCellClass.trim() : "";
4600
+ }) || "").trim() : "";
4449
4601
  return /*#__PURE__*/React.createElement("div", {
4450
4602
  key: column.key,
4451
- className: cn$1("flex justify-between items-center flex-row py-2 border-b last:border-b-0", safeExtraCellClass)
4603
+ className: cn$1("flex justify-between items-center flex-row py-2 border-b last:border-b-0", extraCellClass)
4452
4604
  }, /*#__PURE__*/React.createElement("div", {
4453
4605
  className: "text-xs font-medium text-gray-500 uppercase tracking-wide mb-1 sm:mb-0 sm:w-1/3 sm:pr-2"
4454
4606
  }, column.label), /*#__PURE__*/React.createElement("div", {
@@ -4460,7 +4612,7 @@ var Table = function Table(_ref) {
4460
4612
  row: row,
4461
4613
  index: globalIndex
4462
4614
  })));
4463
- };
4615
+ }, [getRowMetadata, hasDetails, selectable, showSerial, withAction, expandedRows, selectedRows, onRowClick, visibleColumns, renderCell, cellClass, DetailsComponent, actionsToUse, actionAnchor, openActionKey, handleOnAction, actionMenuRef]);
4464
4616
 
4465
4617
  // Render mobile filters
4466
4618
  var renderMobileFilters = function renderMobileFilters() {
@@ -4528,23 +4680,11 @@ var Table = function Table(_ref) {
4528
4680
  htmlFor: "pagination-limit",
4529
4681
  className: "text-sm text-gray-600 whitespace-nowrap"
4530
4682
  }, "Show"), /*#__PURE__*/React.createElement(Select, {
4531
- options: Array.isArray(limitOptions) && limitOptions.length > 0 ? limitOptions.map(function (opt) {
4532
- return {
4533
- label: String(opt),
4534
- value: opt
4535
- };
4536
- }) : [25, 50, 100].map(function (opt) {
4537
- return {
4538
- label: String(opt),
4539
- value: opt
4540
- };
4541
- }),
4683
+ options: limitOptionsMemo,
4542
4684
  value: limit,
4543
4685
  allowClear: false,
4544
4686
  placeholder: "",
4545
- onChange: function onChange(e) {
4546
- return handleLimitChange(e);
4547
- },
4687
+ onChange: handleLimitChange,
4548
4688
  className: "w-20 md:w-30"
4549
4689
  }), /*#__PURE__*/React.createElement("p", {
4550
4690
  className: "text-sm text-gray-600 whitespace-nowrap"
@@ -4701,7 +4841,7 @@ var Table = function Table(_ref) {
4701
4841
  }, /*#__PURE__*/React.createElement("input", {
4702
4842
  type: "text",
4703
4843
  placeholder: "Filter ".concat(column.label),
4704
- className: "w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm",
4844
+ className: "w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm font-normal",
4705
4845
  value: filters[column.key] || "",
4706
4846
  onChange: function onChange(e) {
4707
4847
  return handleFilter(column.key, e.target.value);
@@ -4716,33 +4856,16 @@ var Table = function Table(_ref) {
4716
4856
  }, loading ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
4717
4857
  colSpan: visibleCount,
4718
4858
  className: "px-6 py-8 text-center"
4719
- }, /*#__PURE__*/React.createElement("div", {
4720
- className: "flex flex-col items-center gap-2"
4721
- }, /*#__PURE__*/React.createElement("div", {
4722
- className: "h-6 w-6 animate-spin rounded-full border-2 border-primary-600 border-t-transparent"
4723
- }), /*#__PURE__*/React.createElement("span", {
4724
- className: "text-sm text-gray-500"
4725
- }, "Loading...")))) : paginatedData.length === 0 ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
4859
+ }, /*#__PURE__*/React.createElement(LoadingState, null))) : paginatedData.length === 0 ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", {
4726
4860
  colSpan: visibleCount,
4727
4861
  className: "px-6 py-8 text-center"
4728
- }, /*#__PURE__*/React.createElement("div", {
4729
- className: "flex flex-col items-center gap-2"
4730
- }, /*#__PURE__*/React.createElement("div", {
4731
- className: "text-gray-400"
4732
- }, /*#__PURE__*/React.createElement(List, {
4733
- className: "h-8 w-8"
4734
- })), /*#__PURE__*/React.createElement("span", {
4735
- className: "text-sm text-gray-500"
4736
- }, "No results found.")))) : paginatedData.map(function (row, rowIndexInPage) {
4737
- var globalIndex = startIndex + rowIndexInPage;
4738
- var key = getRowKey(row, globalIndex);
4739
- var actionCellKey = "actions-".concat(key);
4740
- var extraRowClass = typeof rowClass === "function" ? rowClass({
4741
- row: row,
4742
- rowIndex: globalIndex
4743
- }) : "";
4744
- var safeExtraRowClass = typeof extraRowClass === "string" ? extraRowClass.trim() : "";
4745
- var stripeBg = stripedRows && !selectedRows.has(key) ? stripedColors[globalIndex % stripedColors.length] : undefined;
4862
+ }, /*#__PURE__*/React.createElement(EmptyState, null))) : paginatedData.map(function (row, rowIndexInPage) {
4863
+ var _getRowMetadata2 = getRowMetadata(row, rowIndexInPage),
4864
+ globalIndex = _getRowMetadata2.globalIndex,
4865
+ key = _getRowMetadata2.key,
4866
+ actionCellKey = _getRowMetadata2.actionCellKey,
4867
+ extraRowClass = _getRowMetadata2.extraRowClass,
4868
+ stripeBg = _getRowMetadata2.stripeBg;
4746
4869
  return /*#__PURE__*/React.createElement(React.Fragment, {
4747
4870
  key: key
4748
4871
  }, /*#__PURE__*/React.createElement("tr", {
@@ -4752,7 +4875,7 @@ var Table = function Table(_ref) {
4752
4875
  className: cn$1("hover:bg-gray-50", {
4753
4876
  "cursor-pointer": !!onRowClick,
4754
4877
  "bg-primary-50": selectedRows.has(key)
4755
- }, safeExtraRowClass),
4878
+ }, extraRowClass),
4756
4879
  onClick: function onClick() {
4757
4880
  return onRowClick === null || onRowClick === void 0 ? void 0 : onRowClick(row, globalIndex);
4758
4881
  }
@@ -4780,16 +4903,15 @@ var Table = function Table(_ref) {
4780
4903
  return handleSelectRow(row, rowIndexInPage);
4781
4904
  }
4782
4905
  })), visibleColumns.map(function (column, columnIndex) {
4783
- var extraCellClass = typeof cellClass === "function" ? cellClass({
4906
+ var extraCellClass = typeof cellClass === "function" ? (cellClass({
4784
4907
  row: row,
4785
4908
  rowIndex: globalIndex,
4786
4909
  column: column,
4787
4910
  columnIndex: columnIndex
4788
- }) : "";
4789
- var safeExtraCellClass = typeof extraCellClass === "string" ? extraCellClass.trim() : "";
4911
+ }) || "").trim() : "";
4790
4912
  return /*#__PURE__*/React.createElement("td", {
4791
4913
  key: column.key,
4792
- className: cn$1("px-6 py-4 whitespace-nowrap text-sm text-gray-900", safeExtraCellClass)
4914
+ className: cn$1("px-6 py-4 whitespace-nowrap text-sm text-gray-900", extraCellClass)
4793
4915
  }, renderCell(column, row, globalIndex));
4794
4916
  }), withAction && /*#__PURE__*/React.createElement("td", {
4795
4917
  className: "px-4 py-4 text-sm text-right",
@@ -4832,23 +4954,9 @@ var Table = function Table(_ref) {
4832
4954
  className: "p-4"
4833
4955
  }, loading ? /*#__PURE__*/React.createElement("div", {
4834
4956
  className: "py-8 text-center"
4835
- }, /*#__PURE__*/React.createElement("div", {
4836
- className: "flex flex-col items-center gap-2"
4837
- }, /*#__PURE__*/React.createElement("div", {
4838
- className: "h-6 w-6 animate-spin rounded-full border-2 border-primary-600 border-t-transparent"
4839
- }), /*#__PURE__*/React.createElement("span", {
4840
- className: "text-sm text-gray-500"
4841
- }, "Loading..."))) : paginatedData.length === 0 ? /*#__PURE__*/React.createElement("div", {
4957
+ }, /*#__PURE__*/React.createElement(LoadingState, null)) : paginatedData.length === 0 ? /*#__PURE__*/React.createElement("div", {
4842
4958
  className: "py-8 text-center"
4843
- }, /*#__PURE__*/React.createElement("div", {
4844
- className: "flex flex-col items-center gap-2"
4845
- }, /*#__PURE__*/React.createElement("div", {
4846
- className: "text-gray-400"
4847
- }, /*#__PURE__*/React.createElement(List, {
4848
- className: "h-8 w-8"
4849
- })), /*#__PURE__*/React.createElement("span", {
4850
- className: "text-sm text-gray-500"
4851
- }, "No results found."))) : paginatedData.map(function (row, rowIndexInPage) {
4959
+ }, /*#__PURE__*/React.createElement(EmptyState, null)) : paginatedData.map(function (row, rowIndexInPage) {
4852
4960
  return renderMobileCard(row, rowIndexInPage);
4853
4961
  })), pagination && /*#__PURE__*/React.createElement("div", {
4854
4962
  className: "p-4 border-t"
@@ -4868,19 +4976,7 @@ var Table = function Table(_ref) {
4868
4976
  }
4869
4977
  }, "Previous"), /*#__PURE__*/React.createElement("div", {
4870
4978
  className: "flex items-center gap-1"
4871
- }, Array.from({
4872
- length: Math.min(5, totalPages)
4873
- }, function (_, i) {
4874
- var pageNum;
4875
- if (totalPages <= 5) {
4876
- pageNum = i + 1;
4877
- } else if (currentPage <= 3) {
4878
- pageNum = i + 1;
4879
- } else if (currentPage >= totalPages - 2) {
4880
- pageNum = totalPages - 4 + i;
4881
- } else {
4882
- pageNum = currentPage - 2 + i;
4883
- }
4979
+ }, getPaginationNumbers(currentPage, totalPages).map(function (pageNum) {
4884
4980
  return /*#__PURE__*/React.createElement("button", {
4885
4981
  key: pageNum,
4886
4982
  className: cn$1("h-8 w-8 rounded-lg md:rounded-md text-sm", {
@@ -4901,29 +4997,31 @@ var Table = function Table(_ref) {
4901
4997
  }
4902
4998
  }, "Next")))));
4903
4999
  };
4904
- function ActionMenuPortal(_ref4) {
4905
- var anchorElem = _ref4.anchorElem,
4906
- anchorRow = _ref4.anchorRow,
4907
- _ref4$actions = _ref4.actions,
4908
- actions = _ref4$actions === void 0 ? [] : _ref4$actions;
4909
- _ref4.onClose;
4910
- var onAction = _ref4.onAction,
4911
- menuRef = _ref4.menuRef;
5000
+
5001
+ // ActionMenuPortal constants
5002
+ var MENU_WIDTH = 180;
5003
+ var MAX_MENU_HEIGHT = 320;
5004
+ var MENU_MARGIN = 8;
5005
+ var MIN_MENU_HEIGHT = 80;
5006
+ function ActionMenuPortal(_ref2) {
5007
+ var anchorElem = _ref2.anchorElem,
5008
+ anchorRow = _ref2.anchorRow,
5009
+ _ref2$actions = _ref2.actions,
5010
+ actions = _ref2$actions === void 0 ? [] : _ref2$actions;
5011
+ _ref2.onClose;
5012
+ var onAction = _ref2.onAction,
5013
+ menuRef = _ref2.menuRef;
4912
5014
  var _useState29 = React.useState({
4913
5015
  left: 0,
4914
5016
  top: 0,
4915
5017
  transformOrigin: "top right",
4916
5018
  maxHeight: 300,
4917
- width: 180,
5019
+ width: MENU_WIDTH,
4918
5020
  opacity: 0
4919
5021
  }),
4920
5022
  _useState30 = _slicedToArray(_useState29, 2),
4921
5023
  style = _useState30[0],
4922
5024
  setStyle = _useState30[1];
4923
- var menuWidth = 180;
4924
- var maxMenuHeight = 320;
4925
- var margin = 8;
4926
- var minMenuHeight = 80;
4927
5025
 
4928
5026
  // compute position using actual menu height (if available) and layout measurements
4929
5027
  var computePosition = function computePosition() {
@@ -4935,17 +5033,17 @@ function ActionMenuPortal(_ref4) {
4935
5033
  var spaceAbove = rect.top;
4936
5034
 
4937
5035
  // allowed max height based on available space
4938
- var allowedMaxHeight = Math.min(maxMenuHeight, Math.max(minMenuHeight, Math.max(spaceBelow - margin, spaceAbove - margin)));
5036
+ var allowedMaxHeight = Math.min(MAX_MENU_HEIGHT, Math.max(MIN_MENU_HEIGHT, Math.max(spaceBelow - MENU_MARGIN, spaceAbove - MENU_MARGIN)));
4939
5037
 
4940
5038
  // choose placement by comparing actual available spaces
4941
5039
  var placement = "bottom";
4942
- if (spaceBelow < 160 && spaceAbove > spaceBelow) {
5040
+ if (spaceBelow < MENU_PLACEMENT_THRESHOLD && spaceAbove > spaceBelow) {
4943
5041
  placement = "top";
4944
5042
  // when placing on top we should cap allowedMaxHeight by spaceAbove
4945
- allowedMaxHeight = Math.min(maxMenuHeight, Math.max(minMenuHeight, spaceAbove - margin));
5043
+ allowedMaxHeight = Math.min(MAX_MENU_HEIGHT, Math.max(MIN_MENU_HEIGHT, spaceAbove - MENU_MARGIN));
4946
5044
  } else {
4947
5045
  // placing bottom: cap by spaceBelow
4948
- allowedMaxHeight = Math.min(maxMenuHeight, Math.max(minMenuHeight, spaceBelow - margin));
5046
+ allowedMaxHeight = Math.min(MAX_MENU_HEIGHT, Math.max(MIN_MENU_HEIGHT, spaceBelow - MENU_MARGIN));
4949
5047
  }
4950
5048
 
4951
5049
  // measure the menu's content height if we can, and compute the actual menu height we'll use.
@@ -4962,23 +5060,23 @@ function ActionMenuPortal(_ref4) {
4962
5060
  var top;
4963
5061
  if (placement === "top") {
4964
5062
  // place menu so its bottom sits just above the anchor (rect.top - margin)
4965
- top = rect.top + scrollY - measuredMenuHeight - margin;
5063
+ top = rect.top + scrollY - measuredMenuHeight - MENU_MARGIN;
4966
5064
  } else {
4967
5065
  // place menu just below the anchor (rect.bottom + margin)
4968
- top = rect.bottom + scrollY + margin;
5066
+ top = rect.bottom + scrollY + MENU_MARGIN;
4969
5067
  }
4970
5068
 
4971
5069
  // clamp top to viewport (so it never goes off-screen)
4972
- var minTop = margin + scrollY;
4973
- var maxTop = window.innerHeight + scrollY - measuredMenuHeight - margin;
5070
+ var minTop = MENU_MARGIN + scrollY;
5071
+ var maxTop = window.innerHeight + scrollY - measuredMenuHeight - MENU_MARGIN;
4974
5072
  if (top < minTop) top = minTop;
4975
5073
  if (top > maxTop) top = maxTop;
4976
5074
 
4977
5075
  // compute left and clamp horizontally
4978
- var left = rect.right + scrollX - menuWidth;
4979
- if (left < margin) left = margin;
4980
- if (left + menuWidth > window.innerWidth - margin) {
4981
- left = Math.max(margin, window.innerWidth - menuWidth - margin);
5076
+ var left = rect.right + scrollX - MENU_WIDTH;
5077
+ if (left < MENU_MARGIN) left = MENU_MARGIN;
5078
+ if (left + MENU_WIDTH > window.innerWidth - MENU_MARGIN) {
5079
+ left = Math.max(MENU_MARGIN, window.innerWidth - MENU_WIDTH - MENU_MARGIN);
4982
5080
  }
4983
5081
  var transformOrigin = placement === "bottom" ? "top right" : "bottom right";
4984
5082
 
@@ -4988,7 +5086,7 @@ function ActionMenuPortal(_ref4) {
4988
5086
  top: top,
4989
5087
  transformOrigin: transformOrigin,
4990
5088
  maxHeight: allowedMaxHeight,
4991
- width: menuWidth,
5089
+ width: MENU_WIDTH,
4992
5090
  opacity: 1
4993
5091
  });
4994
5092
  };