beautiful-grid 1.0.3 → 1.0.4

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/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![NPM version](https://img.shields.io/npm/v/beautiful-grid.svg?style=flat)](https://npmjs.org/package/beautiful-grid)
6
6
  [![NPM downloads](https://img.shields.io/npm/dm/beautiful-grid.svg?style=flat)](https://npmjs.org/package/beautiful-grid)
7
7
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
8
- [![Coverage](https://img.shields.io/badge/coverage-85.02%25-brightgreen.svg)](https://github.com/axisj/beautiful-grid/actions/workflows/tests.yml)
8
+ [![Coverage](https://img.shields.io/badge/coverage-85.63%25-brightgreen.svg)](https://github.com/axisj/beautiful-grid/actions/workflows/tests.yml)
9
9
 
10
10
  BeautifulGrid is a high-performance, feature-packed, and beautifully designed open-source React Data Grid for data-heavy business applications. It combines zero-runtime-CSS styling with virtual scrolling, spreadsheet-like cell selection and clipboard operations, built-in and plugin cell editing, multi-level grouped headers, filtering & sorting toolboxes, server/client pagination, pivot table transforms, row reordering, and flexible theming.
11
11
 
package/cjs/BGrid.js CHANGED
@@ -79,7 +79,7 @@ var utils_1 = require("./utils");
79
79
  var store_1 = require("./store");
80
80
  function BGrid(_a) {
81
81
  var _b, _c, _d;
82
- var width = _a.width, height = _a.height, _e = _a.headerHeight, headerHeight = _e === void 0 ? 30 : _e, footerHeight = _a.footerHeight, _f = _a.summaryHeight, summaryHeight = _f === void 0 ? 30 : _f, _g = _a.itemHeight, itemHeight = _g === void 0 ? 15 : _g, _h = _a.itemPadding, itemPadding = _h === void 0 ? 7 : _h, columns = _a.columns, columnsGroup = _a.columnsGroup, columnGroups = _a.columnGroups, onChangeColumns = _a.onChangeColumns, _j = _a.frozenColumnIndex, frozenColumnIndex = _j === void 0 ? 0 : _j, _k = _a.frozenRowCount, frozenRowCount = _k === void 0 ? 0 : _k, _l = _a.data, data = _l === void 0 ? [] : _l, page = _a.page, scrollbar = _a.scrollbar, status = _a.status, pagination = _a.pagination, bottomBarHeight = _a.bottomBarHeight, _m = _a.scrollTop, scrollTop = _m === void 0 ? 0 : _m, _o = _a.scrollLeft, scrollLeft = _o === void 0 ? 0 : _o, className = _a.className, style = _a.style, rowChecked = _a.rowChecked, sort = _a.sort, onClick = _a.onClick, _p = _a.loading, loading = _p === void 0 ? false : _p, spinning = _a.spinning, rowKey = _a.rowKey, selectedRowKey = _a.selectedRowKey, editable = _a.editable, onChangeData = _a.onChangeData, showLineNumber = _a.showLineNumber, msg = _a.msg, getRowClassName = _a.getRowClassName, _q = _a.editTrigger, editTrigger = _q === void 0 ? 'dblclick' : _q, cellMergeOptions = _a.cellMergeOptions, cellSelectionOptions = _a.cellSelectionOptions, cellNavigationOptions = _a.cellNavigationOptions, variant = _a.variant, summary = _a.summary, columnSortable = _a.columnSortable, reorder = _a.reorder, pivot = _a.pivot, dataControl = _a.dataControl, icons = _a.icons, searchOptions = _a.searchOptions, contextMenuOptions = _a.contextMenuOptions;
82
+ var ref = _a.ref, width = _a.width, height = _a.height, _e = _a.headerHeight, headerHeight = _e === void 0 ? 30 : _e, footerHeight = _a.footerHeight, _f = _a.summaryHeight, summaryHeight = _f === void 0 ? 30 : _f, _g = _a.itemHeight, itemHeight = _g === void 0 ? 15 : _g, _h = _a.itemPadding, itemPadding = _h === void 0 ? 7 : _h, columns = _a.columns, columnsGroup = _a.columnsGroup, columnGroups = _a.columnGroups, onChangeColumns = _a.onChangeColumns, _j = _a.frozenColumnIndex, frozenColumnIndex = _j === void 0 ? 0 : _j, _k = _a.frozenRowCount, frozenRowCount = _k === void 0 ? 0 : _k, _l = _a.data, data = _l === void 0 ? [] : _l, page = _a.page, scrollbar = _a.scrollbar, status = _a.status, pagination = _a.pagination, bottomBarHeight = _a.bottomBarHeight, _m = _a.scrollTop, scrollTop = _m === void 0 ? 0 : _m, _o = _a.scrollLeft, scrollLeft = _o === void 0 ? 0 : _o, className = _a.className, style = _a.style, rowChecked = _a.rowChecked, sort = _a.sort, onClick = _a.onClick, _p = _a.loading, loading = _p === void 0 ? false : _p, spinning = _a.spinning, rowKey = _a.rowKey, selectedRowKey = _a.selectedRowKey, editable = _a.editable, onChangeData = _a.onChangeData, showLineNumber = _a.showLineNumber, msg = _a.msg, getRowClassName = _a.getRowClassName, _q = _a.editTrigger, editTrigger = _q === void 0 ? 'dblclick' : _q, cellMergeOptions = _a.cellMergeOptions, cellSelectionOptions = _a.cellSelectionOptions, cellNavigationOptions = _a.cellNavigationOptions, variant = _a.variant, summary = _a.summary, columnSortable = _a.columnSortable, reorder = _a.reorder, pivot = _a.pivot, dataControl = _a.dataControl, icons = _a.icons, searchOptions = _a.searchOptions, contextMenuOptions = _a.contextMenuOptions;
83
83
  var warnedSearchControlledRef = React.useRef({ open: false, query: false, pivotContextMenu: false });
84
84
  var pivotData = React.useMemo(function () {
85
85
  return (0, utils_1.createPivotData)({
@@ -475,7 +475,7 @@ function BGrid(_a) {
475
475
  initialShowBottomBar,
476
476
  ]);
477
477
  return (React.createElement(store_1.AppStoreProvider, { initialState: initialStoreState },
478
- React.createElement(Table_1.default, { columns: computedColumns,
478
+ React.createElement(Table_1.default, { ref: ref, columns: computedColumns,
479
479
  columnsGroup: resolvedColumnsGroup,
480
480
  columnGroups: resolvedColumnGroups,
481
481
  onChangeColumns: resolvedOnChangeColumns, width: width, height: height, className: className, style: style, loading: loading, spinning: spinning, scrollLeft: scrollLeft, scrollTop: scrollTop, headerHeight: headerHeight, footerHeight: footerHeight, bottomBarHeight: resolvedBottomBarHeight,
@@ -164,11 +164,11 @@ var LazyGridOptionalSurfaces = React.lazy(function () {
164
164
  });
165
165
  function Table(props) {
166
166
  var _this = this;
167
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
167
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5;
168
168
  var cellSelectionOptions = props.cellSelectionOptions, onChangeData = props.onChangeData, sourceIndexByVisibleIndex = props.sourceIndexByVisibleIndex;
169
169
  var cellSelectionEnabled = (_a = cellSelectionOptions === null || cellSelectionOptions === void 0 ? void 0 : cellSelectionOptions.enabled) !== null && _a !== void 0 ? _a : true;
170
170
  // [Selector Group 1] Layout & Dimensions - 레이아웃 차원
171
- var _5 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
171
+ var _6 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
172
172
  width: s.width,
173
173
  height: s.height,
174
174
  containerBorderWidth: s.containerBorderWidth,
@@ -176,30 +176,30 @@ function Table(props) {
176
176
  style: s.style,
177
177
  itemHeight: s.itemHeight,
178
178
  itemPadding: s.itemPadding,
179
- }); })), width = _5.width, height = _5.height, containerBorderWidth = _5.containerBorderWidth, className = _5.className, style = _5.style, itemHeight = _5.itemHeight, itemPadding = _5.itemPadding;
179
+ }); })), width = _6.width, height = _6.height, containerBorderWidth = _6.containerBorderWidth, className = _6.className, style = _6.style, itemHeight = _6.itemHeight, itemPadding = _6.itemPadding;
180
180
  // [Selector Group 2] Header, Footer, Summary - 헤더/푸터/요약
181
- var _6 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
181
+ var _7 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
182
182
  headerHeight: s.headerHeight,
183
183
  footerHeight: s.footerHeight,
184
184
  bottomBarHeight: s.bottomBarHeight,
185
185
  summaryHeight: s.summaryHeight,
186
- }); })), headerHeight = _6.headerHeight, footerHeight = _6.footerHeight, bottomBarHeight = _6.bottomBarHeight, summaryHeight = _6.summaryHeight;
186
+ }); })), headerHeight = _7.headerHeight, footerHeight = _7.footerHeight, bottomBarHeight = _7.bottomBarHeight, summaryHeight = _7.summaryHeight;
187
187
  // [Selector Group 3] Scroll State - 스크롤 상태
