@canvas-components/react-pivot-table 0.2.18 → 0.2.20

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
@@ -128,6 +128,12 @@ import {
128
128
  - 获取和恢复版本化状态快照
129
129
  - 获取调试快照
130
130
 
131
+ ## XLSX 导出弹窗
132
+
133
+ 右键导出 XLSX 使用与 `ReactListTable` 相同的导出弹窗和配置表,支持修改文件名(后缀固定)、勾选列、拖拽调整列顺序、数据升降序排序,以及选择是否导出汇总行。汇总支持方式、前缀、小数位数、取整方式和保留无效零;默认带入原表配置,不修改原表。
134
+
135
+ 通过 `exportOptions.fileName` 指定默认名称,`exportOptions.promptFileName: false` 跳过弹窗。弹窗关闭后销毁配置表,配置表不提供右键菜单。原生 `ref.exportXlsx()` 仍是返回字节的接口,不触发弹窗。
136
+
131
137
  ## 推荐场景
132
138
 
133
139
  - React 数据分析后台
package/dist/index.cjs CHANGED
@@ -4,6 +4,7 @@ var react = require('react');
4
4
  var pivotTable = require('@canvas-components/pivot-table');
5
5
  var reactComponents = require('@canvas-components/react-components');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var reactListTable = require('@canvas-components/react-list-table');
7
8
  var reactDom = require('react-dom');
8
9
  var chart = require('@canvas-components/chart');
9
10
 
@@ -39,83 +40,269 @@ var CONTEXT_MENU_SURFACE_STYLE = {
39
40
  boxShadow: "0 8px 24px rgba(15, 23, 42, 0.16)",
40
41
  fontSize: 14
41
42
  };
43
+ function ScrollbarModeMenu(props) {
44
+ const { request, onOpenSettings } = props;
45
+ return /* @__PURE__ */ jsxRuntime.jsx(
46
+ MenuSubmenu,
47
+ {
48
+ label: "\u6EDA\u52A8\u6761\u6A21\u5F0F",
49
+ items: [
50
+ ["scrollbar", "\u6EDA\u52A8\u6761"],
51
+ ["button", "\u6309\u94AE"]
52
+ ].map(([mode, label]) => ({
53
+ key: `scrollbar-mode-${mode}`,
54
+ label,
55
+ selected: (request.scrollbar?.mode ?? "scrollbar") === mode,
56
+ onClick: () => {
57
+ request.onChangeScrollbar?.({
58
+ ...request.scrollbar,
59
+ mode,
60
+ horizontal: request.scrollbar?.horizontal === false ? false : { ...request.scrollbar?.horizontal, mode },
61
+ vertical: request.scrollbar?.vertical === false ? false : { ...request.scrollbar?.vertical, mode }
62
+ });
63
+ request.onClose();
64
+ }
65
+ })),
66
+ footer: /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactButton, { onClick: onOpenSettings, children: "\u914D\u7F6E\u6EDA\u52A8\u6761\u5C5E\u6027" })
67
+ }
68
+ );
69
+ }
70
+ function ScrollbarCacheMenu(props) {
71
+ const { request } = props;
72
+ return /* @__PURE__ */ jsxRuntime.jsx(
73
+ MenuSubmenu,
74
+ {
75
+ label: "\u7F13\u5B58\u5230\u672C\u5730",
76
+ items: [
77
+ {
78
+ key: "cache-scrollbar",
79
+ label: "\u6EDA\u52A8\u6761",
80
+ selected: request.scrollbarCacheAvailable === true && request.cacheScrollbar !== false,
81
+ disabled: request.scrollbarCacheAvailable !== true,
82
+ onClick: () => request.onChangeCacheScrollbar?.(request.cacheScrollbar === false)
83
+ }
84
+ ]
85
+ }
86
+ );
87
+ }
42
88
  function PivotContextMenu(props) {
43
89
  const { request } = props;
44
90
  const [menuOpen, setMenuOpen] = react.useState(true);
91
+ const [scrollbarSettingsRequest, setScrollbarSettingsRequest] = react.useState(null);
92
+ const [scrollbarPositionRequest, setScrollbarPositionRequest] = react.useState(null);
45
93
  react.useEffect(() => {
46
94
  if (request) setMenuOpen(true);
47
95
  }, [request]);
48
- if (!request) return null;
49
- return /* @__PURE__ */ jsxRuntime.jsx(
50
- reactComponents.ReactPopup,
96
+ const scrollbarDialog = scrollbarSettingsRequest ? /* @__PURE__ */ jsxRuntime.jsx(
97
+ reactComponents.ReactScrollbarSettingsDialog,
51
98
  {
52
- open: menuOpen,
53
- anchorRect: { x: request.x, y: request.y, width: 0, height: 0 },
54
- offset: 4,
55
- matchAnchorWidth: false,
56
- minWidth: 260,
57
- onOpenChange: (open) => {
58
- setMenuOpen(open);
59
- if (!open) request.onClose();
99
+ value: scrollbarSettingsRequest.scrollbar,
100
+ onConfirm: (value) => {
101
+ scrollbarSettingsRequest.onChangeScrollbar?.({
102
+ ...scrollbarSettingsRequest.scrollbar,
103
+ ...value
104
+ });
105
+ setScrollbarSettingsRequest(null);
60
106
  },
61
- surfaceStyle: { ...CONTEXT_MENU_SURFACE_STYLE, width: 260 },
62
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
63
- request.title ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "6px 10px", color: "#8f959e", fontSize: 12 }, children: request.title }) : null,
64
- /* @__PURE__ */ jsxRuntime.jsx(
65
- MenuSubmenu,
66
- {
67
- label: "\u590D\u5236",
68
- items: [
69
- {
70
- key: "copy-cell",
71
- label: request.target === "header" ? "\u590D\u5236\u8868\u5934" : "\u590D\u5236\u5355\u5143\u683C",
72
- onClick: request.onCopy
73
- },
74
- {
75
- key: "copy-selection",
76
- label: "\u590D\u5236\u9009\u533A",
77
- onClick: request.target === "header" ? void 0 : request.onCopySelection
107
+ onClose: () => setScrollbarSettingsRequest(null)
108
+ }
109
+ ) : null;
110
+ const scrollbarPositionDialog = scrollbarPositionRequest ? /* @__PURE__ */ jsxRuntime.jsx(
111
+ reactComponents.ReactScrollbarPositionDialog,
112
+ {
113
+ rowCount: scrollbarPositionRequest.scrollbarRowCount ?? 0,
114
+ columnCount: scrollbarPositionRequest.scrollbarColumnCount ?? 0,
115
+ onConfirm: (row, column) => scrollbarPositionRequest.onScrollToPosition?.(row, column),
116
+ onClose: () => setScrollbarPositionRequest(null)
117
+ }
118
+ ) : null;
119
+ if (!request)
120
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
121
+ scrollbarDialog,
122
+ scrollbarPositionDialog
123
+ ] });
124
+ const openScrollbarSettings = () => {
125
+ setScrollbarSettingsRequest(request);
126
+ request.onClose();
127
+ };
128
+ const exportAndClose = (action) => action ? () => {
129
+ setMenuOpen(false);
130
+ request.onClose();
131
+ action();
132
+ } : void 0;
133
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
134
+ scrollbarDialog,
135
+ scrollbarPositionDialog,
136
+ /* @__PURE__ */ jsxRuntime.jsx(
137
+ reactComponents.ReactPopup,
138
+ {
139
+ open: menuOpen,
140
+ anchorRect: { x: request.x, y: request.y, width: 0, height: 0 },
141
+ offset: 4,
142
+ matchAnchorWidth: false,
143
+ minWidth: 260,
144
+ onOpenChange: (open) => {
145
+ setMenuOpen(open);
146
+ if (!open) request.onClose();
147
+ },
148
+ surfaceStyle: { ...CONTEXT_MENU_SURFACE_STYLE, width: 260 },
149
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: request.target === "scrollbar" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
150
+ /* @__PURE__ */ jsxRuntime.jsx(
151
+ ScrollbarModeMenu,
152
+ {
153
+ request,
154
+ onOpenSettings: openScrollbarSettings
155
+ }
156
+ ),
157
+ /* @__PURE__ */ jsxRuntime.jsx(
158
+ MenuAction,
159
+ {
160
+ label: "\u6EDA\u52A8\u5230\u6307\u5B9A\u884C / \u5217",
161
+ onClick: () => {
162
+ setScrollbarPositionRequest(request);
163
+ request.onClose();
78
164
  }
79
- ],
80
- children: request.target !== "header" ? /* @__PURE__ */ jsxRuntime.jsx(CustomSelectionMenu, { request }) : null
81
- }
82
- ),
83
- request.target === "header" ? /* @__PURE__ */ jsxRuntime.jsx(HeaderMenu, { request }) : null,
84
- request.target === "summary" ? /* @__PURE__ */ jsxRuntime.jsx(
85
- SummaryMenu,
86
- {
87
- request
88
- },
89
- `${request.indicatorKey}-${request.x}-${request.y}`
90
- ) : null,
91
- /* @__PURE__ */ jsxRuntime.jsx(DataFormatMenu, { request }),
92
- /* @__PURE__ */ jsxRuntime.jsx(DensityMenu, { request }),
93
- /* @__PURE__ */ jsxRuntime.jsx(
94
- MenuSubmenu,
95
- {
96
- label: "\u5BFC\u51FA",
97
- items: [
98
- {
99
- key: "export-csv",
100
- label: "\u5BFC\u51FA CSV",
101
- onClick: request.onExportCsv
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsxRuntime.jsx(
168
+ MenuAction,
169
+ {
170
+ label: "\u91CD\u7F6E\u6EDA\u52A8\u6761",
171
+ onClick: () => {
172
+ request.onResetScrollbar?.();
173
+ request.onClose();
174
+ }
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollbarCacheMenu, { request })
178
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
179
+ request.title ? /* @__PURE__ */ jsxRuntime.jsx(
180
+ "div",
181
+ {
182
+ style: {
183
+ padding: "6px 10px",
184
+ color: "#8f959e",
185
+ fontSize: 12
102
186
  },
103
- {
104
- key: "export-xlsx",
105
- label: "\u5BFC\u51FA XLSX",
106
- onClick: request.onExportXlsx
187
+ children: request.title
188
+ }
189
+ ) : null,
190
+ /* @__PURE__ */ jsxRuntime.jsx(
191
+ MenuSubmenu,
192
+ {
193
+ label: "\u590D\u5236",
194
+ items: [
195
+ {
196
+ key: "copy-cell",
197
+ label: request.target === "header" ? "\u590D\u5236\u8868\u5934" : "\u590D\u5236\u5355\u5143\u683C",
198
+ onClick: request.onCopy
199
+ },
200
+ {
201
+ key: "copy-selection",
202
+ label: "\u590D\u5236\u9009\u533A",
203
+ onClick: request.target === "header" ? void 0 : request.onCopySelection
204
+ },
205
+ ...["all", "selection", "viewport"].map(
206
+ (scope) => ({
207
+ key: `copy-image-${scope}`,
208
+ label: `\u590D\u5236\u4E3A\u56FE\u7247 \xB7 ${{ all: "\u6240\u6709\u533A\u57DF", selection: "\u9009\u4E2D\u533A\u57DF", viewport: "\u89C6\u53E3\u533A\u57DF" }[scope]}`,
209
+ onClick: scope === "selection" && !request.hasImageSelection ? void 0 : request.onCopyImage ? () => request.onCopyImage?.(scope) : void 0
210
+ })
211
+ )
212
+ ],
213
+ children: request.target !== "header" ? /* @__PURE__ */ jsxRuntime.jsx(CustomSelectionMenu, { request }) : null
214
+ }
215
+ ),
216
+ request.target === "header" ? /* @__PURE__ */ jsxRuntime.jsx(HeaderMenu, { request }) : null,
217
+ request.target === "summary" ? /* @__PURE__ */ jsxRuntime.jsx(
218
+ SummaryMenu,
219
+ {
220
+ request
221
+ },
222
+ `${request.indicatorKey}-${request.x}-${request.y}`
223
+ ) : null,
224
+ /* @__PURE__ */ jsxRuntime.jsx(DataFormatMenu, { request }),
225
+ /* @__PURE__ */ jsxRuntime.jsx(DensityMenu, { request }),
226
+ /* @__PURE__ */ jsxRuntime.jsx(
227
+ ScrollbarModeMenu,
228
+ {
229
+ request,
230
+ onOpenSettings: openScrollbarSettings
231
+ }
232
+ ),
233
+ /* @__PURE__ */ jsxRuntime.jsx(
234
+ MenuAction,
235
+ {
236
+ label: "\u6EDA\u52A8\u5230\u6307\u5B9A\u884C / \u5217",
237
+ onClick: () => {
238
+ setScrollbarPositionRequest(request);
239
+ request.onClose();
107
240
  }
108
- ]
109
- }
110
- ),
111
- request.recordCount != null ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "8px 10px", color: "#8f959e", fontSize: 12 }, children: [
112
- "\u4E0B\u94BB\u8BB0\u5F55 ",
113
- request.recordCount,
114
- " \u6761"
115
- ] }) : null
116
- ] })
117
- }
118
- );
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollbarCacheMenu, { request }),
244
+ /* @__PURE__ */ jsxRuntime.jsx(
245
+ MenuSubmenu,
246
+ {
247
+ label: "\u91CD\u7F6E",
248
+ items: [
249
+ {
250
+ key: "reset-scrollbar",
251
+ label: "\u91CD\u7F6E\u6EDA\u52A8\u6761",
252
+ onClick: () => {
253
+ request.onResetScrollbar?.();
254
+ request.onClose();
255
+ }
256
+ }
257
+ ]
258
+ }
259
+ ),
260
+ /* @__PURE__ */ jsxRuntime.jsx(
261
+ MenuSubmenu,
262
+ {
263
+ label: "\u5BFC\u51FA",
264
+ items: [
265
+ {
266
+ key: "export-csv",
267
+ label: "\u5BFC\u51FA CSV",
268
+ onClick: exportAndClose(request.onExportCsv)
269
+ },
270
+ {
271
+ key: "export-xlsx",
272
+ label: "\u5BFC\u51FA XLSX",
273
+ onClick: exportAndClose(request.onExportXlsx)
274
+ },
275
+ ...["all", "selection", "viewport"].map(
276
+ (scope) => ({
277
+ key: `export-image-${scope}`,
278
+ label: `\u5BFC\u51FA\u56FE\u7247 \xB7 ${{ all: "\u6240\u6709\u533A\u57DF", selection: "\u9009\u4E2D\u533A\u57DF", viewport: "\u89C6\u53E3\u533A\u57DF" }[scope]}`,
279
+ onClick: exportAndClose(
280
+ scope === "selection" && !request.hasImageSelection ? void 0 : request.onExportImage ? () => request.onExportImage?.(scope) : void 0
281
+ )
282
+ })
283
+ )
284
+ ]
285
+ }
286
+ ),
287
+ request.recordCount != null ? /* @__PURE__ */ jsxRuntime.jsxs(
288
+ "div",
289
+ {
290
+ style: {
291
+ padding: "8px 10px",
292
+ color: "#8f959e",
293
+ fontSize: 12
294
+ },
295
+ children: [
296
+ "\u4E0B\u94BB\u8BB0\u5F55 ",
297
+ request.recordCount,
298
+ " \u6761"
299
+ ]
300
+ }
301
+ ) : null
302
+ ] }) })
303
+ }
304
+ )
305
+ ] });
119
306
  }
