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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties, ReactNode, ForwardedRef, PropsWithChildren } from 'react';
3
- import { PivotTableOptions, PivotField, PivotFieldLayout, PivotTable, PivotModel, PivotSelectionState, PivotFilterState, PivotSortRule, PivotCellAddress, PivotAxis, PivotFilterAxis, PivotDimensionFilter, PivotFilterOptionItem, PivotExportOptions, PivotTableStateSnapshot } from '@canvas-components/pivot-table';
3
+ import { PivotTableOptions, PivotFieldLayout, PivotField, PivotTable, PivotModel, PivotSelectionState, PivotFilterState, PivotSortRule, PivotCellAddress, PivotAxis, PivotFilterAxis, PivotDimensionFilter, PivotFilterOptionItem, PivotExportOptions, PivotTableStateSnapshot } from '@canvas-components/pivot-table';
4
4
 
5
5
  /** PivotTable 自定义字段面板配置。 */
6
6
  interface ReactPivotTableCustomizationOptions<RecordType = Record<string, unknown>> {
@@ -28,6 +28,8 @@ interface ReactPivotTableProps<RecordType = Record<string, unknown>> extends Omi
28
28
  style?: CSSProperties;
29
29
  /** 标题栏左侧内容。 */
30
30
  title?: ReactNode;
31
+ /** 初始透视字段区域;字段 key 从行、列、指标及 customization.fields 中查找,已缓存布局优先。 */
32
+ pivotAreas?: PivotFieldLayout;
31
33
  /** 开启字段自定义模式及右侧字段面板。 */
32
34
  customization?: boolean | ReactPivotTableCustomizationOptions<RecordType>;
33
35
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties, ReactNode, ForwardedRef, PropsWithChildren } from 'react';
3
- import { PivotTableOptions, PivotField, PivotFieldLayout, PivotTable, PivotModel, PivotSelectionState, PivotFilterState, PivotSortRule, PivotCellAddress, PivotAxis, PivotFilterAxis, PivotDimensionFilter, PivotFilterOptionItem, PivotExportOptions, PivotTableStateSnapshot } from '@canvas-components/pivot-table';
3
+ import { PivotTableOptions, PivotFieldLayout, PivotField, PivotTable, PivotModel, PivotSelectionState, PivotFilterState, PivotSortRule, PivotCellAddress, PivotAxis, PivotFilterAxis, PivotDimensionFilter, PivotFilterOptionItem, PivotExportOptions, PivotTableStateSnapshot } from '@canvas-components/pivot-table';
4
4
 
5
5
  /** PivotTable 自定义字段面板配置。 */
6
6
  interface ReactPivotTableCustomizationOptions<RecordType = Record<string, unknown>> {
@@ -28,6 +28,8 @@ interface ReactPivotTableProps<RecordType = Record<string, unknown>> extends Omi
28
28
  style?: CSSProperties;
29
29
  /** 标题栏左侧内容。 */
30
30
  title?: ReactNode;
31
+ /** 初始透视字段区域;字段 key 从行、列、指标及 customization.fields 中查找,已缓存布局优先。 */
32
+ pivotAreas?: PivotFieldLayout;
31
33
  /** 开启字段自定义模式及右侧字段面板。 */
32
34
  customization?: boolean | ReactPivotTableCustomizationOptions<RecordType>;
33
35
  }
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createContext, forwardRef, useMemo, useRef, useState, useEffect, useImperativeHandle, useContext, Fragment as Fragment$1 } from 'react';
2
- import { createEmptyPivotFieldLayout, createPivotFieldCatalog, resolvePivotDimensionKey, resolvePivotFieldLayoutOptions, PivotTable, loadPivotFieldLayout, DEFAULT_PIVOT_TABLE_DEBUG_OPTIONS, getValueByDataIndex, resolvePivotDimensionTitle, findPivotFieldArea, removePivotField, movePivotField, resolvePivotValueFieldTitle, savePivotFieldLayout, createPivotCellKey } from '@canvas-components/pivot-table';
3
- import { ReactResizablePanels, ReactFilterPanel, ReactPopup, ReactCheckbox, ReactModal, ReactInput, ReactSelect, ReactInputNumber } from '@canvas-components/react-components';
2
+ import { createPivotFieldLayout, createPivotFieldCatalog, resolvePivotDimensionKey, resolvePivotFieldLayoutOptions, PivotTable, loadPivotScrollbarConfig, loadPivotFieldLayout, DEFAULT_PIVOT_TABLE_DEBUG_OPTIONS, getValueByDataIndex, resolvePivotDimensionTitle, findPivotFieldArea, removePivotField, movePivotField, savePivotScrollbarConfig, resolvePivotValueFieldTitle, savePivotFieldLayout, createPivotCellKey } from '@canvas-components/pivot-table';
3
+ import { getSharedScrollbarSettings, subscribeSharedScrollbarSettings, ReactResizablePanels, ReactFilterPanel, ReactPopup, ReactCheckbox, ReactScrollbarSettingsDialog, ReactScrollbarPositionDialog, setSharedScrollbarSettings, ReactInput, ReactSelect, ReactButton, ReactInputNumber } from '@canvas-components/react-components';
4
4
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
5
+ import { ReactListTableExportNameDialog, ReactListTable } from '@canvas-components/react-list-table';
5
6
  import { createPortal } from 'react-dom';