188
- var _7 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
188
+ var _8 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
189
189
  scrollLeft: s.scrollLeft,
190
190
  scrollTop: s.scrollTop,
191
- }); })), scrollLeft = _7.scrollLeft, scrollTop = _7.scrollTop;
191
+ }); })), scrollLeft = _8.scrollLeft, scrollTop = _8.scrollTop;
192
192
  // [Selector Group 4] Content, Columns, Data - 컨텐츠 관련
193
- var _8 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
193
+ var _9 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
194
194
  contentBodyHeight: s.contentBodyHeight,
195
195
  columns: s.columns,
196
196
  data: s.data,
197
197
  frozenColumnsWidth: s.frozenColumnsWidth,
198
198
  frozenRowCount: s.frozenRowCount,
199
199
  frozenRowsHeight: s.frozenRowsHeight,
200
- }); })), contentBodyHeight = _8.contentBodyHeight, columns = _8.columns, data = _8.data, frozenColumnsWidth = _8.frozenColumnsWidth, frozenRowCount = _8.frozenRowCount, frozenRowsHeight = _8.frozenRowsHeight;
200
+ }); })), contentBodyHeight = _9.contentBodyHeight, columns = _9.columns, data = _9.data, frozenColumnsWidth = _9.frozenColumnsWidth, frozenRowCount = _9.frozenRowCount, frozenRowsHeight = _9.frozenRowsHeight;
201
201
  // [Selector Group 4-1] Cell selection & navigation - 셀 선택 및 내비게이션
202
- var _9 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
202
+ var _10 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
203
203
  cellSelectionRange: s.cellSelectionRange,
204
204
  cellSelectionRanges: s.cellSelectionRanges,
205
205
  activeCell: s.activeCell,
@@ -208,9 +208,9 @@ function Table(props) {
208
208
  editItemIndex: s.editItemIndex,
209
209
  editable: s.editable,
210
210
  handleClick: s.handleClick,
211
- }); })), cellSelectionRange = _9.cellSelectionRange, cellSelectionRanges = _9.cellSelectionRanges, activeCell = _9.activeCell, activeCellHost = _9.activeCellHost, cellNavigationOptions = _9.cellNavigationOptions, editItemIndex = _9.editItemIndex, editable = _9.editable, handleClick = _9.handleClick;
211
+ }); })), cellSelectionRange = _10.cellSelectionRange, cellSelectionRanges = _10.cellSelectionRanges, activeCell = _10.activeCell, activeCellHost = _10.activeCellHost, cellNavigationOptions = _10.cellNavigationOptions, editItemIndex = _10.editItemIndex, editable = _10.editable, handleClick = _10.handleClick;
212
212
  // [Selector Group 5] State - 상태
213
- var _10 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
213
+ var _11 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
214
214
  rowChecked: s.rowChecked,
215
215
  page: s.page,
216
216
  loading: s.loading,
@@ -220,8 +220,8 @@ function Table(props) {
220
220
  scrollbar: s.scrollbar,
221
221
  status: s.status,
222
222
  pagination: s.pagination,
223
- }); })), rowChecked = _10.rowChecked, page = _10.page, loading = _10.loading, spinning = _10.spinning, showLineNumber = _10.showLineNumber, summary = _10.summary, scrollbar = _10.scrollbar, status = _10.status, pagination = _10.pagination;
224
- var _11 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
223
+ }); })), rowChecked = _11.rowChecked, page = _11.page, loading = _11.loading, spinning = _11.spinning, showLineNumber = _11.showLineNumber, summary = _11.summary, scrollbar = _11.scrollbar, status = _11.status, pagination = _11.pagination;
224
+ var _12 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
225
225
  searchOpen: s.searchOpen,
226
226
  searchOptions: s.searchOptions,
227
227
  contextMenuOptions: s.contextMenuOptions,