120
307
  function HeaderMenu(props) {
121
308
  const { request } = props;
@@ -817,54 +1004,15 @@ function DataFormatMenu(props) {
817
1004
  );
818
1005
  }
819
1006
  function PivotExportNameDialog({
820
- request
1007
+ request,
1008
+ onClose
821
1009
  }) {
822
- const extension = request.fileName.match(/\.(xlsx|csv)$/i)?.[0] ?? "";
823
- const [fileName, setFileName] = react.useState(
824
- extension ? request.fileName.slice(0, -extension.length) : request.fileName
825
- );
826
- const [invalid, setInvalid] = react.useState(false);
827
- const confirm = () => {
828
- if (!fileName.trim()) {
829
- setInvalid(true);
830
- return;
831
- }
832
- request.onConfirm(`${fileName.trim()}${extension}`);
833
- };
834
- return /* @__PURE__ */ jsxRuntime.jsxs(
835
- reactComponents.ReactModal,
1010
+ return /* @__PURE__ */ jsxRuntime.jsx(
1011
+ reactListTable.ReactListTableExportNameDialog,
836
1012
  {
837
- open: true,
838
- title: "\u5BFC\u51FA\u6587\u4EF6",
839
- width: 420,
840
- fullscreenable: false,
841
- onCancel: request.onCancel,
842
- onOk: confirm,
843
- okText: "\u5BFC\u51FA",
844
- cancelText: "\u53D6\u6D88",
845
- children: [
846
- /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
847
- "\u6587\u4EF6\u540D\u79F0",
848
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
849
- /* @__PURE__ */ jsxRuntime.jsx(
850
- reactComponents.ReactInput,
851
- {
852
- autoFocus: true,
853
- value: fileName,
854
- placeholder: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0",
855
- onFocus: (event) => event.target.select(),
856
- onChange: (event) => {
857
- setFileName(event.target.value);
858
- setInvalid(false);
859
- },
860
- onPressEnter: confirm
861
- }
862
- ),
863
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": "\u6587\u4EF6\u540E\u7F00", style: { flexShrink: 0 }, children: extension })
864
- ] })
865
- ] }),
866
- invalid ? /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", style: { color: "#ff4d4f", marginTop: 8 }, children: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0" }) : null
867
- ]
1013
+ request,
1014
+ onClose,
1015
+ renderTable: (props) => /* @__PURE__ */ jsxRuntime.jsx(reactListTable.ReactListTable, { ...props })
868
1016
  }