6
7
  import { CanvasChart } from '@canvas-components/chart';
7
8
 
@@ -37,83 +38,269 @@ var CONTEXT_MENU_SURFACE_STYLE = {
37
38
  boxShadow: "0 8px 24px rgba(15, 23, 42, 0.16)",
38
39
  fontSize: 14
39
40
  };
41
+ function ScrollbarModeMenu(props) {
42
+ const { request, onOpenSettings } = props;
43
+ return /* @__PURE__ */ jsx(
44
+ MenuSubmenu,
45
+ {
46
+ label: "\u6EDA\u52A8\u6761\u6A21\u5F0F",
47
+ items: [
48
+ ["scrollbar", "\u6EDA\u52A8\u6761"],
49
+ ["button", "\u6309\u94AE"]
50
+ ].map(([mode, label]) => ({
51
+ key: `scrollbar-mode-${mode}`,
52
+ label,
53
+ selected: (request.scrollbar?.mode ?? "scrollbar") === mode,
54
+ onClick: () => {
55
+ request.onChangeScrollbar?.({
56
+ ...request.scrollbar,
57
+ mode,
58
+ horizontal: request.scrollbar?.horizontal === false ? false : { ...request.scrollbar?.horizontal, mode },
59
+ vertical: request.scrollbar?.vertical === false ? false : { ...request.scrollbar?.vertical, mode }
60
+ });
61
+ request.onClose();
62
+ }
63
+ })),
64
+ footer: /* @__PURE__ */ jsx(ReactButton, { onClick: onOpenSettings, children: "\u914D\u7F6E\u6EDA\u52A8\u6761\u5C5E\u6027" })
65
+ }
66
+ );
67
+ }
68
+ function ScrollbarCacheMenu(props) {
69
+ const { request } = props;
70
+ return /* @__PURE__ */ jsx(
71
+ MenuSubmenu,
72
+ {
73
+ label: "\u7F13\u5B58\u5230\u672C\u5730",
74
+ items: [
75
+ {
76
+ key: "cache-scrollbar",
77
+ label: "\u6EDA\u52A8\u6761",
78
+ selected: request.scrollbarCacheAvailable === true && request.cacheScrollbar !== false,
79
+ disabled: request.scrollbarCacheAvailable !== true,
80
+ onClick: () => request.onChangeCacheScrollbar?.(request.cacheScrollbar === false)
81
+ }
82
+ ]
83
+ }
84
+ );
85
+ }
40
86
  function PivotContextMenu(props) {
41
87
  const { request } = props;
42
88
  const [menuOpen, setMenuOpen] = useState(true);
89
+ const [scrollbarSettingsRequest, setScrollbarSettingsRequest] = useState(null);
90
+ const [scrollbarPositionRequest, setScrollbarPositionRequest] = useState(null);
43
91
  useEffect(() => {
44
92
  if (request) setMenuOpen(true);
45
93
  }, [request]);
46
- if (!request) return null;
47
- return /* @__PURE__ */ jsx(
48
- ReactPopup,
94
+ const scrollbarDialog = scrollbarSettingsRequest ? /* @__PURE__ */ jsx(
95
+ ReactScrollbarSettingsDialog,
49
96
  {
50
- open: menuOpen,
51
- anchorRect: { x: request.x, y: request.y, width: 0, height: 0 },
52
- offset: 4,
53
- matchAnchorWidth: false,
54
- minWidth: 260,
55
- onOpenChange: (open) => {
56
- setMenuOpen(open);
57
- if (!open) request.onClose();
97
+ value: scrollbarSettingsRequest.scrollbar,
98
+ onConfirm: (value) => {
99
+ scrollbarSettingsRequest.onChangeScrollbar?.({
100
+ ...scrollbarSettingsRequest.scrollbar,
101
+ ...value
102
+ });
103
+ setScrollbarSettingsRequest(null);
58
104
  },
59
- surfaceStyle: { ...CONTEXT_MENU_SURFACE_STYLE, width: 260 },
60
- children: /* @__PURE__ */ jsxs("div", { children: [
61
- request.title ? /* @__PURE__ */ jsx("div", { style: { padding: "6px 10px", color: "#8f959e", fontSize: 12 }, children: request.title }) : null,
62
- /* @__PURE__ */ jsx(
63
- MenuSubmenu,
64
- {
65
- label: "\u590D\u5236",
66
- items: [
67
- {
68
- key: "copy-cell",
69
- label: request.target === "header" ? "\u590D\u5236\u8868\u5934" : "\u590D\u5236\u5355\u5143\u683C",
70
- onClick: request.onCopy
71
- },
72
- {
73
- key: "copy-selection",
74
- label: "\u590D\u5236\u9009\u533A",
75
- onClick: request.target === "header" ? void 0 : request.onCopySelection
105
+ onClose: () => setScrollbarSettingsRequest(null)
106
+ }
107
+ ) : null;
108
+ const scrollbarPositionDialog = scrollbarPositionRequest ? /* @__PURE__ */ jsx(
109
+ ReactScrollbarPositionDialog,
110
+ {
111
+ rowCount: scrollbarPositionRequest.scrollbarRowCount ?? 0,
112
+ columnCount: scrollbarPositionRequest.scrollbarColumnCount ?? 0,
113
+ onConfirm: (row, column) => scrollbarPositionRequest.onScrollToPosition?.(row, column),
114
+ onClose: () => setScrollbarPositionRequest(null)
115
+ }
116
+ ) : null;
117
+ if (!request)
118
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
119
+ scrollbarDialog,
120
+ scrollbarPositionDialog
121
+ ] });
122
+ const openScrollbarSettings = () => {
123
+ setScrollbarSettingsRequest(request);
124
+ request.onClose();
125
+ };
126
+ const exportAndClose = (action) => action ? () => {
127
+ setMenuOpen(false);
128
+ request.onClose();
129
+ action();
130
+ } : void 0;
131
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
132
+ scrollbarDialog,
133
+ scrollbarPositionDialog,
134
+ /* @__PURE__ */ jsx(
135
+ ReactPopup,
136
+ {
137
+ open: menuOpen,
138
+ anchorRect: { x: request.x, y: request.y, width: 0, height: 0 },
139
+ offset: 4,
140
+ matchAnchorWidth: false,
141
+ minWidth: 260,
142
+ onOpenChange: (open) => {
143
+ setMenuOpen(open);
144
+ if (!open) request.onClose();
145
+ },
146
+ surfaceStyle: { ...CONTEXT_MENU_SURFACE_STYLE, width: 260 },
147
+ children: /* @__PURE__ */ jsx("div", { children: request.target === "scrollbar" ? /* @__PURE__ */ jsxs(Fragment, { children: [
148
+ /* @__PURE__ */ jsx(
149
+ ScrollbarModeMenu,
150
+ {
151
+ request,
152
+ onOpenSettings: openScrollbarSettings
153
+ }
154
+ ),
155
+ /* @__PURE__ */ jsx(
156
+ MenuAction,
157
+ {
158
+ label: "\u6EDA\u52A8\u5230\u6307\u5B9A\u884C / \u5217",
159
+ onClick: () => {
160
+ setScrollbarPositionRequest(request);
161
+ request.onClose();
76
162
  }
77
- ],
78
- children: request.target !== "header" ? /* @__PURE__ */ jsx(CustomSelectionMenu, { request }) : null
79
- }
80
- ),
81
- request.target === "header" ? /* @__PURE__ */ jsx(HeaderMenu, { request }) : null,
82
- request.target === "summary" ? /* @__PURE__ */ jsx(
83
- SummaryMenu,
84
- {
85
- request
86
- },
87
- `${request.indicatorKey}-${request.x}-${request.y}`
88
- ) : null,
89
- /* @__PURE__ */ jsx(DataFormatMenu, { request }),
90
- /* @__PURE__ */ jsx(DensityMenu, { request }),
91
- /* @__PURE__ */ jsx(
92
- MenuSubmenu,
93
- {
94
- label: "\u5BFC\u51FA",
95
- items: [
96
- {
97
- key: "export-csv",
98
- label: "\u5BFC\u51FA CSV",
99
- onClick: request.onExportCsv
163
+ }
164
+ ),
165
+ /* @__PURE__ */ jsx(
166
+ MenuAction,
167
+ {
168
+ label: "\u91CD\u7F6E\u6EDA\u52A8\u6761",
169
+ onClick: () => {
170
+ request.onResetScrollbar?.();
171
+ request.onClose();
172
+ }
173
+ }
174
+ ),
175
+ /* @__PURE__ */ jsx(ScrollbarCacheMenu, { request })
176
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
177
+ request.title ? /* @__PURE__ */ jsx(
178
+ "div",
179
+ {
180
+ style: {
181
+ padding: "6px 10px",
182
+ color: "#8f959e",
183
+ fontSize: 12
100
184
  },
101
- {
102
- key: "export-xlsx",
103
- label: "\u5BFC\u51FA XLSX",
104
- onClick: request.onExportXlsx
185
+ children: request.title
186
+ }
187
+ ) : null,
188
+ /* @__PURE__ */ jsx(
189
+ MenuSubmenu,
190
+ {
191
+ label: "\u590D\u5236",
192
+ items: [
193
+ {
194
+ key: "copy-cell",
195
+ label: request.target === "header" ? "\u590D\u5236\u8868\u5934" : "\u590D\u5236\u5355\u5143\u683C",
196
+ onClick: request.onCopy
197
+ },
198
+ {
199
+ key: "copy-selection",
200
+ label: "\u590D\u5236\u9009\u533A",
201
+ onClick: request.target === "header" ? void 0 : request.onCopySelection
202
+ },
203
+ ...["all", "selection", "viewport"].map(
204
+ (scope) => ({
205
+ key: `copy-image-${scope}`,
206
+ label: `\u590D\u5236\u4E3A\u56FE\u7247 \xB7 ${{ all: "\u6240\u6709\u533A\u57DF", selection: "\u9009\u4E2D\u533A\u57DF", viewport: "\u89C6\u53E3\u533A\u57DF" }[scope]}`,
207
+ onClick: scope === "selection" && !request.hasImageSelection ? void 0 : request.onCopyImage ? () => request.onCopyImage?.(scope) : void 0
208
+ })
209
+ )
210
+ ],
211
+ children: request.target !== "header" ? /* @__PURE__ */ jsx(CustomSelectionMenu, { request }) : null
212
+ }
213
+ ),
214
+ request.target === "header" ? /* @__PURE__ */ jsx(HeaderMenu, { request }) : null,
215
+ request.target === "summary" ? /* @__PURE__ */ jsx(
216
+ SummaryMenu,
217
+ {
218
+ request
219
+ },
220
+ `${request.indicatorKey}-${request.x}-${request.y}`
221
+ ) : null,
222
+ /* @__PURE__ */ jsx(DataFormatMenu, { request }),
223
+ /* @__PURE__ */ jsx(DensityMenu, { request }),
224
+ /* @__PURE__ */ jsx(
225
+ ScrollbarModeMenu,
226
+ {
227
+ request,
228
+ onOpenSettings: openScrollbarSettings
229
+ }
230
+ ),
231
+ /* @__PURE__ */ jsx(
232
+ MenuAction,
233
+ {
234
+ label: "\u6EDA\u52A8\u5230\u6307\u5B9A\u884C / \u5217",
235
+ onClick: () => {
236
+ setScrollbarPositionRequest(request);
237
+ request.onClose();
105
238
  }
106
- ]
107
- }
108
- ),
109
- request.recordCount != null ? /* @__PURE__ */ jsxs("div", { style: { padding: "8px 10px", color: "#8f959e", fontSize: 12 }, children: [
110
- "\u4E0B\u94BB\u8BB0\u5F55 ",
111
- request.recordCount,
112
- " \u6761"
113
- ] }) : null
114
- ] })
115
- }
116
- );
239
+ }
240
+ ),
241
+ /* @__PURE__ */ jsx(ScrollbarCacheMenu, { request }),
242
+ /* @__PURE__ */ jsx(
243
+ MenuSubmenu,
244
+ {
245
+ label: "\u91CD\u7F6E",
246
+ items: [
247
+ {
248
+ key: "reset-scrollbar",
249
+ label: "\u91CD\u7F6E\u6EDA\u52A8\u6761",
250
+ onClick: () => {
251
+ request.onResetScrollbar?.();
252
+ request.onClose();
253
+ }
254
+ }
255
+ ]
256
+ }
257
+ ),
258
+ /* @__PURE__ */ jsx(
259
+ MenuSubmenu,
260
+ {
261
+ label: "\u5BFC\u51FA",
262
+ items: [
263
+ {
264
+ key: "export-csv",
265
+ label: "\u5BFC\u51FA CSV",
266
+ onClick: exportAndClose(request.onExportCsv)
267
+ },
268
+ {
269
+ key: "export-xlsx",
270
+ label: "\u5BFC\u51FA XLSX",
271
+ onClick: exportAndClose(request.onExportXlsx)
272
+ },
273
+ ...["all", "selection", "viewport"].map(
274
+ (scope) => ({
275
+ key: `export-image-${scope}`,
276
+ label: `\u5BFC\u51FA\u56FE\u7247 \xB7 ${{ all: "\u6240\u6709\u533A\u57DF", selection: "\u9009\u4E2D\u533A\u57DF", viewport: "\u89C6\u53E3\u533A\u57DF" }[scope]}`,
277
+ onClick: exportAndClose(
278
+ scope === "selection" && !request.hasImageSelection ? void 0 : request.onExportImage ? () => request.onExportImage?.(scope) : void 0
279
+ )
280
+ })
281
+ )
282
+ ]
283
+ }
284
+ ),
285
+ request.recordCount != null ? /* @__PURE__ */ jsxs(
286
+ "div",
287
+ {
288
+ style: {
289
+ padding: "8px 10px",
290
+ color: "#8f959e",
291
+ fontSize: 12
292
+ },
293
+ children: [
294
+ "\u4E0B\u94BB\u8BB0\u5F55 ",
295
+ request.recordCount,
296
+ " \u6761"
297
+ ]
298
+ }
299
+ ) : null
300
+ ] }) })
301
+ }
302
+ )
303
+ ] });
117
304
  }