@@ -230,9 +230,9 @@ function Table(props) {
230
230
  storeSourceIndexByVisibleIndex: s.sourceIndexByVisibleIndex,
231
231
  storeRowKey: s.rowKey,
232
232
  cellInteractionSession: s.cellInteractionSession,
233
- }); })), searchOpen = _11.searchOpen, searchOptions = _11.searchOptions, contextMenuOptions = _11.contextMenuOptions, activeSearchMatchIndex = _11.activeSearchMatchIndex, searchMatches = _11.searchMatches, storeSourceIndexByVisibleIndex = _11.storeSourceIndexByVisibleIndex, storeRowKey = _11.storeRowKey, cellInteractionSession = _11.cellInteractionSession;
233
+ }); })), searchOpen = _12.searchOpen, searchOptions = _12.searchOptions, contextMenuOptions = _12.contextMenuOptions, activeSearchMatchIndex = _12.activeSearchMatchIndex, searchMatches = _12.searchMatches, storeSourceIndexByVisibleIndex = _12.storeSourceIndexByVisibleIndex, storeRowKey = _12.storeRowKey, cellInteractionSession = _12.cellInteractionSession;
234
234
  // [Selector Group 6] State Setters - 차원 설정자
235
- var _12 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
235
+ var _13 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
236
236
  setHeight: s.setHeight,
237
237
  setWidth: s.setWidth,
238
238
  setContentBodyHeight: s.setContentBodyHeight,
@@ -245,9 +245,9 @@ function Table(props) {
245
245
  setItemPadding: s.setItemPadding,
246
246
  setLoading: s.setLoading,
247
247
  setSpinning: s.setSpinning,
248
- }); })), setHeight = _12.setHeight, setWidth = _12.setWidth, setContentBodyHeight = _12.setContentBodyHeight, setDisplayItemCount = _12.setDisplayItemCount, setHeaderHeight = _12.setHeaderHeight, setFooterHeight = _12.setFooterHeight, setBottomBarHeight = _12.setBottomBarHeight, setSummaryHeight = _12.setSummaryHeight, setItemHeight = _12.setItemHeight, setItemPadding = _12.setItemPadding, setLoading = _12.setLoading, setSpinning = _12.setSpinning;
248
+ }); })), setHeight = _13.setHeight, setWidth = _13.setWidth, setContentBodyHeight = _13.setContentBodyHeight, setDisplayItemCount = _13.setDisplayItemCount, setHeaderHeight = _13.setHeaderHeight, setFooterHeight = _13.setFooterHeight, setBottomBarHeight = _13.setBottomBarHeight, setSummaryHeight = _13.setSummaryHeight, setItemHeight = _13.setItemHeight, setItemPadding = _13.setItemPadding, setLoading = _13.setLoading, setSpinning = _13.setSpinning;
249
249
  // [Selector Group 7] Data & Column Setters - 데이터/열 설정자
250
- var _13 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
250
+ var _14 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
251
251
  setData: s.setData,
252
252
  setSourceData: s.setSourceData,
253
253
  setProcessedData: s.setProcessedData,
@@ -258,9 +258,9 @@ function Table(props) {
258
258
  setFrozenColumnIndex: s.setFrozenColumnIndex,
259
259
  setFrozenRowCount: s.setFrozenRowCount,
260
260
  setFrozenRowsHeight: s.setFrozenRowsHeight,
261
- }); })), setData = _13.setData, setSourceData = _13.setSourceData, setProcessedData = _13.setProcessedData, setColumns = _13.setColumns, setColumnsGroup = _13.setColumnsGroup, setColumnGroups = _13.setColumnGroups, setFrozenColumnsWidth = _13.setFrozenColumnsWidth, setFrozenColumnIndex = _13.setFrozenColumnIndex, setFrozenRowCount = _13.setFrozenRowCount, setFrozenRowsHeight = _13.setFrozenRowsHeight;
261
+ }); })), setData = _14.setData, setSourceData = _14.setSourceData, setProcessedData = _14.setProcessedData, setColumns = _14.setColumns, setColumnsGroup = _14.setColumnsGroup, setColumnGroups = _14.setColumnGroups, setFrozenColumnsWidth = _14.setFrozenColumnsWidth, setFrozenColumnIndex = _14.setFrozenColumnIndex, setFrozenRowCount = _14.setFrozenRowCount, setFrozenRowsHeight = _14.setFrozenRowsHeight;
262
262
  // [Selector Group 8] Row & Sort Setters - 행/정렬 설정자
263
- var _14 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
263
+ var _15 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
264
264
  setRowChecked: s.setRowChecked,
265
265
  setCheckedIndexesMap: s.setCheckedIndexesMap,
266
266
  setSort: s.setSort,
@@ -277,9 +277,9 @@ function Table(props) {
277
277
  requestSearchOpen: s.requestSearchOpen,
278
278
  openContextMenu: s.openContextMenu,
279
279
  commitCheckboxCell: s.commitCheckboxCell,
280
- }); })), setRowChecked = _14.setRowChecked, setCheckedIndexesMap = _14.setCheckedIndexesMap, setSort = _14.setSort, setSortParams = _14.setSortParams, setDataQuery = _14.setDataQuery, setDataControl = _14.setDataControl, setIcons = _14.setIcons, setActiveToolbox = _14.setActiveToolbox, setRowKey = _14.setRowKey, setFocusedRowKey = _14.setFocusedRowKey, setEditItem = _14.setEditItem, setSearchOptions = _14.setSearchOptions, setContextMenuOptions = _14.setContextMenuOptions, requestSearchOpen = _14.requestSearchOpen, openContextMenu = _14.openContextMenu, commitCheckboxCell = _14.commitCheckboxCell;
280
+ }); })), setRowChecked = _15.setRowChecked, setCheckedIndexesMap = _15.setCheckedIndexesMap, setSort = _15.setSort, setSortParams = _15.setSortParams, setDataQuery = _15.setDataQuery, setDataControl = _15.setDataControl, setIcons = _15.setIcons, setActiveToolbox = _15.setActiveToolbox, setRowKey = _15.setRowKey, setFocusedRowKey = _15.setFocusedRowKey, setEditItem = _15.setEditItem, setSearchOptions = _15.setSearchOptions, setContextMenuOptions = _15.setContextMenuOptions, requestSearchOpen = _15.requestSearchOpen, openContextMenu = _15.openContextMenu, commitCheckboxCell = _15.commitCheckboxCell;
281
281
  // [Selector Group 9] Pagination & Display Setters - 페이지/표시 설정자
282
- var _15 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
282
+ var _16 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
283
283
  setPage: s.setPage,
284
284
  setDisplayPaginationLength: s.setDisplayPaginationLength,
285
285
  setShowLineNumber: s.setShowLineNumber,