869
1017
  );
870
1018
  }
@@ -1857,7 +2005,14 @@ function resolveReactPivotTableDebugOptions(debug, inheritedEnabled) {
1857
2005
  };
1858
2006
  }
1859
2007
  function ReactPivotTableInner(props, ref) {
1860
- const { className, style, customization, title, ...tableOptions } = props;
2008
+ const {
2009
+ className,
2010
+ style,
2011
+ customization,
2012
+ pivotAreas,
2013
+ title,
2014
+ ...tableOptions
2015
+ } = props;
1861
2016
  const inheritedDebugEnabled = useReactPivotTableDebugEnabled();
1862
2017
  const resolvedDebug = react.useMemo(
1863
2018
  () => resolveReactPivotTableDebugOptions(
@@ -1870,6 +2025,7 @@ function ReactPivotTableInner(props, ref) {
1870
2025
  const tableRef = react.useRef(null);
1871
2026
  const customizationOptions = customization && typeof customization === "object" ? customization : void 0;
1872
2027
  const customizationEnabled = customization === true || customizationOptions != null;
2028
+ const pivotLayoutEnabled = customizationEnabled || pivotAreas != null;
1873
2029
  const [internalPanelOpen, setInternalPanelOpen] = react.useState(
1874
2030
  customizationOptions?.defaultOpen ?? false
1875
2031
  );
@@ -1884,13 +2040,35 @@ function ReactPivotTableInner(props, ref) {
1884
2040
  const chartIdRef = react.useRef(0);
1885
2041
  const layoutRevisionRef = react.useRef(0);
1886
2042
  const [internalLayout, setInternalLayout] = react.useState(
1887
- () => customizationOptions?.defaultLayout ?? pivotTable.createEmptyPivotFieldLayout()
2043
+ () => pivotAreas ?? customizationOptions?.defaultLayout ?? pivotTable.createPivotFieldLayout({
2044
+ filterDimensions: tableOptions.filterDimensions,
2045
+ columns: tableOptions.columns,
2046
+ rows: tableOptions.rows,
2047
+ indicators: tableOptions.indicators
2048
+ })
1888
2049
  );
1889
2050
  const [fieldOverrides, setFieldOverrides] = react.useState({});
1890
2051
  const [densityOverride, setDensityOverride] = react.useState(null);
2052
+ const [scrollbarOverride, setScrollbarOverride] = react.useState(null);
2053
+ const [sharedScrollbar, setSharedScrollbar] = react.useState(
2054
+ reactComponents.getSharedScrollbarSettings
2055
+ );
2056
+ react.useEffect(
2057
+ () => reactComponents.subscribeSharedScrollbarSettings(
2058
+ () => setSharedScrollbar(reactComponents.getSharedScrollbarSettings())
2059
+ ),
2060
+ []
2061
+ );
2062
+ const [scrollbarCacheEnabled, setScrollbarCacheEnabled] = react.useState(true);
2063
+ const scrollbarRevisionRef = react.useRef(0);
2064
+ const scrollbarStorageKey = customizationOptions?.storageKey;
2065
+ const effectiveScrollbar = sharedScrollbar.shared ? sharedScrollbar.value : scrollbarOverride ?? tableOptions.scrollbar;
1891
2066
  const [filterRequest, setFilterRequest] = react.useState(null);
1892
2067
  const [contextMenuRequest, setContextMenuRequest] = react.useState(null);
1893
2068
  const [exportNameRequest, setExportNameRequest] = react.useState(null);
2069
+ const [exportLoadingText, setExportLoadingText] = react.useState(
2070
+ null
2071
+ );
1894
2072
  const [tooltipRequest, setTooltipRequest] = react.useState(null);
1895
2073
  const panelOpen = customizationOptions?.open ?? internalPanelOpen;
1896
2074
  const fieldLayout = customizationOptions?.layout ?? internalLayout;
@@ -1942,8 +2120,8 @@ function ReactPivotTableInner(props, ref) {
1942
2120
  [baseFields, fieldOverrides]
1943
2121
  );
1944
2122
  const customizedOptions = react.useMemo(
1945
- () => customizationEnabled ? pivotTable.resolvePivotFieldLayoutOptions(fields, fieldLayout) : null,
1946
- [customizationEnabled, fieldLayout, fields]
2123
+ () => pivotLayoutEnabled ? pivotTable.resolvePivotFieldLayoutOptions(fields, fieldLayout) : null,
2124
+ [pivotLayoutEnabled, fieldLayout, fields]
1947
2125
  );
1948
2126
  const overriddenIndicators = react.useMemo(
1949
2127
  () => tableOptions.indicators.map((indicator) => {
@@ -1967,10 +2145,12 @@ function ReactPivotTableInner(props, ref) {
1967
2145
  const options = {
1968
2146
  ...tableOptions,
1969
2147
  ...customizedOptions,
2148
+ scrollbar: effectiveScrollbar,
1970
2149
  debug: resolvedDebug,
1971
2150
  rowHeight: densityOverride == null ? tableOptions.rowHeight : resolveDensityRowHeight(densityOverride),
1972
2151
  indicators: customizedOptions?.indicators ?? overriddenIndicators,
1973
2152
  ui: {
2153
+ onLoadingRequest: (request) => setExportLoadingText(request ? request.text ?? "\u6B63\u5728\u5BFC\u51FA\u2026" : null),
1974
2154
  onExportNameRequest: (request) => {
1975
2155
  setExportNameRequest(request);
1976
2156
  },
@@ -1981,6 +2161,39 @@ function ReactPivotTableInner(props, ref) {
1981
2161
  const fieldKey = request.indicatorKey;
1982
2162
  const enhancedRequest = {
1983
2163
  ...request,
2164
+ scrollbar: effectiveScrollbar,
2165
+ cacheScrollbar: scrollbarCacheEnabled,
2166
+ scrollbarCacheAvailable: Boolean(scrollbarStorageKey),
2167
+ onChangeCacheScrollbar: (enabled) => {
2168
+ setScrollbarCacheEnabled(enabled);
2169
+ scrollbarRevisionRef.current += 1;
2170
+ if (scrollbarStorageKey)
2171
+ void pivotTable.savePivotScrollbarConfig(scrollbarStorageKey, {
2172
+ enabled,
2173
+ scrollbar: enabled ? effectiveScrollbar : void 0
2174
+ });
2175
+ },
2176
+ onChangeScrollbar: (value) => {
2177
+ setScrollbarOverride(value);
2178
+ if (reactComponents.getSharedScrollbarSettings().shared)
2179
+ reactComponents.setSharedScrollbarSettings({ shared: true, value });
2180
+ scrollbarRevisionRef.current += 1;
2181
+ if (scrollbarStorageKey && scrollbarCacheEnabled)
2182
+ void pivotTable.savePivotScrollbarConfig(scrollbarStorageKey, {
2183
+ enabled: true,
2184
+ scrollbar: value
2185
+ });
2186
+ },
2187
+ onResetScrollbar: () => {
2188
+ setScrollbarOverride(null);
2189
+ if (reactComponents.getSharedScrollbarSettings().shared)
2190
+ reactComponents.setSharedScrollbarSettings({ shared: true, value: {} });
2191
+ scrollbarRevisionRef.current += 1;
2192
+ if (scrollbarStorageKey && scrollbarCacheEnabled)
2193
+ void pivotTable.savePivotScrollbarConfig(scrollbarStorageKey, {
2194
+ enabled: true
2195
+ });
2196
+ },
1984
2197
  onChangeDensity: (density) => {
1985
2198
  nativeChangeDensity?.(density);
1986
2199
  setDensityOverride(density);
@@ -2118,6 +2331,21 @@ function ReactPivotTableInner(props, ref) {
2118
2331
  table.updateOptions(options);
2119
2332
  refreshChartModel();
2120
2333
  }, [options]);
2334
+ react.useEffect(() => {
2335
+ if (!scrollbarStorageKey) return;
2336
+ let active = true;
2337
+ const revision = scrollbarRevisionRef.current;
2338
+ void pivotTable.loadPivotScrollbarConfig(scrollbarStorageKey).then((stored) => {
2339
+ if (!active || scrollbarRevisionRef.current !== revision || !stored)
2340
+ return;
2341
+ setScrollbarCacheEnabled(stored.enabled);
2342
+ if (stored.enabled && stored.scrollbar)
2343
+ setScrollbarOverride(stored.scrollbar);
2344
+ });
2345
+ return () => {
2346
+ active = false;
2347
+ };
2348
+ }, [scrollbarStorageKey]);
2121
2349
  react.useEffect(() => {
2122
2350
  const storageKey = customizationOptions?.storageKey;
2123
2351
  if (!storageKey || customizationOptions?.layout !== void 0) return;
@@ -2190,11 +2418,27 @@ function ReactPivotTableInner(props, ref) {
2190
2418
  {
2191
2419
  className: `react-pivot-table${className ? ` ${className}` : ""}`,
2192
2420
  style: {
2421
+ position: "relative",
2193
2422
  width: props.width ?? "100%",
2194
2423
  height: props.height ?? "100%",
2195
2424
  ...style
2196
2425
  },
2197
2426
  children: [
2427
+ exportLoadingText ? /* @__PURE__ */ jsxRuntime.jsx(
2428
+ "div",
2429
+ {
2430
+ role: "status",
2431
+ style: {
2432
+ position: "absolute",
2433
+ inset: 0,
2434
+ zIndex: 10,
2435
+ display: "grid",
2436
+ placeItems: "center",
2437
+ background: "rgba(255,255,255,0.75)"
2438
+ },
2439
+ children: exportLoadingText
2440
+ }
2441
+ ) : null,
2198
2442
  /* @__PURE__ */ jsxRuntime.jsx(
2199
2443
  PivotTitlebar,
2200
2444
  {
@@ -2287,7 +2531,13 @@ function ReactPivotTableInner(props, ref) {
2287
2531
  ),
2288
2532
  /* @__PURE__ */ jsxRuntime.jsx(reactComponents.ReactFilterPanel, { request: sharedFilterRequest }),
2289
2533
  /* @__PURE__ */ jsxRuntime.jsx(PivotContextMenu, { request: contextMenuRequest }),
2290
- exportNameRequest ? /* @__PURE__ */ jsxRuntime.jsx(PivotExportNameDialog, { request: exportNameRequest }) : null,
2534
+ exportNameRequest ? /* @__PURE__ */ jsxRuntime.jsx(
2535
+ PivotExportNameDialog,
2536
+ {
2537
+ request: exportNameRequest,
2538
+ onClose: () => setExportNameRequest(null)
2539
+ }
2540
+ ) : null,
2291
2541
  /* @__PURE__ */ jsxRuntime.jsx(PivotTooltip, { request: tooltipRequest })
2292
2542
  ] });
2293
2543
  }