118
305
  function HeaderMenu(props) {
119
306
  const { request } = props;
@@ -815,54 +1002,15 @@ function DataFormatMenu(props) {
815
1002
  );
816
1003
  }
817
1004
  function PivotExportNameDialog({
818
- request
1005
+ request,
1006
+ onClose
819
1007
  }) {
820
- const extension = request.fileName.match(/\.(xlsx|csv)$/i)?.[0] ?? "";
821
- const [fileName, setFileName] = useState(
822
- extension ? request.fileName.slice(0, -extension.length) : request.fileName
823
- );
824
- const [invalid, setInvalid] = useState(false);
825
- const confirm = () => {
826
- if (!fileName.trim()) {
827
- setInvalid(true);
828
- return;
829
- }
830
- request.onConfirm(`${fileName.trim()}${extension}`);
831
- };
832
- return /* @__PURE__ */ jsxs(
833
- ReactModal,
1008
+ return /* @__PURE__ */ jsx(
1009
+ ReactListTableExportNameDialog,
834
1010
  {
835
- open: true,
836
- title: "\u5BFC\u51FA\u6587\u4EF6",
837
- width: 420,
838
- fullscreenable: false,
839
- onCancel: request.onCancel,
840
- onOk: confirm,
841
- okText: "\u5BFC\u51FA",
842
- cancelText: "\u53D6\u6D88",
843
- children: [
844
- /* @__PURE__ */ jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
845
- "\u6587\u4EF6\u540D\u79F0",
846
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
847
- /* @__PURE__ */ jsx(
848
- ReactInput,
849
- {
850
- autoFocus: true,
851
- value: fileName,
852
- placeholder: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0",
853
- onFocus: (event) => event.target.select(),
854
- onChange: (event) => {
855
- setFileName(event.target.value);
856
- setInvalid(false);
857
- },
858
- onPressEnter: confirm
859
- }
860
- ),
861
- /* @__PURE__ */ jsx("span", { "aria-label": "\u6587\u4EF6\u540E\u7F00", style: { flexShrink: 0 }, children: extension })
862
- ] })
863
- ] }),
864
- invalid ? /* @__PURE__ */ jsx("div", { role: "alert", style: { color: "#ff4d4f", marginTop: 8 }, children: "\u8BF7\u8F93\u5165\u6587\u4EF6\u540D\u79F0" }) : null
865
- ]
1011
+ request,
1012
+ onClose,
1013
+ renderTable: (props) => /* @__PURE__ */ jsx(ReactListTable, { ...props })
866
1014
  }