@@ -295,9 +295,9 @@ function Table(props) {
295
295
  setScrollbar: s.setScrollbar,
296
296
  setStatus: s.setStatus,
297
297
  setPagination: s.setPagination,
298
- }); })), setPage = _15.setPage, setDisplayPaginationLength = _15.setDisplayPaginationLength, setShowLineNumber = _15.setShowLineNumber, setMsg = _15.setMsg, setRowClassName = _15.setRowClassName, setCellMergeOptions = _15.setCellMergeOptions, setVariant = _15.setVariant, setSummary = _15.setSummary, setColumnSortable = _15.setColumnSortable, setReorder = _15.setReorder, setClassName = _15.setClassName, setStyle = _15.setStyle, setScrollbar = _15.setScrollbar, setStatus = _15.setStatus, setPagination = _15.setPagination;
298
+ }); })), setPage = _16.setPage, setDisplayPaginationLength = _16.setDisplayPaginationLength, setShowLineNumber = _16.setShowLineNumber, setMsg = _16.setMsg, setRowClassName = _16.setRowClassName, setCellMergeOptions = _16.setCellMergeOptions, setVariant = _16.setVariant, setSummary = _16.setSummary, setColumnSortable = _16.setColumnSortable, setReorder = _16.setReorder, setClassName = _16.setClassName, setStyle = _16.setStyle, setScrollbar = _16.setScrollbar, setStatus = _16.setStatus, setPagination = _16.setPagination;
299
299
  // [Selector Group 10] Edit & Event Setters - 편집/이벤트 설정자
300
- var _16 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
300
+ var _17 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
301
301
  setEditable: s.setEditable,
302
302
  setEditTrigger: s.setEditTrigger,
303
303
  setOnClick: s.setOnClick,
@@ -306,8 +306,8 @@ function Table(props) {
306
306
  setOnLoadMore: s.setOnLoadMore,
307
307
  setScroll: s.setScroll,
308
308
  setInitialized: s.setInitialized,
309
- }); })), setEditable = _16.setEditable, setEditTrigger = _16.setEditTrigger, setOnClick = _16.setOnClick, setOnChangeColumns = _16.setOnChangeColumns, setOnChangeData = _16.setOnChangeData, setOnLoadMore = _16.setOnLoadMore, setScroll = _16.setScroll, setInitialized = _16.setInitialized;
310
- var _17 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
309
+ }); })), setEditable = _17.setEditable, setEditTrigger = _17.setEditTrigger, setOnClick = _17.setOnClick, setOnChangeColumns = _17.setOnChangeColumns, setOnChangeData = _17.setOnChangeData, setOnLoadMore = _17.setOnLoadMore, setScroll = _17.setScroll, setInitialized = _17.setInitialized;
310
+ var _18 = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
311
311
  setCellSelectionRanges: s.setCellSelectionRanges,
312
312
  setCellSelecting: s.setCellSelecting,
313
313
  clearCellSelection: s.clearCellSelection,
@@ -315,7 +315,7 @@ function Table(props) {
315
315
  moveActiveCell: s.moveActiveCell,
316
316
  setCellNavigationOptions: s.setCellNavigationOptions,
317
317
  syncActiveCellToBounds: s.syncActiveCellToBounds,
318
- }); })), setCellSelectionRanges = _17.setCellSelectionRanges, setCellSelecting = _17.setCellSelecting, clearCellSelection = _17.clearCellSelection, setActiveCell = _17.setActiveCell, moveActiveCell = _17.moveActiveCell, setCellNavigationOptions = _17.setCellNavigationOptions, syncActiveCellToBounds = _17.syncActiveCellToBounds;
318
+ }); })), setCellSelectionRanges = _18.setCellSelectionRanges, setCellSelecting = _18.setCellSelecting, clearCellSelection = _18.clearCellSelection, setActiveCell = _18.setActiveCell, moveActiveCell = _18.moveActiveCell, setCellNavigationOptions = _18.setCellNavigationOptions, syncActiveCellToBounds = _18.syncActiveCellToBounds;
319
319
  var trHeight = itemHeight + itemPadding * 2;
320
320
  var scrollableBodyHeight = Math.max(contentBodyHeight - frozenRowsHeight, 0);
321
321
  var mainViewportWidth = Math.max(width - (frozenColumnsWidth !== null && frozenColumnsWidth !== void 0 ? frozenColumnsWidth : 0), 0);
@@ -327,7 +327,7 @@ function Table(props) {
327
327
  enabled: scrollbar.variant !== 'native',
328
328
  });
329
329
  }, [contentBodyHeight, logicalBodyContentHeight, scrollbar.variant]);
330
- var _18 = __read(React.useState(0), 2), virtualScrollBase = _18[0], setVirtualScrollBase = _18[1];
330
+ var _19 = __read(React.useState(0), 2), virtualScrollBase = _19[0], setVirtualScrollBase = _19[1];
331
331
  var virtualScrollBaseRef = (0, react_1.useRef)(0);
332
332
  var containerRef = (0, react_1.useRef)(null);
333
333
  var searchPopoverRef = (0, react_1.useRef)(null);
@@ -617,6 +617,15 @@ function Table(props) {
617
617
  }, []);
618
618
  var latestScrollRef = (0, react_1.useRef)({ top: scrollTop, left: scrollLeft });
619
619
  var latestCommittedScrollRef = (0, react_1.useRef)({ top: scrollTop, left: scrollLeft });
620
+ var scrollPropsRef = (0, react_1.useRef)({ top: props.scrollTop, left: props.scrollLeft });
621
+ var syncedDataPropRef = (0, react_1.useRef)(props.data);
622
+ var _20 = __read(React.useState(null), 2), rowScrollRequest = _20[0], setRowScrollRequest = _20[1];
623
+ React.useImperativeHandle(props.ref, function () { return ({
624
+ scrollToRow: function (rowIndex, options) {
625
+ var _a;
626
+ setRowScrollRequest({ rowIndex: rowIndex, align: (_a = options === null || options === void 0 ? void 0 : options.align) !== null && _a !== void 0 ? _a : 'nearest' });
627
+ },
628
+ }); }, []);
620
629
  var scrollRafRef = (0, react_1.useRef)(null);
621
630
  var scrollIdleTimerRef = (0, react_1.useRef)(null);
622
631
  var selectionAutoScrollRafRef = (0, react_1.useRef)(null);
@@ -1525,6 +1534,7 @@ function Table(props) {
1525
1534
  setSourceData(props.sourceData);
1526
1535
  }
1527
1536
  }
