beautiful-grid 1.0.5 → 1.0.7

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.
Files changed (39) hide show
  1. package/README.md +47 -4
  2. package/cjs/BGrid.js +178 -50
  3. package/cjs/components/ColResizer.js +8 -3
  4. package/cjs/components/Pagination.js +8 -5
  5. package/cjs/components/Table.js +71 -41
  6. package/cjs/components/TableBody.js +10 -15
  7. package/cjs/components/TableHead.js +6 -8
  8. package/cjs/components/TableHeadColumn.js +23 -18
  9. package/cjs/components/TableHeadFrozen.js +7 -9
  10. package/cjs/components/toolbox/TableHeadToolbox.js +8 -3
  11. package/cjs/components/toolbox/ToolboxColumnVisibilitySection.js +131 -0
  12. package/cjs/components/toolbox/index.js +1 -0
  13. package/cjs/store/createAppStore.js +111 -27
  14. package/cjs/utils/columnVisibility.js +114 -0
  15. package/cjs/utils/index.js +1 -0
  16. package/esm/BGrid.js +180 -60
  17. package/esm/components/ColResizer.js +8 -3
  18. package/esm/components/Pagination.js +8 -5
  19. package/esm/components/Table.js +69 -36
  20. package/esm/components/TableBody.js +11 -16
  21. package/esm/components/TableHead.js +6 -8
  22. package/esm/components/TableHeadColumn.js +23 -18
  23. package/esm/components/TableHeadFrozen.js +7 -9
  24. package/esm/components/toolbox/TableHeadToolbox.js +8 -3
  25. package/esm/components/toolbox/ToolboxColumnVisibilitySection.js +68 -0
  26. package/esm/components/toolbox/index.js +1 -0
  27. package/esm/store/createAppStore.js +127 -29
  28. package/esm/utils/columnVisibility.js +89 -0
  29. package/esm/utils/index.js +1 -0
  30. package/package.json +1 -1
  31. package/style.css +126 -28
  32. package/types/BGrid.d.ts +1 -1
  33. package/types/components/Table.d.ts +3 -1
  34. package/types/components/toolbox/ToolboxColumnVisibilitySection.d.ts +11 -0
  35. package/types/components/toolbox/index.d.ts +1 -0
  36. package/types/store/createAppStore.d.ts +1 -1
  37. package/types/types.d.ts +42 -0
  38. package/types/utils/columnVisibility.d.ts +21 -0
  39. package/types/utils/index.d.ts +1 -0
package/README.md CHANGED
@@ -2,12 +2,23 @@
2
2
 
3
3
  **Beautiful. Powerful. Naturally React.**
4
4
 