867
1015
  );
868
1016
  }
@@ -1855,7 +2003,14 @@ function resolveReactPivotTableDebugOptions(debug, inheritedEnabled) {
1855
2003
  };
1856
2004
  }
1857
2005
  function ReactPivotTableInner(props, ref) {
1858
- const { className, style, customization, title, ...tableOptions } = props;
2006
+ const {
2007
+ className,
2008
+ style,
2009
+ customization,
2010
+ pivotAreas,
2011
+ title,
2012
+ ...tableOptions
2013
+ } = props;
1859
2014
  const inheritedDebugEnabled = useReactPivotTableDebugEnabled();
1860
2015
  const resolvedDebug = useMemo(
1861
2016
  () => resolveReactPivotTableDebugOptions(
@@ -1868,6 +2023,7 @@ function ReactPivotTableInner(props, ref) {
1868
2023
  const tableRef = useRef(null);
1869
2024
  const customizationOptions = customization && typeof customization === "object" ? customization : void 0;
1870
2025
  const customizationEnabled = customization === true || customizationOptions != null;
2026
+ const pivotLayoutEnabled = customizationEnabled || pivotAreas != null;
1871
2027
  const [internalPanelOpen, setInternalPanelOpen] = useState(
1872
2028
  customizationOptions?.defaultOpen ?? false
1873
2029
  );
@@ -1882,13 +2038,35 @@ function ReactPivotTableInner(props, ref) {
1882
2038
  const chartIdRef = useRef(0);
1883
2039
  const layoutRevisionRef = useRef(0);
1884
2040
  const [internalLayout, setInternalLayout] = useState(
1885
- () => customizationOptions?.defaultLayout ?? createEmptyPivotFieldLayout()
2041
+ () => pivotAreas ?? customizationOptions?.defaultLayout ?? createPivotFieldLayout({
2042
+ filterDimensions: tableOptions.filterDimensions,
2043
+ columns: tableOptions.columns,
2044
+ rows: tableOptions.rows,
2045
+ indicators: tableOptions.indicators
2046
+ })
1886
2047
  );
1887
2048
  const [fieldOverrides, setFieldOverrides] = useState({});
1888
2049
  const [densityOverride, setDensityOverride] = useState(null);
2050
+ const [scrollbarOverride, setScrollbarOverride] = useState(null);
2051
+ const [sharedScrollbar, setSharedScrollbar] = useState(
2052
+ getSharedScrollbarSettings
2053
+ );
2054
+ useEffect(
2055
+ () => subscribeSharedScrollbarSettings(
2056
+ () => setSharedScrollbar(getSharedScrollbarSettings())
2057
+ ),
2058
+ []
2059
+ );
2060
+ const [scrollbarCacheEnabled, setScrollbarCacheEnabled] = useState(true);
2061
+ const scrollbarRevisionRef = useRef(0);
2062
+ const scrollbarStorageKey = customizationOptions?.storageKey;
2063
+ const effectiveScrollbar = sharedScrollbar.shared ? sharedScrollbar.value : scrollbarOverride ?? tableOptions.scrollbar;
1889
2064
  const [filterRequest, setFilterRequest] = useState(null);
1890
2065
  const [contextMenuRequest, setContextMenuRequest] = useState(null);
1891
2066
  const [exportNameRequest, setExportNameRequest] = useState(null);
2067
+ const [exportLoadingText, setExportLoadingText] = useState(
2068
+ null
2069
+ );
1892
2070
  const [tooltipRequest, setTooltipRequest] = useState(null);
1893
2071
  const panelOpen = customizationOptions?.open ?? internalPanelOpen;
1894
2072
  const fieldLayout = customizationOptions?.layout ?? internalLayout;
@@ -1940,8 +2118,8 @@ function ReactPivotTableInner(props, ref) {
1940
2118
  [baseFields, fieldOverrides]
1941
2119
  );
1942
2120
  const customizedOptions = useMemo(
1943
- () => customizationEnabled ? resolvePivotFieldLayoutOptions(fields, fieldLayout) : null,
1944
- [customizationEnabled, fieldLayout, fields]
2121
+ () => pivotLayoutEnabled ? resolvePivotFieldLayoutOptions(fields, fieldLayout) : null,
2122
+ [pivotLayoutEnabled, fieldLayout, fields]
1945
2123
  );
1946
2124
  const overriddenIndicators = useMemo(
1947
2125
  () => tableOptions.indicators.map((indicator) => {
@@ -1965,10 +2143,12 @@ function ReactPivotTableInner(props, ref) {
1965
2143
  const options = {
1966
2144
  ...tableOptions,
1967
2145
  ...customizedOptions,
2146
+ scrollbar: effectiveScrollbar,
1968
2147
  debug: resolvedDebug,
1969
2148
  rowHeight: densityOverride == null ? tableOptions.rowHeight : resolveDensityRowHeight(densityOverride),
1970
2149
  indicators: customizedOptions?.indicators ?? overriddenIndicators,
1971
2150
  ui: {
2151
+ onLoadingRequest: (request) => setExportLoadingText(request ? request.text ?? "\u6B63\u5728\u5BFC\u51FA\u2026" : null),
1972
2152
  onExportNameRequest: (request) => {
1973
2153
  setExportNameRequest(request);
1974
2154
  },
@@ -1979,6 +2159,39 @@ function ReactPivotTableInner(props, ref) {
1979
2159
  const fieldKey = request.indicatorKey;
1980
2160
  const enhancedRequest = {
1981
2161
  ...request,
2162
+ scrollbar: effectiveScrollbar,
2163
+ cacheScrollbar: scrollbarCacheEnabled,
2164
+ scrollbarCacheAvailable: Boolean(scrollbarStorageKey),
2165
+ onChangeCacheScrollbar: (enabled) => {
2166
+ setScrollbarCacheEnabled(enabled);
2167
+ scrollbarRevisionRef.current += 1;
2168
+ if (scrollbarStorageKey)
2169
+ void savePivotScrollbarConfig(scrollbarStorageKey, {
2170
+ enabled,
2171
+ scrollbar: enabled ? effectiveScrollbar : void 0
2172
+ });
2173
+ },
2174
+ onChangeScrollbar: (value) => {
2175
+ setScrollbarOverride(value);
2176
+ if (getSharedScrollbarSettings().shared)
2177
+ setSharedScrollbarSettings({ shared: true, value });
2178
+ scrollbarRevisionRef.current += 1;
2179
+ if (scrollbarStorageKey && scrollbarCacheEnabled)
2180
+ void savePivotScrollbarConfig(scrollbarStorageKey, {
2181
+ enabled: true,
2182
+ scrollbar: value
2183
+ });
2184
+ },
2185
+ onResetScrollbar: () => {
2186
+ setScrollbarOverride(null);
2187
+ if (getSharedScrollbarSettings().shared)
2188
+ setSharedScrollbarSettings({ shared: true, value: {} });
2189
+ scrollbarRevisionRef.current += 1;
2190
+ if (scrollbarStorageKey && scrollbarCacheEnabled)
2191
+ void savePivotScrollbarConfig(scrollbarStorageKey, {
2192
+ enabled: true
2193
+ });
2194
+ },
1982
2195
  onChangeDensity: (density) => {
1983
2196
  nativeChangeDensity?.(density);
1984
2197
  setDensityOverride(density);
@@ -2116,6 +2329,21 @@ function ReactPivotTableInner(props, ref) {
2116
2329
  table.updateOptions(options);
2117
2330
  refreshChartModel();
2118
2331
  }, [options]);
2332
+ useEffect(() => {
2333
+ if (!scrollbarStorageKey) return;
2334
+ let active = true;
2335
+ const revision = scrollbarRevisionRef.current;
2336
+ void loadPivotScrollbarConfig(scrollbarStorageKey).then((stored) => {
2337
+ if (!active || scrollbarRevisionRef.current !== revision || !stored)
2338
+ return;
2339
+ setScrollbarCacheEnabled(stored.enabled);
2340
+ if (stored.enabled && stored.scrollbar)
2341
+ setScrollbarOverride(stored.scrollbar);
2342
+ });
2343
+ return () => {
2344
+ active = false;
2345
+ };
2346
+ }, [scrollbarStorageKey]);
2119
2347
  useEffect(() => {
2120
2348
  const storageKey = customizationOptions?.storageKey;
2121
2349
  if (!storageKey || customizationOptions?.layout !== void 0) return;
@@ -2188,11 +2416,27 @@ function ReactPivotTableInner(props, ref) {
2188
2416
  {
2189
2417
  className: `react-pivot-table${className ? ` ${className}` : ""}`,
2190
2418
  style: {
2419
+ position: "relative",
2191
2420
  width: props.width ?? "100%",
2192
2421
  height: props.height ?? "100%",
2193
2422
  ...style
2194
2423
  },
2195
2424
  children: [
2425
+ exportLoadingText ? /* @__PURE__ */ jsx(
2426
+ "div",
2427
+ {
2428
+ role: "status",
2429
+ style: {
2430
+ position: "absolute",
2431
+ inset: 0,
2432
+ zIndex: 10,
2433
+ display: "grid",
2434
+ placeItems: "center",
2435
+ background: "rgba(255,255,255,0.75)"
2436
+ },
2437
+ children: exportLoadingText
2438
+ }
2439
+ ) : null,
2196
2440
  /* @__PURE__ */ jsx(
2197
2441
  PivotTitlebar,
2198
2442
  {
@@ -2285,7 +2529,13 @@ function ReactPivotTableInner(props, ref) {
2285
2529
  ),
2286
2530
  /* @__PURE__ */ jsx(ReactFilterPanel, { request: sharedFilterRequest }),
2287
2531
  /* @__PURE__ */ jsx(PivotContextMenu, { request: contextMenuRequest }),
2288
- exportNameRequest ? /* @__PURE__ */ jsx(PivotExportNameDialog, { request: exportNameRequest }) : null,
2532
+ exportNameRequest ? /* @__PURE__ */ jsx(
2533
+ PivotExportNameDialog,
2534
+ {
2535
+ request: exportNameRequest,
2536
+ onClose: () => setExportNameRequest(null)
2537
+ }
2538
+ ) : null,
2289
2539
  /* @__PURE__ */ jsx(PivotTooltip, { request: tooltipRequest })
2290
2540
  ] });
2291
2541
  }