1537
+ syncedDataPropRef.current = props.data;
1528
1538
  }, [
1529
1539
  props.data,
1530
1540
  props.sourceData,
@@ -1605,9 +1615,13 @@ function Table(props) {
1605
1615
  setPage,
1606
1616
  setDisplayPaginationLength,
1607
1617
  ]);
1618
+ var previousPageRef = (0, react_1.useRef)((_o = props.page) === null || _o === void 0 ? void 0 : _o.currentPage);
1608
1619
  (0, react_1.useEffect)(function () {
1609
- resetScrollPosition('top');
1610
- }, [resetScrollPosition, (_o = props.page) === null || _o === void 0 ? void 0 : _o.currentPage]);
1620
+ var _a, _b;
1621
+ if (previousPageRef.current !== ((_a = props.page) === null || _a === void 0 ? void 0 : _a.currentPage))
1622
+ resetScrollPosition('top');
1623
+ previousPageRef.current = (_b = props.page) === null || _b === void 0 ? void 0 : _b.currentPage;
1624
+ }, [resetScrollPosition, (_p = props.page) === null || _p === void 0 ? void 0 : _p.currentPage]);
1611
1625
  // [Group 8] Row key & selection
1612
1626
  (0, react_1.useEffect)(function () {
1613
1627
  setRowKey(props.rowKey);
@@ -1679,10 +1693,10 @@ function Table(props) {
1679
1693
  }, [
1680
1694
  columns.length,
1681
1695
  data.length,
1682
- (_q = (_p = props.cellNavigationOptions) === null || _p === void 0 ? void 0 : _p.activeCell) === null || _q === void 0 ? void 0 : _q.columnIndex,
1683
- (_s = (_r = props.cellNavigationOptions) === null || _r === void 0 ? void 0 : _r.activeCell) === null || _s === void 0 ? void 0 : _s.rowIndex,
1684
- (_u = (_t = props.cellNavigationOptions) === null || _t === void 0 ? void 0 : _t.defaultActiveCell) === null || _u === void 0 ? void 0 : _u.columnIndex,
1685
- (_w = (_v = props.cellNavigationOptions) === null || _v === void 0 ? void 0 : _v.defaultActiveCell) === null || _w === void 0 ? void 0 : _w.rowIndex,
1696
+ (_r = (_q = props.cellNavigationOptions) === null || _q === void 0 ? void 0 : _q.activeCell) === null || _r === void 0 ? void 0 : _r.columnIndex,
1697
+ (_t = (_s = props.cellNavigationOptions) === null || _s === void 0 ? void 0 : _s.activeCell) === null || _t === void 0 ? void 0 : _t.rowIndex,
1698
+ (_v = (_u = props.cellNavigationOptions) === null || _u === void 0 ? void 0 : _u.defaultActiveCell) === null || _v === void 0 ? void 0 : _v.columnIndex,
1699
+ (_x = (_w = props.cellNavigationOptions) === null || _w === void 0 ? void 0 : _w.defaultActiveCell) === null || _x === void 0 ? void 0 : _x.rowIndex,
1686
1700
  syncActiveCellToBounds,
1687
1701
  ]);
1688
1702
  // setInitialized + DOM event bindings
@@ -1691,7 +1705,7 @@ function Table(props) {
1691
1705
  var containerRefCurrent = containerRef.current;
1692
1706
  var scrollContainerRefCurrent = scrollContainerRef === null || scrollContainerRef === void 0 ? void 0 : scrollContainerRef.current;
1693
1707
  if (scrollContainerRefCurrent) {
1694
- scrollContainerRefCurrent.removeEventListener('scroll', onScroll);
1708
+ scrollContainerRefCurrent.removeEventListener('scroll', onScroll, true);
1695
1709
  scrollContainerRefCurrent.addEventListener('scroll', onScroll, { passive: true, capture: true });
1696
1710
  }
1697
1711
  return function () {
@@ -1704,17 +1718,55 @@ function Table(props) {
1704
1718
  scrollIdleTimerRef.current = null;
1705
1719
  }
1706
1720
  containerRefCurrent === null || containerRefCurrent === void 0 ? void 0 : containerRefCurrent.removeAttribute('data-bgrid-scrolling');
1707
- scrollContainerRefCurrent === null || scrollContainerRefCurrent === void 0 ? void 0 : scrollContainerRefCurrent.removeEventListener('scroll', onScroll);
1721
+ scrollContainerRefCurrent === null || scrollContainerRefCurrent === void 0 ? void 0 : scrollContainerRefCurrent.removeEventListener('scroll', onScroll, true);
1708
1722
  };
1709
1723
  }, [onScroll, setInitialized]);