5
- [![NPM version](https://img.shields.io/npm/v/beautiful-grid.svg?style=flat)](https://npmjs.org/package/beautiful-grid)
6
- [![NPM downloads](https://img.shields.io/npm/dm/beautiful-grid.svg?style=flat)](https://npmjs.org/package/beautiful-grid)
5
+ [![NPM version](https://img.shields.io/npm/v/beautiful-grid?logo=npm)](https://npmjs.org/package/beautiful-grid)
6
+ [![NPM downloads](https://img.shields.io/npm/dm/beautiful-grid?color=blue&logo=npm)](https://npmjs.org/package/beautiful-grid)
7
+ [![Bundle size](https://img.shields.io/badge/minzipped-62.6%20KiB-success)](https://bgrid.axisj.com)
8
+ [![Unpacked size](https://img.shields.io/npm/unpacked-size/beautiful-grid?color=informational)](https://www.npmjs.com/package/beautiful-grid)
9
+ [![Test](https://img.shields.io/github/actions/workflow/status/axisj/beautiful-grid/tests.yml?branch=main&label=tests&logo=github)](https://github.com/axisj/beautiful-grid/actions/workflows/tests.yml)
10
+ <br />
7
11
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
8
- [![Coverage](https://img.shields.io/badge/coverage-85.63%25-brightgreen.svg)](https://github.com/axisj/beautiful-grid/actions/workflows/tests.yml)
12
+ [![TypeScript](https://img.shields.io/npm/types/beautiful-grid?logo=typescript&logoColor=white)](https://www.npmjs.com/package/beautiful-grid)
13
+ [![React](https://img.shields.io/badge/React-%5E19.0.0-61DAFB?logo=react&logoColor=black)](https://react.dev/)
14
+ [![Node](https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white)](https://nodejs.org)
15
+ [![Last commit](https://img.shields.io/github/last-commit/axisj/beautiful-grid?logo=git)](https://github.com/axisj/beautiful-grid/commits/main)
16
+ <br />
17
+ [![GitHub stars](https://img.shields.io/github/stars/axisj/beautiful-grid?logo=github)](https://github.com/axisj/beautiful-grid/stargazers)
18
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/axisj/beautiful-grid/pulls)
19
+ [![Docs](https://img.shields.io/badge/docs-bgrid.axisj.com-blue?logo=googlechrome&logoColor=white)](https://bgrid.axisj.com)
9
20
 
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.
21
+ 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, recoverable column visibility, server/client pagination, pivot table transforms, row reordering, and flexible theming.
11
22
 
12
23
  Explore live interactive examples and in-depth documentation at [bgrid.axisj.com](https://bgrid.axisj.com).
13
24
 
@@ -33,6 +44,7 @@ Explore live interactive examples and in-depth documentation at [bgrid.axisj.com
33
44
  - [11. Summary Row](#11-summary-row)
34
45
  - [12. Cell Merging](#12-cell-merging)
35
46
  - [13. Pivot Table](#13-pivot-table)
47
+ - [14. Column Visibility](#14-column-visibility)
36
48
  - [Props Reference](#props-reference)
37
49
  - [BGridProps](#bgridprops)
38
50
  - [BGridColumn](#bgridcolumn)
@@ -846,6 +858,35 @@ const pivotConfig: BGridProps<SalesRecord>['pivot'] = {
846
858
 
847
859
  ---
848
860
 
861
+ ### 14. Column Visibility
862
+
863
+ Available since BeautifulGrid `1.0.6`.
864
+
865
+ Enable recoverable column hiding through the existing header toolbox. Use controlled state to persist a user's visible-column preferences.
866
+
867
+ ```typescript jsx
868
+ function OrdersGrid({ data, columns }) {
869
+ const [hiddenColumnIds, setHiddenColumnIds] = React.useState(['owner']);
870
+
871
+ return (
872
+ <BGrid
873
+ width={800}
874
+ height={420}
875
+ data={data}
876
+ columns={columns}
877
+ columnVisibility={{
878
+ hiddenColumnIds,
879
+ onChange: setHiddenColumnIds,
880
+ }}
881
+ />
882
+ );
883
+ }
884
+ ```
885
+
886
+ Set `hideable: false` on columns that must remain available. The final visible column cannot be hidden, and active sort/filter conditions remain intact while their column is hidden.
887
+
888
+ ---
889
+
849
890
  ## Props Reference
850
891
 
851
892
  ### BGridProps
@@ -919,6 +960,7 @@ Below is a categorized reference of `<BGrid>` props. For exact TypeScript types,
919
960
  | `summary` | `{ position: 'top' \| 'bottom'; columns: BGridSummaryColumn<T>[] }` | Static summary row configuration. |
920
961
  | `cellMergeOptions` | `{ columnsMap: Record<number, BGridCellMergeColumn> }` | Vertical cell merge rules. |
921
962
  | `pivot` | `BGridPivotOptions<T>` | Pivot table dimensions, aggregation rules, and metrics. |
963
+ | `columnVisibility` | `boolean \| BGridColumnVisibilityOptions<T>` | Enables controlled or uncontrolled column hiding and restore controls (since `1.0.6`). |
922
964
  | `loading` | `boolean` | Displays full-grid loading overlay. |
923
965
  | `spinning` | `boolean` | Displays body-area spinner. |
924
966
  | `msg` | `{ emptyList?: string }` | Custom empty state text. |
@@ -950,6 +992,7 @@ Below is a categorized reference of `<BGrid>` props. For exact TypeScript types,
950
992
  | `searchable` | `boolean` | Whether this column participates in grid search (defaults to `true`). |
951
993
  | `getSearchText` | `(params: BGridSearchCellParams<T>) => unknown` | Custom string extractor for grid search matching. |
952
994
  | `toolbox` | `boolean \| BGridToolboxConfig<T>` | Enables header sort/filter toolbox popup. |
995
+ | `hideable` | `boolean` | Allows this column to be hidden through the visibility menu (defaults to `true`, since `1.0.6`). |
953
996
  | `filter` | `false \| BGridColumnFilterConfig<T>` | Column filter configuration (`type: 'values' \| 'text' \| 'number'`). |
954
997
  | `sortComparator` | `(a, b, params) => number` | Custom comparator function for sorting. |
955
998
 
package/cjs/BGrid.js CHANGED
@@ -77,10 +77,28 @@ var React = __importStar(require("react"));
77
77
  var Table_1 = __importDefault(require("./components/Table"));
78
78
  var utils_1 = require("./utils");
79
79
  var store_1 = require("./store");
80
+ function computeModelColumns(columns, frozenColumnIndex, duplicateToolboxColumnIds) {
81
+ var left = 0;
82
+ var previousWidth = 0;
83
+ return columns.map(function (column, columnIndex) {
84
+ var _a, _b;
85
+ var columnId = (0, utils_1.getColumnId)(column);
86
+ if (columnIndex >= frozenColumnIndex) {
87
+ left += previousWidth;
88
+ previousWidth = (_a = column.width) !== null && _a !== void 0 ? _a : 100;
89
+ }
90
+ return __assign(__assign({}, column), { columnId: columnId, keyToken: (0, utils_1.getColumnKeyToken)(column.key), toolbox: duplicateToolboxColumnIds.has(columnId) ? false : column.toolbox, left: columnIndex < frozenColumnIndex ? -1 : left, width: (_b = column.width) !== null && _b !== void 0 ? _b : 100 });
91
+ });
92
+ }
80
93
  function BGrid(_a) {
81
94
  var _b, _c, _d;
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
- var warnedSearchControlledRef = React.useRef({ open: false, query: false, pivotContextMenu: false });
95
+ 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, disabled = _a.disabled, 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, columnVisibility = _a.columnVisibility, searchOptions = _a.searchOptions, contextMenuOptions = _a.contextMenuOptions;
96
+ var warnedSearchControlledRef = React.useRef({
97
+ open: false,
98
+ query: false,
99
+ pivotContextMenu: false,
100
+ columnVisibility: false,
101
+ });
84
102
  var pivotData = React.useMemo(function () {
85
103
  return (0, utils_1.createPivotData)({
86
104
  data: data,
@@ -88,37 +106,76 @@ function BGrid(_a) {
88
106
  });
89
107
  }, [data, pivot]);
90
108
  var pivotEnabled = !!pivotData;
91
- var resolvedColumns = (_b = pivotData === null || pivotData === void 0 ? void 0 : pivotData.columns) !== null && _b !== void 0 ? _b : columns;
109
+ var resolvedColumns = ((_b = pivotData === null || pivotData === void 0 ? void 0 : pivotData.columns) !== null && _b !== void 0 ? _b : columns);
110
+ var visibilityOptions = typeof columnVisibility === 'object' ? columnVisibility : undefined;
111
+ var visibilityEnabled = columnVisibility === true || (visibilityOptions !== undefined && visibilityOptions.enabled !== false);
112
+ var _r = __read(React.useState(function () { var _a; return Array.from(new Set((_a = visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.defaultHiddenColumnIds) !== null && _a !== void 0 ? _a : [])); }), 2), uncontrolledHiddenColumnIds = _r[0], setUncontrolledHiddenColumnIds = _r[1];
113
+ var hiddenColumnIds = React.useMemo(function () {
114
+ var _a;
115
+ if (!visibilityEnabled)
116
+ return [];
117
+ var requestedIds = Array.from(new Set((_a = visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.hiddenColumnIds) !== null && _a !== void 0 ? _a : uncontrolledHiddenColumnIds));
118
+ if (resolvedColumns.length > 0 &&
119
+ resolvedColumns.every(function (column) { return requestedIds.includes((0, utils_1.getColumnId)(column)); })) {
120
+ var firstColumnId_1 = (0, utils_1.getColumnId)(resolvedColumns[0]);
121
+ return requestedIds.filter(function (columnId) { return columnId !== firstColumnId_1; });
122
+ }
123
+ return requestedIds;
124
+ }, [resolvedColumns, uncontrolledHiddenColumnIds, visibilityEnabled, visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.hiddenColumnIds]);
125
+ var hiddenColumnIdSet = React.useMemo(function () { return new Set(hiddenColumnIds); }, [hiddenColumnIds]);
92
126
  var resolvedColumnGroups = React.useMemo(function () { return (pivotEnabled ? [] : columnGroups !== null && columnGroups !== void 0 ? columnGroups : []); }, [columnGroups, pivotEnabled]);
93
127
  var resolvedColumnsGroup = React.useMemo(function () { var _a; return (_a = pivotData === null || pivotData === void 0 ? void 0 : pivotData.columnsGroup) !== null && _a !== void 0 ? _a : (resolvedColumnGroups.length ? [] : columnsGroup !== null && columnsGroup !== void 0 ? columnsGroup : []); }, [columnsGroup, pivotData === null || pivotData === void 0 ? void 0 : pivotData.columnsGroup, resolvedColumnGroups.length]);
128
+ var visibilityProjection = React.useMemo(function () {
129
+ return (0, utils_1.projectColumnVisibility)({
130
+ columns: resolvedColumns,
131
+ hiddenColumnIds: hiddenColumnIdSet,
132
+ frozenColumnIndex: pivotEnabled ? 0 : frozenColumnIndex,
133
+ columnsGroup: resolvedColumnsGroup,
134
+ columnGroups: resolvedColumnGroups,
135
+ cellMergeOptions: pivotEnabled ? undefined : cellMergeOptions,
136
+ summary: pivotEnabled ? undefined : summary,
137
+ });
138
+ }, [
139
+ cellMergeOptions,
140
+ frozenColumnIndex,
141
+ hiddenColumnIdSet,
142
+ pivotEnabled,
143
+ resolvedColumnGroups,
144
+ resolvedColumns,
145
+ resolvedColumnsGroup,
146
+ summary,
147
+ ]);
94
148
  var resolvedData = (_c = pivotData === null || pivotData === void 0 ? void 0 : pivotData.data) !== null && _c !== void 0 ? _c : data;
95
149
  var resolvedPage = pivotEnabled ? undefined : page;
96
- var resolvedFrozenColumnIndex = pivotEnabled ? 0 : frozenColumnIndex;
150
+ var resolvedFrozenColumnIndex = visibilityProjection.frozenColumnIndex;
97
151
  var resolvedRowChecked = pivotEnabled ? undefined : rowChecked;
98
152
  var resolvedSort = pivotEnabled ? undefined : sort;
99
- var resolvedOnClick = pivotEnabled ? undefined : onClick;
100
- var resolvedOnChangeColumns = pivotEnabled ? undefined : onChangeColumns;
153
+ var resolvedDisabled = !!disabled;
154
+ var resolvedOnClick = pivotEnabled || resolvedDisabled ? undefined : onClick;
155
+ var baseOnChangeColumns = pivotEnabled ? undefined : onChangeColumns;
101
156
  var resolvedOnChangeData = pivotEnabled ? undefined : onChangeData;
102
157
  var resolvedRowKey = pivotEnabled ? undefined : rowKey;
103
158
  var resolvedSelectedRowKey = pivotEnabled ? undefined : selectedRowKey;
104
- var resolvedEditable = pivotEnabled ? false : editable;
159
+ var resolvedEditable = pivotEnabled || resolvedDisabled ? false : editable;
105
160
  var resolvedShowLineNumber = pivotEnabled ? false : showLineNumber;
106
161
  var resolvedGetRowClassName = pivotEnabled ? undefined : getRowClassName;
107
- var resolvedCellMergeOptions = pivotEnabled ? undefined : cellMergeOptions;
108
- var resolvedCellSelectionOptions = cellSelectionOptions;
109
- var resolvedSummary = pivotEnabled ? undefined : summary;
110
- var resolvedColumnSortable = pivotEnabled ? false : columnSortable;
162
+ var resolvedCellMergeOptions = visibilityProjection.cellMergeOptions;
163
+ var resolvedCellSelectionOptions = resolvedDisabled
164
+ ? __assign(__assign({}, cellSelectionOptions), { enabled: false }) : cellSelectionOptions;
165
+ var resolvedSummary = visibilityProjection.summary;
166
+ var hasHiddenColumns = visibilityProjection.columns.length < resolvedColumns.length;
167
+ var resolvedColumnSortable = pivotEnabled || hasHiddenColumns || resolvedDisabled ? false : columnSortable;
111
168
  var resolvedDataControl = pivotEnabled ? undefined : dataControl;
112
- var resolvedSearchOptions = pivotEnabled ? undefined : searchOptions;
113
- var resolvedContextMenuOptions = pivotEnabled ? undefined : contextMenuOptions;
169
+ var resolvedSearchOptions = pivotEnabled || resolvedDisabled ? undefined : searchOptions;
170
+ var resolvedContextMenuOptions = pivotEnabled || resolvedDisabled ? undefined : contextMenuOptions;
114
171
  var hasActiveClientQuery = (resolvedDataControl === null || resolvedDataControl === void 0 ? void 0 : resolvedDataControl.mode) === 'client' &&
115
172
  (resolvedDataControl.query.sortParams.length > 0 || resolvedDataControl.query.filterParams.length > 0);
116
173
  var resolvedReorder = React.useMemo(function () {
117
- return pivotEnabled
174
+ return pivotEnabled || resolvedDisabled
118
175
  ? undefined
119
176
  : (hasActiveClientQuery || frozenRowCount > 0) && reorder
120
177
  ? __assign(__assign({}, reorder), { enabled: false }) : reorder;
121
- }, [frozenRowCount, hasActiveClientQuery, pivotEnabled, reorder]);
178
+ }, [frozenRowCount, hasActiveClientQuery, pivotEnabled, reorder, resolvedDisabled]);
122
179
  // Development warnings
123
180
  React.useEffect(function () {
124
181
  var _a, _b;
@@ -148,9 +205,16 @@ function BGrid(_a) {
148
205
  warnedSearchControlledRef.current.pivotContextMenu = true;
149
206
  console.warn('[BGrid] contextMenuOptions is disabled while pivot mode is active.');
150
207
  }
151
- if ((searchOptions === null || searchOptions === void 0 ? void 0 : searchOptions.open) !== undefined &&
152
- !searchOptions.onOpenChange &&
153
- !warnedSearchControlledRef.current.open) {
208
+ if (hasHiddenColumns && columnSortable) {
209
+ console.warn('[BGrid] Column reordering is disabled while columns are hidden.');
210
+ }
211
+ if ((visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.hiddenColumnIds) !== undefined &&
212
+ !visibilityOptions.onChange &&
213
+ !warnedSearchControlledRef.current.columnVisibility) {
214
+ warnedSearchControlledRef.current.columnVisibility = true;
215
+ console.warn('[BGrid] Controlled columnVisibility.hiddenColumnIds requires onChange to respond to user actions.');
216
+ }
217
+ if ((searchOptions === null || searchOptions === void 0 ? void 0 : searchOptions.open) !== undefined && !searchOptions.onOpenChange && !warnedSearchControlledRef.current.open) {
154
218
  warnedSearchControlledRef.current.open = true;
155
219
  console.warn('[BGrid] Controlled searchOptions.open requires onOpenChange to respond to user actions.');
156
220
  }
@@ -173,8 +237,18 @@ function BGrid(_a) {
173
237
  resolvedSort,
174
238
  contextMenuOptions,
175
239
  searchOptions,
240
+ columnSortable,
241
+ hasHiddenColumns,
242
+ visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.hiddenColumnIds,
243
+ visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.onChange,
176
244
  ]);
177
- var duplicateToolboxColumnIds = React.useMemo(function () { return (0, utils_1.findDuplicateColumnIds)(resolvedColumns, true); }, [resolvedColumns]);
245
+ var duplicateToolboxColumnIds = React.useMemo(function () {
246
+ var duplicates = (0, utils_1.findDuplicateColumnIds)(resolvedColumns, true);
247
+ if (visibilityEnabled) {
248
+ (0, utils_1.findDuplicateColumnIds)(resolvedColumns).forEach(function (columnId) { return duplicates.add(columnId); });
249
+ }
250
+ return duplicates;
251
+ }, [resolvedColumns, visibilityEnabled]);
178
252
  var warnedDuplicateIdsRef = React.useRef(new Set());
179
253
  React.useEffect(function () {
180
254
  if (process.env.NODE_ENV === 'production')
@@ -183,30 +257,80 @@ function BGrid(_a) {
183
257
  if (newDuplicateIds.length === 0)
184
258
  return;
185
259
  newDuplicateIds.forEach(function (id) { return warnedDuplicateIdsRef.current.add(id); });
186
- console.warn("[BGrid] Duplicate column IDs detected: ".concat(newDuplicateIds.join(', '), ". Toolbox is disabled for those columns; specify an explicit unique 'id'."));
187
- }, [duplicateToolboxColumnIds]);
260
+ console.warn("[BGrid] Duplicate column IDs detected: ".concat(newDuplicateIds.join(', '), ". Toolbox").concat(visibilityEnabled ? ' and column visibility are' : ' is', " disabled for those columns; specify an explicit unique 'id'."));
261
+ }, [duplicateToolboxColumnIds, visibilityEnabled]);
262
+ var requestColumnVisibilityChange = React.useCallback(function (nextHiddenColumnIds, event) {
263
+ var _a;
264
+ var uniqueIds = Array.from(new Set(nextHiddenColumnIds));
265
+ if (event.type === 'hide') {
266
+ var visibleCount = resolvedColumns.reduce(function (count, column) { return count + (uniqueIds.includes((0, utils_1.getColumnId)(column)) ? 0 : 1); }, 0);
267
+ if (visibleCount === 0)
268
+ return;
269
+ }
270
+ if ((visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.hiddenColumnIds) === undefined) {
271
+ setUncontrolledHiddenColumnIds(uniqueIds);
272
+ }
273
+ (_a = visibilityOptions === null || visibilityOptions === void 0 ? void 0 : visibilityOptions.onChange) === null || _a === void 0 ? void 0 : _a.call(visibilityOptions, uniqueIds, event);
274
+ }, [resolvedColumns, visibilityOptions]);
275
+ var columnVisibilityState = React.useMemo(function () {
276
+ return visibilityEnabled
277
+ ? {
278
+ items: resolvedColumns.map(function (column) {
279
+ var columnId = (0, utils_1.getColumnId)(column);
280
+ return {
281
+ column: column,
282
+ columnId: columnId,
283
+ hidden: hiddenColumnIdSet.has(columnId),
284
+ hideable: column.hideable !== false && !duplicateToolboxColumnIds.has(columnId),
285
+ };
286
+ }),
287
+ hiddenColumnIds: hiddenColumnIds,
288
+ onChange: requestColumnVisibilityChange,
289
+ }
290
+ : undefined;
291
+ }, [
292
+ duplicateToolboxColumnIds,
293
+ hiddenColumnIdSet,
294
+ hiddenColumnIds,
295
+ requestColumnVisibilityChange,
296
+ resolvedColumns,
297
+ visibilityEnabled,
298
+ ]);
188
299
  var computedColumns = React.useMemo(function () {
189
- var left = 0;
190
- var prevWidth = 0;
191
- return __spreadArray(__spreadArray([], __read(resolvedColumns.slice(0, resolvedFrozenColumnIndex).map(function (column) {
192
- var _a;
193
- var columnId = (0, utils_1.getColumnId)(column);
194
- return __assign(__assign({}, column), { columnId: columnId, keyToken: (0, utils_1.getColumnKeyToken)(column.key), toolbox: duplicateToolboxColumnIds.has(columnId) ? false : column.toolbox, left: -1, width: (_a = column.width) !== null && _a !== void 0 ? _a : 100 });
195
- })), false), __read(resolvedColumns.slice(resolvedFrozenColumnIndex).map(function (column) {
196
- var _a, _b;
197
- left += prevWidth;
198
- prevWidth = (_a = column.width) !== null && _a !== void 0 ? _a : 100;
199
- var columnId = (0, utils_1.getColumnId)(column);
200
- return __assign(__assign({}, column), { columnId: columnId, keyToken: (0, utils_1.getColumnKeyToken)(column.key), toolbox: duplicateToolboxColumnIds.has(columnId) ? false : column.toolbox, left: left, width: (_b = column.width) !== null && _b !== void 0 ? _b : 100 });
201
- })), false);
202
- }, [duplicateToolboxColumnIds, resolvedColumns, resolvedFrozenColumnIndex]);
300
+ return computeModelColumns(visibilityProjection.columns, resolvedFrozenColumnIndex, duplicateToolboxColumnIds);
301
+ }, [duplicateToolboxColumnIds, resolvedFrozenColumnIndex, visibilityProjection.columns]);
302
+ var queryColumns = React.useMemo(function () { return computeModelColumns(resolvedColumns, pivotEnabled ? 0 : frozenColumnIndex, duplicateToolboxColumnIds); }, [duplicateToolboxColumnIds, frozenColumnIndex, pivotEnabled, resolvedColumns]);
303
+ var projectedOnChangeColumns = React.useCallback(function (visibleColumnIndex, info) {
304
+ var _a;
305
+ if (!baseOnChangeColumns)
306
+ return;
307
+ if (!hasHiddenColumns) {
308
+ baseOnChangeColumns(visibleColumnIndex, info);
309
+ return;
310
+ }
311
+ var nextColumns = __spreadArray([], __read(resolvedColumns), false);
312
+ visibilityProjection.visibleOriginalIndexes.forEach(function (originalIndex, visibleIndex) {
313
+ var updatedColumn = info.columns[visibleIndex];
314
+ if (updatedColumn)
315
+ nextColumns[originalIndex] = updatedColumn;
316
+ });
317
+ baseOnChangeColumns(visibleColumnIndex === null ? null : (_a = visibilityProjection.visibleOriginalIndexes[visibleColumnIndex]) !== null && _a !== void 0 ? _a : null, __assign(__assign({}, info), { columns: nextColumns, columnsGroup: resolvedColumnsGroup, columnGroups: resolvedColumnGroups }));
318
+ }, [
319
+ baseOnChangeColumns,
320
+ hasHiddenColumns,
321
+ resolvedColumnGroups,
322
+ resolvedColumns,
323
+ resolvedColumnsGroup,
324
+ visibilityProjection.visibleOriginalIndexes,
325
+ ]);
326
+ var resolvedOnChangeColumns = baseOnChangeColumns ? projectedOnChangeColumns : undefined;
203
327
  var headerMatrixDiagnostics = React.useMemo(function () {
204
328
  return (0, utils_1.buildHeaderMatrix)({
205
329
  columns: computedColumns,
206
- columnsGroup: resolvedColumnsGroup,
207
- columnGroups: resolvedColumnGroups,
330
+ columnsGroup: visibilityProjection.columnsGroup,
331
+ columnGroups: visibilityProjection.columnGroups,
208
332
  });
209
- }, [computedColumns, resolvedColumnGroups, resolvedColumnsGroup]);
333
+ }, [computedColumns, visibilityProjection.columnGroups, visibilityProjection.columnsGroup]);
210
334
  React.useEffect(function () {
211
335
  if (process.env.NODE_ENV === 'production')
212
336
  return;
@@ -221,9 +345,9 @@ function BGrid(_a) {
221
345
  var unknownQueryColumnIds = React.useMemo(function () {
222
346
  if (!resolvedDataControl)
223
347
  return [];
224
- var knownIds = new Set(computedColumns.map(function (column) { return column.columnId; }));
348
+ var knownIds = new Set(queryColumns.map(function (column) { return column.columnId; }));
225
349
  return Array.from(new Set(__spreadArray(__spreadArray([], __read(resolvedDataControl.query.sortParams.map(function (param) { var _a; return (_a = param.columnId) !== null && _a !== void 0 ? _a : param.key; })), false), __read(resolvedDataControl.query.filterParams.map(function (param) { return param.columnId; })), false).filter(function (id) { return !!id && !knownIds.has(id); })));
226
- }, [computedColumns, resolvedDataControl]);
350
+ }, [queryColumns, resolvedDataControl]);
227
351
  var warnedUnknownQueryIdsRef = React.useRef(new Set());
228
352
  React.useEffect(function () {
229
353
  if (process.env.NODE_ENV === 'production')
@@ -257,7 +381,7 @@ function BGrid(_a) {
257
381
  if ((resolvedDataControl === null || resolvedDataControl === void 0 ? void 0 : resolvedDataControl.mode) === 'client') {
258
382
  return (0, utils_1.processDataQuery)({
259
383
  data: resolvedData,
260
- columns: computedColumns,
384
+ columns: queryColumns,
261
385
  query: resolvedDataQuery,
262
386
  rowKey: resolvedRowKey,
263
387
  includeRows: false,
@@ -271,7 +395,7 @@ function BGrid(_a) {
271
395
  sourceIndexByVisibleIndex: sourceIndexByVisibleIndex,
272
396
  visibleIndexBySourceIndex: visibleIndexBySourceIndex,
273
397
  };
274
- }, [computedColumns, resolvedData, resolvedDataControl === null || resolvedDataControl === void 0 ? void 0 : resolvedDataControl.mode, resolvedDataQuery, resolvedRowKey]);
398
+ }, [queryColumns, resolvedData, resolvedDataControl === null || resolvedDataControl === void 0 ? void 0 : resolvedDataControl.mode, resolvedDataQuery, resolvedRowKey]);
275
399
  var displayData = processedResult.data;
276
400
  var resolvedFrozenRowCount = pivotEnabled
277
401
  ? 0
@@ -376,8 +500,8 @@ function BGrid(_a) {
376
500
  reorderable: (_a = resolvedReorder === null || resolvedReorder === void 0 ? void 0 : resolvedReorder.enabled) !== null && _a !== void 0 ? _a : false,
377
501
  }),
378
502
  columns: computedColumns,
379
- columnsGroup: resolvedColumnsGroup,
380
- columnGroups: resolvedColumnGroups,
503
+ columnsGroup: visibilityProjection.columnsGroup,
504
+ columnGroups: visibilityProjection.columnGroups,
381
505
  data: displayData,
382
506
  sourceData: resolvedData,
383
507
  sourceIndexByVisibleIndex: processedResult.sourceIndexByVisibleIndex,
@@ -392,11 +516,13 @@ function BGrid(_a) {
392
516
  dataQuery: resolvedDataQuery,
393
517
  dataControl: resolvedDataControl,
394
518
  icons: icons,
519
+ columnVisibilityState: columnVisibilityState,
395
520
  searchOptions: resolvedSearchOptions,
396
521
  contextMenuOptions: resolvedContextMenuOptions,
397
522
  page: resolvedPage,
398
523
  displayPaginationLength: resolvedPage ? (_b = resolvedPage.displayPaginationLength) !== null && _b !== void 0 ? _b : 5 : 0,
399
524
  loading: loading,
525
+ disabled: resolvedDisabled,
400
526
  spinning: spinning,
401
527
  scrollTop: scrollTop,
402
528
  scrollLeft: scrollLeft,
@@ -445,16 +571,18 @@ function BGrid(_a) {
445
571
  resolvedRowChecked,
446
572
  computedColumns,
447
573
  resolvedReorder,
448
- resolvedColumnsGroup,
449
- resolvedColumnGroups,
574
+ visibilityProjection.columnsGroup,
575
+ visibilityProjection.columnGroups,
450
576
  resolvedSort,
451
577
  sortParams,
452
578
  resolvedDataQuery,
453
579
  resolvedDataControl,
454
580
  icons,
581
+ columnVisibilityState,
455
582
  resolvedSearchOptions,
456
583
  resolvedContextMenuOptions,
457
584
  loading,
585
+ resolvedDisabled,
458
586
  spinning,
459
587
  scrollTop,
460
588
  scrollLeft,
@@ -476,15 +604,15 @@ function BGrid(_a) {
476
604
  ]);
477
605
  return (React.createElement(store_1.AppStoreProvider, { initialState: initialStoreState },
478
606
  React.createElement(Table_1.default, { ref: ref, columns: computedColumns,
479
- columnsGroup: resolvedColumnsGroup,
480
- columnGroups: resolvedColumnGroups,
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,
607
+ columnsGroup: visibilityProjection.columnsGroup,
608
+ columnGroups: visibilityProjection.columnGroups,
609
+ onChangeColumns: resolvedOnChangeColumns, width: width, height: height, className: className, style: style, loading: loading, disabled: resolvedDisabled, spinning: spinning, scrollLeft: scrollLeft, scrollTop: scrollTop, headerHeight: headerHeight, footerHeight: footerHeight, bottomBarHeight: resolvedBottomBarHeight,
482
610
  scrollbar: resolvedScrollbar,
483
611
  status: resolvedStatus,
484
612
  pagination: resolvedPagination, summaryHeight: summaryHeight, itemHeight: itemHeight, itemPadding: itemPadding, frozenColumnIndex: resolvedFrozenColumnIndex,
485
613
  frozenRowCount: resolvedFrozenRowCount,
486
614
  rowChecked: resolvedRowChecked, checkedIndexesMap: checkedIndexesMap, sort: resolvedSort, sortParams: sortParams, dataQuery: resolvedDataQuery,
487
- dataControl: resolvedDataControl, icons: icons, searchOptions: resolvedSearchOptions,
615
+ dataControl: resolvedDataControl, icons: icons, columnVisibilityState: columnVisibilityState, searchOptions: resolvedSearchOptions,
488
616
  contextMenuOptions: resolvedContextMenuOptions,
489
617
  page: resolvedPage,
490
618
  data: displayData,
@@ -79,9 +79,12 @@ function ColResizer(_a) {
79
79
  var setColumnWidth = (0, store_1.useAppStore)(function (s) { return s.setColumnWidth; });
80
80
  var setColumnResizing = (0, store_1.useAppStore)(function (s) { return s.setColumnResizing; });
81
81
  var endCellEdit = (0, store_1.useAppStore)(function (s) { return s.endCellEdit; });
82
+ var disabled = (0, store_1.useAppStore)(function (s) { return s.disabled; });
82
83
  var columnsGroup = (0, store_1.useAppStore)(function (s) { return s.columnsGroup; });
83
84
  var onPointerDownResizerHandle = React.useCallback(function (evt, columnIndex) {
84
85
  var _a, _b;
86
+ if (disabled)
87
+ return;
85
88
  evt.preventDefault();
86
89
  evt.stopPropagation();
87
90
  endCellEdit();
@@ -101,13 +104,15 @@ function ColResizer(_a) {
101
104
  pointerId: evt.pointerId,
102
105
  initialClientX: evt.clientX,
103
106
  });
104
- }, [container, endCellEdit, setColumnResizing, setColumnWidth]);
107
+ }, [container, disabled, endCellEdit, setColumnResizing, setColumnWidth]);
105
108
  var onMouseDoubleClick = React.useCallback(function (evt, columnIndex) { return __awaiter(_this, void 0, void 0, function () {
106
109
  var headFrozenHTML, headHTML, bodyFrozenHTML, bodyHTML, targetDiv, bodyTarget, targetTd;
107
110
  var _a, _b, _c, _d, _e;
108
111
  return __generator(this, function (_f) {
109
112
  switch (_f.label) {
110
113
  case 0:
114
+ if (disabled)
115
+ return [2 /*return*/];
111
116
  evt.preventDefault();
112
117
  evt.stopPropagation();
113
118
  endCellEdit();
@@ -135,13 +140,13 @@ function ColResizer(_a) {
135
140
  case 2: return [2 /*return*/];
136
141
  }
137
142
  });
138
- }); }, [container, endCellEdit, setColumnWidth]);
143
+ }); }, [container, disabled, endCellEdit, setColumnWidth]);
139
144
  return (React.createElement("div", { className: [
140
145
  'bgrid-col-resizer',
141
146
  hideHandle ? '' : 'bgrid-col-resizer-handle',
142
147
  frozenBoundary ? 'bgrid-col-resizer-frozen-boundary' : '',
143
148
  ]
144
149
  .filter(Boolean)
145
- .join(' '), "data-bgrid-frozen-boundary": frozenBoundary ? 'true' : undefined, style: !hideHandle ? (_b = {}, _b['--bgrid-resizer-height'] = bordered ? '100%' : '1em', _b) : undefined, onPointerDown: function (evt) { return onPointerDownResizerHandle(evt, columnIndex); }, onDoubleClick: function (evt) { return onMouseDoubleClick(evt, columnIndex); }, onClick: function (evt) { return evt.stopPropagation(); } }));
150
+ .join(' '), "data-bgrid-frozen-boundary": frozenBoundary ? 'true' : undefined, "data-bgrid-disabled": disabled ? 'true' : undefined, style: !hideHandle ? (_b = {}, _b['--bgrid-resizer-height'] = bordered ? '100%' : '1em', _b) : undefined, onPointerDown: function (evt) { return onPointerDownResizerHandle(evt, columnIndex); }, onDoubleClick: function (evt) { return onMouseDoubleClick(evt, columnIndex); }, onClick: function (evt) { return evt.stopPropagation(); } }));
146
151
  }
147
152
  exports.default = ColResizer;
@@ -54,18 +54,21 @@ function Pagination(props) {
54
54
  var _b = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
55
55
  page: s.page,
56
56
  displayPaginationLength: s.displayPaginationLength,
57
- }); })), page = _b.page, displayPaginationLength = _b.displayPaginationLength;
57
+ disabled: s.disabled,
58
+ }); })), page = _b.page, displayPaginationLength = _b.displayPaginationLength, disabled = _b.disabled;
58
59
  // [Selector Group 2] Pagination Actions - 페이지네이션 액션
59
60
  var setPage = (0, store_1.useAppStore)((0, shallow_1.useShallow)(function (s) { return ({
60
61
  setPage: s.setPage,
61
62
  }); })).setPage;
62
63
  var onClickPageNo = React.useCallback(function (pageNo) {
63
64
  var _a;
65
+ if (disabled)
66
+ return;
64
67
  if (page) {
65
68
  setPage(__assign(__assign({}, page), { currentPage: pageNo }));
66
69
  (_a = page === null || page === void 0 ? void 0 : page.onChange) === null || _a === void 0 ? void 0 : _a.call(page, pageNo, page === null || page === void 0 ? void 0 : page.pageSize);
67
70
  }
68
- }, [page, setPage]);
71
+ }, [disabled, page, setPage]);
69
72
  if (page && page.totalPages !== undefined && page.currentPage !== undefined && page.totalPages > 0) {
70
73
  var displayLength_1 = Math.min(displayPaginationLength !== null && displayPaginationLength !== void 0 ? displayPaginationLength : 0, (_a = page.totalPages) !== null && _a !== void 0 ? _a : 5);
71
74
  var pageStartNumber_1 = (function () {
@@ -75,18 +78,18 @@ function Pagination(props) {
75
78
  var pageNumber_1 = 0;
76
79
  return (React.createElement("div", { className: 'bgrid-pagination' },
77
80
  pageStartNumber_1 > 1 && (React.createElement(React.Fragment, null,
78
- React.createElement("span", { role: 'page-number', className: 'bgrid-page-no', onClick: function () { return onClickPageNo(1); } }, "1"),
81
+ React.createElement("span", { role: 'page-number', className: 'bgrid-page-no', "aria-disabled": disabled ? 'true' : undefined, onClick: function () { return onClickPageNo(1); } }, "1"),
79
82
  pageStartNumber_1 > 2 && '...')),
80
83
  Array.from({ length: displayLength_1 }).map(function (_, i) {
81
84
  var _a;
82
85
  if (i <= ((_a = page.totalPages) !== null && _a !== void 0 ? _a : 1)) {
83
86
  var num_1 = (pageNumber_1 = pageStartNumber_1 + i);
84
- return (React.createElement("span", { role: 'page-number', key: num_1, className: 'bgrid-page-no', "data-active": page.currentPage === num_1, onClick: function () { return onClickPageNo(num_1); } }, (0, number_1.toMoney)(num_1)));
87
+ return (React.createElement("span", { role: 'page-number', key: num_1, className: 'bgrid-page-no', "data-active": page.currentPage === num_1, "aria-disabled": disabled ? 'true' : undefined, onClick: function () { return onClickPageNo(num_1); } }, (0, number_1.toMoney)(num_1)));
85
88
  }
86
89
  }),
87
90
  page.totalPages && pageNumber_1 < page.totalPages && (React.createElement(React.Fragment, null,
88
91
  pageNumber_1 < page.totalPages - 1 && '...',
89
- React.createElement("span", { role: 'page-number', className: 'bgrid-page-no', onClick: function () { var _a; return onClickPageNo((_a = page.totalPages) !== null && _a !== void 0 ? _a : 0); } }, (0, number_1.toMoney)(page.totalPages))))));
92
+ React.createElement("span", { role: 'page-number', className: 'bgrid-page-no', "aria-disabled": disabled ? 'true' : undefined, onClick: function () { var _a; return onClickPageNo((_a = page.totalPages) !== null && _a !== void 0 ? _a : 0); } }, (0, number_1.toMoney)(page.totalPages))))));
90
93
  }
91
94
  return null;
92
95
  }