1710
1724
  React.useLayoutEffect(function () {
1711
1725
  var _a, _b;
1712
1726
  if (!scrollContainerRef.current)
1713
1727
  return;
1714
- var nextTop = (_a = props.scrollTop) !== null && _a !== void 0 ? _a : latestScrollRef.current.top;
1715
- var nextLeft = (_b = props.scrollLeft) !== null && _b !== void 0 ? _b : latestScrollRef.current.left;
1728
+ if (props.data !== syncedDataPropRef.current)
1729
+ return;
1730
+ // Resizing or changing the data also changes commitScroll. Only a changed
1731
+ // scroll prop should override the user's current position.
1732
+ var nextTop = props.scrollTop !== scrollPropsRef.current.top
1733
+ ? (_a = props.scrollTop) !== null && _a !== void 0 ? _a : latestScrollRef.current.top
1734
+ : latestScrollRef.current.top;
1735
+ var nextLeft = props.scrollLeft !== scrollPropsRef.current.left
1736
+ ? (_b = props.scrollLeft) !== null && _b !== void 0 ? _b : latestScrollRef.current.left
1737
+ : latestScrollRef.current.left;
1738
+ scrollPropsRef.current = { top: props.scrollTop, left: props.scrollLeft };
1716
1739
  commitScroll(nextTop, nextLeft);
1717
- }, [commitScroll, props.scrollLeft, props.scrollTop]);
1740
+ }, [commitScroll, data, props.data, props.scrollLeft, props.scrollTop]);
1741
+ React.useLayoutEffect(function () {
1742
+ if (!rowScrollRequest)
1743
+ return;
1744
+ // Prop data reaches the per-grid store in an effect. Wait for that render
1745
+ // so appending a row and requesting it in the same event is supported.
1746
+ if (props.data !== syncedDataPropRef.current)
1747
+ return;
1748
+ setRowScrollRequest(null);
1749
+ var rowIndex = rowScrollRequest.rowIndex, align = rowScrollRequest.align;
1750
+ if (!Number.isInteger(rowIndex) || rowIndex < frozenRowCount || rowIndex >= data.length)
1751
+ return;
1752
+ if (scrollableBodyHeight <= 0)
1753
+ return;
1754
+ var rowTop = (rowIndex - frozenRowCount) * trHeight;
1755
+ var rowBottom = rowTop + trHeight;
1756
+ var _a = latestScrollRef.current, top = _a.top, left = _a.left;
1757
+ var nextTop = top;
1758
+ if (align === 'start')
1759
+ nextTop = rowTop;
1760
+ else if (align === 'center')
1761
+ nextTop = rowTop - (scrollableBodyHeight - trHeight) / 2;
1762
+ else if (align === 'end')
1763
+ nextTop = rowBottom - scrollableBodyHeight;
1764
+ else if (rowTop < top)
1765
+ nextTop = rowTop;
1766
+ else if (rowBottom > top + scrollableBodyHeight)
1767
+ nextTop = rowBottom - scrollableBodyHeight;
1768
+ commitScroll(nextTop, left);
1769
+ }, [commitScroll, data, frozenRowCount, props.data, rowScrollRequest, scrollableBodyHeight, trHeight]);
1718
1770
  (0, react_1.useEffect)(function () {
1719
1771
  latestScrollRef.current = { top: scrollTop, left: scrollLeft };
1720
1772
  latestCommittedScrollRef.current = { top: scrollTop, left: scrollLeft };
@@ -1766,8 +1818,8 @@ function Table(props) {
1766
1818
  endCellSelectionDrag();
1767
1819
  clearCellSelection();
1768
1820
  }, [cellSelectionEnabled, clearCellSelection, endCellSelectionDrag]);
1769
- var clearCellSelectionOnEscape = (_y = (_x = props.cellSelectionOptions) === null || _x === void 0 ? void 0 : _x.clearOnEscape) !== null && _y !== void 0 ? _y : true;
1770
- var clearCellSelectionOnOutsideClick = (_0 = (_z = props.cellSelectionOptions) === null || _z === void 0 ? void 0 : _z.clearOnOutsideClick) !== null && _0 !== void 0 ? _0 : true;
1821
+ var clearCellSelectionOnEscape = (_z = (_y = props.cellSelectionOptions) === null || _y === void 0 ? void 0 : _y.clearOnEscape) !== null && _z !== void 0 ? _z : true;
1822
+ var clearCellSelectionOnOutsideClick = (_1 = (_0 = props.cellSelectionOptions) === null || _0 === void 0 ? void 0 : _0.clearOnOutsideClick) !== null && _1 !== void 0 ? _1 : true;
1771
1823
  var keyboardRuntimeRef = (0, react_1.useRef)({
1772
1824
  activeCell: activeCell,
1773
1825
  cellInteractionSession: cellInteractionSession,
@@ -1785,7 +1837,7 @@ function Table(props) {
1785
1837
  editable: editable,
1786
1838
  editItemIndex: editItemIndex,
1787
1839
  endCellSelectionDrag: endCellSelectionDrag,
1788
- frozenColumnIndex: (_1 = props.frozenColumnIndex) !== null && _1 !== void 0 ? _1 : 0,
1840
+ frozenColumnIndex: (_2 = props.frozenColumnIndex) !== null && _2 !== void 0 ? _2 : 0,
1789
1841
  frozenRowCount: frozenRowCount,
1790
1842
  height: height,
1791
1843
  handleClick: handleClick,
@@ -1818,7 +1870,7 @@ function Table(props) {
1818
1870
  editable: editable,
1819
1871
  editItemIndex: editItemIndex,
1820
1872
  endCellSelectionDrag: endCellSelectionDrag,
1821
- frozenColumnIndex: (_2 = props.frozenColumnIndex) !== null && _2 !== void 0 ? _2 : 0,
1873
+ frozenColumnIndex: (_3 = props.frozenColumnIndex) !== null && _3 !== void 0 ? _3 : 0,
1822
1874
  frozenRowCount: frozenRowCount,
1823
1875
  height: height,
1824
1876
  handleClick: handleClick,
@@ -2207,7 +2259,7 @@ function Table(props) {
2207
2259
  if (gateway instanceof HTMLInputElement) {
2208
2260
  gateway.focus({ preventScroll: true });
2209
2261
  }
2210
- }, "data-scroll-variant": scrollbar.variant, "data-vertical-scrollbar": scrollbar.variant !== 'native' && scrollbar.vertical.visible ? 'visible' : 'hidden', "data-bgrid-cell-selection-enabled": cellSelectionEnabled ? 'true' : 'false', "data-bgrid-frozen-columns": ((_3 = props.frozenColumnIndex) !== null && _3 !== void 0 ? _3 : 0) > 0 ? 'true' : 'false' },
2262
+ }, "data-scroll-variant": scrollbar.variant, "data-vertical-scrollbar": scrollbar.variant !== 'native' && scrollbar.vertical.visible ? 'visible' : 'hidden', "data-bgrid-cell-selection-enabled": cellSelectionEnabled ? 'true' : 'false', "data-bgrid-frozen-columns": ((_4 = props.frozenColumnIndex) !== null && _4 !== void 0 ? _4 : 0) > 0 ? 'true' : 'false' },
2211
2263
  scrollbar.variant !== 'native' && scrollbar.vertical.visible && (React.createElement("div", { className: 'bgrid-vertical-scrollbar-gutter', "aria-hidden": 'true' })),
2212
2264
  scrollbar.variant !== 'native' && scrollbar.vertical.visible && (React.createElement("div", { className: 'bgrid-vertical-scrollbar-area', style: {
2213
2265
  top: 0,
@@ -2266,7 +2318,7 @@ function Table(props) {
2266
2318
  React.createElement(Summary, { style: { left: frozenColumnsWidth }, role: 'rfdg-summary' },
2267
2319
  React.createElement(TableSummary_1.TableSummary, { position: 'bottom' })))))),
2268
2320
  React.createElement(BodyViewport, { ref: bodyContainerRef, style: { top: stickyTopHeight, height: contentBodyHeight }, "data-last": !page ? 'true' : undefined },
2269
- ((_4 = rowReorderController.preview) === null || _4 === void 0 ? void 0 : _4.visible) && (React.createElement("div", { className: 'bgrid-row-reorder-preview', "data-bgrid-row-reorder-phase": rowReorderController.preview.phase, "aria-hidden": 'true' }, rowReorderController.preview.text)),
2321
+ ((_5 = rowReorderController.preview) === null || _5 === void 0 ? void 0 : _5.visible) && (React.createElement("div", { className: 'bgrid-row-reorder-preview', "data-bgrid-row-reorder-phase": rowReorderController.preview.phase, "aria-hidden": 'true' }, rowReorderController.preview.text)),
2270
2322
  React.createElement(Loading_1.default, { active: !!spinning, size: 'small' })),
2271
2323
  React.createElement("div", { className: 'bgrid-visually-hidden', role: 'status', "aria-live": 'polite', "aria-atomic": 'true' }, rowReorderController.announcement),
2272
2324
  React.createElement(CellTextEditorGateway_1.CellTextEditorGateway, { containerRef: containerRef }),
package/esm/BGrid.js CHANGED
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import Table from './components/Table';
3
3
  import { createPivotData, buildHeaderMatrix, findDuplicateColumnIds, getCellValueByRowKey, getColumnId, getColumnKeyToken, getFrozenColumnsWidth, processDataQuery, resolveStatusOptions, resolvePaginationViewOptions, resolveScrollbarOptions, shouldRenderBottomBar, } from './utils';
4
4
  import { AppStoreProvider } from './store';
5
- export function BGrid({ width, height, headerHeight = 30, footerHeight, summaryHeight = 30, itemHeight = 15, itemPadding = 7, columns, columnsGroup, columnGroups, onChangeColumns, frozenColumnIndex = 0, frozenRowCount = 0, data = [], page, scrollbar, status, pagination, bottomBarHeight, scrollTop = 0, scrollLeft = 0, className, style, rowChecked, sort, onClick, loading = false, spinning, rowKey, selectedRowKey, editable, onChangeData, showLineNumber, msg, getRowClassName, editTrigger = 'dblclick', cellMergeOptions, cellSelectionOptions, cellNavigationOptions, variant, summary, columnSortable, reorder, pivot, dataControl, icons, searchOptions, contextMenuOptions, }) {
5
+ export function BGrid({ ref, width, height, headerHeight = 30, footerHeight, summaryHeight = 30, itemHeight = 15, itemPadding = 7, columns, columnsGroup, columnGroups, onChangeColumns, frozenColumnIndex = 0, frozenRowCount = 0, data = [], page, scrollbar, status, pagination, bottomBarHeight, scrollTop = 0, scrollLeft = 0, className, style, rowChecked, sort, onClick, loading = false, spinning, rowKey, selectedRowKey, editable, onChangeData, showLineNumber, msg, getRowClassName, editTrigger = 'dblclick', cellMergeOptions, cellSelectionOptions, cellNavigationOptions, variant, summary, columnSortable, reorder, pivot, dataControl, icons, searchOptions, contextMenuOptions, }) {
6
6
  const warnedSearchControlledRef = React.useRef({ open: false, query: false, pivotContextMenu: false });
7
7
  const pivotData = React.useMemo(() => {
8
8
  return createPivotData({
@@ -410,7 +410,7 @@ export function BGrid({ width, height, headerHeight = 30, footerHeight, summaryH
410
410
  initialShowBottomBar,
411
411
  ]);
412
412
  return (React.createElement(AppStoreProvider, { initialState: initialStoreState },
413
- React.createElement(Table, { columns: computedColumns,
413
+ React.createElement(Table, { ref: ref, columns: computedColumns,
414
414
  columnsGroup: resolvedColumnsGroup,
415
415
  columnGroups: resolvedColumnGroups,
416
416
  onChangeColumns: resolvedOnChangeColumns,
@@ -465,6 +465,14 @@ function Table(props) {
465
465
  }, []);
466
466
  const latestScrollRef = useRef({ top: scrollTop, left: scrollLeft });
467
467
  const latestCommittedScrollRef = useRef({ top: scrollTop, left: scrollLeft });
468
+ const scrollPropsRef = useRef({ top: props.scrollTop, left: props.scrollLeft });
469
+ const syncedDataPropRef = useRef(props.data);
470
+ const [rowScrollRequest, setRowScrollRequest] = React.useState(null);
471
+ React.useImperativeHandle(props.ref, () => ({
472
+ scrollToRow(rowIndex, options) {
473
+ setRowScrollRequest({ rowIndex, align: options?.align ?? 'nearest' });
474
+ },
475
+ }), []);
468
476
  const scrollRafRef = useRef(null);
469
477
  const scrollIdleTimerRef = useRef(null);
470
478
  const selectionAutoScrollRafRef = useRef(null);
@@ -1333,6 +1341,7 @@ function Table(props) {
1333
1341
  setSourceData(props.sourceData);
1334
1342
  }
1335
1343
  }
1344
+ syncedDataPropRef.current = props.data;
1336
1345
  }, [
1337
1346
  props.data,
1338
1347
  props.sourceData,
@@ -1411,8 +1420,11 @@ function Table(props) {
1411
1420
  setPage,
1412
1421
  setDisplayPaginationLength,
1413
1422
  ]);
1423
+ const previousPageRef = useRef(props.page?.currentPage);
1414
1424
  useEffect(() => {
1415
- resetScrollPosition('top');
1425
+ if (previousPageRef.current !== props.page?.currentPage)
1426
+ resetScrollPosition('top');
1427
+ previousPageRef.current = props.page?.currentPage;
1416
1428
  }, [resetScrollPosition, props.page?.currentPage]);
1417
1429
  // [Group 8] Row key & selection
1418
1430
  useEffect(() => {
@@ -1497,7 +1509,7 @@ function Table(props) {
1497
1509
  const containerRefCurrent = containerRef.current;
1498
1510
  const scrollContainerRefCurrent = scrollContainerRef?.current;
1499
1511
  if (scrollContainerRefCurrent) {
1500
- scrollContainerRefCurrent.removeEventListener('scroll', onScroll);
1512
+ scrollContainerRefCurrent.removeEventListener('scroll', onScroll, true);
1501
1513
  scrollContainerRefCurrent.addEventListener('scroll', onScroll, { passive: true, capture: true });
1502
1514
  }
1503
1515
  return () => {
@@ -1510,16 +1522,54 @@ function Table(props) {
1510
1522
  scrollIdleTimerRef.current = null;
1511
1523
  }
1512
1524
  containerRefCurrent?.removeAttribute('data-bgrid-scrolling');
1513
- scrollContainerRefCurrent?.removeEventListener('scroll', onScroll);
1525
+ scrollContainerRefCurrent?.removeEventListener('scroll', onScroll, true);
1514
1526
  };
1515
1527
  }, [onScroll, setInitialized]);
1516
1528
  React.useLayoutEffect(() => {
1517
1529
  if (!scrollContainerRef.current)
1518
1530
  return;
1519
- const nextTop = props.scrollTop ?? latestScrollRef.current.top;
1520
- const nextLeft = props.scrollLeft ?? latestScrollRef.current.left;
1531
+ if (props.data !== syncedDataPropRef.current)
1532
+ return;
1533
+ // Resizing or changing the data also changes commitScroll. Only a changed
1534
+ // scroll prop should override the user's current position.
1535
+ const nextTop = props.scrollTop !== scrollPropsRef.current.top
1536
+ ? props.scrollTop ?? latestScrollRef.current.top
1537
+ : latestScrollRef.current.top;
1538
+ const nextLeft = props.scrollLeft !== scrollPropsRef.current.left
1539
+ ? props.scrollLeft ?? latestScrollRef.current.left
1540
+ : latestScrollRef.current.left;
1541
+ scrollPropsRef.current = { top: props.scrollTop, left: props.scrollLeft };
1521
1542
  commitScroll(nextTop, nextLeft);
1522
- }, [commitScroll, props.scrollLeft, props.scrollTop]);
1543
+ }, [commitScroll, data, props.data, props.scrollLeft, props.scrollTop]);
1544
+ React.useLayoutEffect(() => {
1545
+ if (!rowScrollRequest)
1546
+ return;
1547
+ // Prop data reaches the per-grid store in an effect. Wait for that render
1548
+ // so appending a row and requesting it in the same event is supported.
1549
+ if (props.data !== syncedDataPropRef.current)
1550
+ return;
1551
+ setRowScrollRequest(null);
1552
+ const { rowIndex, align } = rowScrollRequest;
1553
+ if (!Number.isInteger(rowIndex) || rowIndex < frozenRowCount || rowIndex >= data.length)
1554
+ return;
1555
+ if (scrollableBodyHeight <= 0)
1556
+ return;
1557
+ const rowTop = (rowIndex - frozenRowCount) * trHeight;
1558
+ const rowBottom = rowTop + trHeight;
1559
+ const { top, left } = latestScrollRef.current;
1560
+ let nextTop = top;
1561
+ if (align === 'start')
1562
+ nextTop = rowTop;
1563
+ else if (align === 'center')
1564
+ nextTop = rowTop - (scrollableBodyHeight - trHeight) / 2;
1565
+ else if (align === 'end')
1566
+ nextTop = rowBottom - scrollableBodyHeight;
1567
+ else if (rowTop < top)
1568
+ nextTop = rowTop;
1569
+ else if (rowBottom > top + scrollableBodyHeight)
1570
+ nextTop = rowBottom - scrollableBodyHeight;
1571
+ commitScroll(nextTop, left);
1572
+ }, [commitScroll, data, frozenRowCount, props.data, rowScrollRequest, scrollableBodyHeight, trHeight]);
1523
1573
  useEffect(() => {
1524
1574
  latestScrollRef.current = { top: scrollTop, left: scrollLeft };
1525
1575
  latestCommittedScrollRef.current = { top: scrollTop, left: scrollLeft };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beautiful-grid",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "A beautiful, powerful, open-source React Data Grid.",
5
5
  "homepage": "https://bgrid.axisj.com",
6
6
  "bugs": {
package/types/BGrid.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  import * as React from 'react';
2
2
  import { BGridProps } from './types';
3
- export declare function BGrid<T = Record<string, any>>({ width, height, headerHeight, footerHeight, summaryHeight, itemHeight, itemPadding, columns, columnsGroup, columnGroups, onChangeColumns, frozenColumnIndex, frozenRowCount, data, page, scrollbar, status, pagination, bottomBarHeight, scrollTop, scrollLeft, className, style, rowChecked, sort, onClick, loading, spinning, rowKey, selectedRowKey, editable, onChangeData, showLineNumber, msg, getRowClassName, editTrigger, cellMergeOptions, cellSelectionOptions, cellNavigationOptions, variant, summary, columnSortable, reorder, pivot, dataControl, icons, searchOptions, contextMenuOptions, }: BGridProps<T>): React.JSX.Element;
3
+ export declare function BGrid<T = Record<string, any>>({ ref, width, height, headerHeight, footerHeight, summaryHeight, itemHeight, itemPadding, columns, columnsGroup, columnGroups, onChangeColumns, frozenColumnIndex, frozenRowCount, data, page, scrollbar, status, pagination, bottomBarHeight, scrollTop, scrollLeft, className, style, rowChecked, sort, onClick, loading, spinning, rowKey, selectedRowKey, editable, onChangeData, showLineNumber, msg, getRowClassName, editTrigger, cellMergeOptions, cellSelectionOptions, cellNavigationOptions, variant, summary, columnSortable, reorder, pivot, dataControl, icons, searchOptions, contextMenuOptions, }: BGridProps<T>): React.JSX.Element;
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { Key } from 'react';
3
3
  import { BGridCellNavigationOptions, AppModelColumn, BGridColumnGroup, BGridColumnGroupNode, BGridDataControl, BGridDataItem, BGridDataQuery, BGridPage, BGridProps, BGridRowChecked, BGridSortInfo, BGridSortParam, BGridResolvedScrollbarOptions, BGridResolvedStatusOptions, BGridResolvedPaginationViewOptions } from '../types';
4
4
  interface Props<T> {
5
+ ref?: BGridProps<T>['ref'];
5
6
  width?: number;
6
7
  height?: number;
7
8
  headerHeight?: number;
package/types/types.d.ts CHANGED
@@ -619,7 +619,20 @@ export interface BGridResolvedStatusOptions extends BGridStatusOptions {
619
619
  configured: boolean;
620
620
  }
621
621
  export type BGridResolvedPaginationViewOptions = Required<Pick<BGridPaginationViewOptions, 'visible'>> & Omit<BGridPaginationViewOptions, 'visible'>;
622
+ export interface BGridScrollToRowOptions {
623
+ /** Defaults to nearest: scroll only as far as needed to reveal the row. */
624
+ align?: 'start' | 'center' | 'end' | 'nearest';
625
+ }
626
+ export interface BGridRef {
627
+ /**
628
+ * Reveal a zero-based row in the displayed (sorted/filtered) data on the current page.
629
+ * Runs after pending data updates. Invalid indexes and frozen rows are ignored.
630
+ * Preserves horizontal scroll, cell focus and selection; does not load other pages.
631
+ */
632
+ scrollToRow: (rowIndex: number, options?: BGridScrollToRowOptions) => void;
633
+ }
622
634
  export interface BGridProps<T> {
635
+ ref?: React.Ref<BGridRef>;
623
636
  width: number;
624
637
  height: number;
625
638
  headerHeight?: number;