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

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.cjs CHANGED
@@ -32,11 +32,12 @@ function styleInject(css, { insertAt } = {}) {
32
32
  }
33
33
 
34
34
  // src/features/context-menu/pivot-context-menu.css
35
- styleInject(".react-pivot-table-menu-action {\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n.react-pivot-table-menu-action:hover {\n background: #f3f4f6 !important;\n}\n.react-pivot-table-menu-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.react-pivot-table-menu-action:hover .react-pivot-table-menu-chevron,\n.react-pivot-table-menu-chevron-active {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n");
35
+ styleInject(".react-pivot-table-menu-action {\n font-size: inherit;\n transition: background-color 0.2s ease, color 0.2s ease;\n}\n.react-pivot-table-menu-action:hover {\n background: #f3f4f6 !important;\n}\n.react-pivot-table-menu-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.react-pivot-table-menu-action:hover .react-pivot-table-menu-chevron,\n.react-pivot-table-menu-chevron-active {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n");
36
36
  var CONTEXT_MENU_SURFACE_STYLE = {
37
37
  padding: 8,
38
38
  background: "#ffffff",
39
- boxShadow: "0 8px 24px rgba(15, 23, 42, 0.16)"
39
+ boxShadow: "0 8px 24px rgba(15, 23, 42, 0.16)",
40
+ fontSize: 14
40
41
  };
41
42
  function PivotContextMenu(props) {
42
43
  const { request } = props;
@@ -146,7 +147,29 @@ function HeaderMenu(props) {
146
147
  ]
147
148
  }
148
149
  ) : null,
149
- request.onOpenFilter ? /* @__PURE__ */ jsxRuntime.jsx(MenuAction, { label: "\u6253\u5F00\u7B5B\u9009\u9762\u677F", onClick: request.onOpenFilter }) : null,
150
+ request.onAutoFitCurrentColumn || request.onAutoFitAllColumns ? /* @__PURE__ */ jsxRuntime.jsx(
151
+ MenuSubmenu,
152
+ {
153
+ label: "\u81EA\u52A8\u8C03\u6574\u5217\u5BBD",
154
+ items: [
155
+ {
156
+ key: "auto-fit-current",
157
+ label: "\u5F53\u524D\u5217",
158
+ onClick: request.onAutoFitCurrentColumn
159
+ },
160
+ {
161
+ key: "auto-fit-all",
162
+ label: "\u5168\u90E8\u5217",
163
+ onClick: request.onAutoFitAllColumns
164
+ },
165
+ {
166
+ key: "auto-fit-fill-container",
167
+ label: "\u81EA\u52A8\u94FA\u6EE1\u5BB9\u5668",
168
+ onClick: request.onAutoFitFillContainer
169
+ }
170
+ ]
171
+ }
172
+ ) : null,
150
173
  hasExpand ? /* @__PURE__ */ jsxRuntime.jsx(
151
174
  MenuSubmenu,
152
175
  {
@@ -174,14 +197,35 @@ function HeaderMenu(props) {
174
197
  }
175
198
  function SummaryMenu(props) {
176
199
  const { request } = props;
200
+ const [title, setTitle] = react.useState(request.summaryTitle ?? "");
177
201
  const [precision, setPrecision] = react.useState(
178
202
  request.summaryPrecision ?? null
179
203
  );
204
+ const [roundingMode, setRoundingMode] = react.useState(
205
+ request.summaryRoundingMode ?? "round"
206
+ );
207
+ const [preserveTrailingZeros, setPreserveTrailingZeros] = react.useState(
208
+ request.summaryPreserveTrailingZeros ?? false
209
+ );
210
+ react.useEffect(() => {
211
+ setTitle(request.summaryTitle ?? "");
212
+ setPrecision(request.summaryPrecision ?? null);
213
+ setRoundingMode(request.summaryRoundingMode ?? "round");
214
+ setPreserveTrailingZeros(request.summaryPreserveTrailingZeros ?? false);
215
+ }, [
216
+ request.indicatorKey,
217
+ request.summaryTitle,
218
+ request.summaryPrecision,
219
+ request.summaryRoundingMode,
220
+ request.summaryPreserveTrailingZeros
221
+ ]);
180
222
  const aggregators = [
181
223
  ["sum", "\u6C42\u548C"],
182
224
  ["avg", "\u5E73\u5747\u503C"],
183
225
  ["count", "\u8BA1\u6570"],
184
226
  ["distinctCount", "\u53BB\u91CD\u8BA1\u6570"],
227
+ ["rowCount", "\u884C\u6570"],
228
+ ["mergedRowCount", "\u5408\u5E76\u884C\u6570"],
185
229
  ["min", "\u6700\u5C0F\u503C"],
186
230
  ["max", "\u6700\u5927\u503C"]
187
231
  ];
@@ -190,15 +234,62 @@ function SummaryMenu(props) {
190
234
  MenuSubmenu,
191
235
  {
192
236
  label: "\u6C47\u603B\u65B9\u5F0F",
193
- items: aggregators.map(([value, label]) => ({
194
- key: `summary-${value}`,
195
- label,
196
- selected: request.summaryAggregator === value,
197
- onClick: () => {
198
- request.onChangeSummaryAggregator?.(value);
199
- request.onClose();
237
+ minWidth: 268,
238
+ header: request.onChangeSummaryTitle ? /* @__PURE__ */ jsxRuntime.jsxs(
239
+ "div",
240
+ {
241
+ style: {
242
+ display: "grid",
243
+ gridTemplateColumns: "56px 1fr",
244
+ gap: 8,
245
+ alignItems: "center",
246
+ padding: "2px 10px 10px",
247
+ marginBottom: 4,
248
+ borderBottom: "1px solid #e5e7eb"
249
+ },
250
+ children: [
251
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#374151", fontSize: 14 }, children: "\u6807\u9898\uFF1A" }),
252
+ /* @__PURE__ */ jsxRuntime.jsx(
253
+ reactComponents.ReactInput,
254
+ {
255
+ value: title,
256
+ placeholder: "\u8BF7\u8F93\u5165\u6807\u9898",
257
+ onChange: (event) => {
258
+ setTitle(event.target.value);
259
+ request.onChangeSummaryTitle?.(event.target.value);
260
+ }
261
+ }
262
+ )
263
+ ]
200
264
  }
201
- })),
265
+ ) : void 0,
266
+ items: [
267
+ ...aggregators.map(([value, label]) => ({
268
+ key: `summary-${value}`,
269
+ label,
270
+ selected: !request.summaryDisabled && request.summaryAggregator === value,
271
+ onClick: () => {
272
+ request.onChangeSummaryAggregator?.(value);
273
+ request.onClose();
274
+ }
275
+ })),
276
+ {
277
+ key: "summary-prefix",
278
+ label: "\u5C55\u793A\u6C47\u603B\u65B9\u5F0F\u524D\u7F00",
279
+ separatorBefore: true,
280
+ selected: request.summaryShowTypePrefix !== false,
281
+ disabled: request.summaryDisabled,
282
+ onClick: () => request.onChangeSummaryShowTypePrefix?.(
283
+ request.summaryShowTypePrefix === false
284
+ )
285
+ },
286
+ {
287
+ key: "summary-clear",
288
+ label: "\u53D6\u6D88\u6C47\u603B",
289
+ separatorBefore: true,
290
+ onClick: request.onClearSummary
291
+ }
292
+ ],
202
293
  footer: request.onChangeSummaryPrecision ? /* @__PURE__ */ jsxRuntime.jsxs(
203
294
  "div",
204
295
  {
@@ -212,7 +303,7 @@ function SummaryMenu(props) {
212
303
  borderTop: "1px solid #e5e7eb"
213
304
  },
214
305
  children: [
215
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#374151", fontSize: 13 }, children: "\u5C0F\u6570\u4F4D\u6570" }),
306
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#374151", fontSize: 14 }, children: "\u5C0F\u6570\u4F4D\u6570" }),
216
307
  /* @__PURE__ */ jsxRuntime.jsx(
217
308
  reactComponents.ReactInputNumber,
218
309
  {
@@ -221,10 +312,42 @@ function SummaryMenu(props) {
221
312
  max: 20,
222
313
  step: 1,
223
314
  precision: 0,
224
- placeholder: "\u81EA\u52A8",
315
+ placeholder: "\u9ED8\u8BA4",
316
+ onChange: setPrecision,
317
+ onCommit: (value) => request.onChangeSummaryPrecision?.(value ?? void 0)
318
+ }
319
+ ),
320
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#374151", fontSize: 14 }, children: "\u53D6\u6574\u65B9\u5F0F" }),
321
+ /* @__PURE__ */ jsxRuntime.jsx(
322
+ reactComponents.ReactSelect,
323
+ {
324
+ value: roundingMode,
325
+ options: [
326
+ { label: "\u56DB\u820D\u4E94\u5165", value: "round" },
327
+ { label: "\u5411\u4E0B\u53D6\u6574", value: "floor" },
328
+ { label: "\u5411\u4E0A\u53D6\u6574", value: "ceil" },
329
+ { label: "\u820D\u53BB\u4E0D\u5904\u7406", value: "truncate" }
330
+ ],
331
+ onChange: (value) => {
332
+ const mode = value;
333
+ setRoundingMode(mode);
334
+ request.onChangeSummaryRoundingMode?.(mode);
335
+ }
336
+ }
337
+ ),
338
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#374151", fontSize: 14 }, children: "\u4FDD\u7559\u65E0\u6548\u96F6" }),
339
+ /* @__PURE__ */ jsxRuntime.jsx(
340
+ reactComponents.ReactSelect,
341
+ {
342
+ value: preserveTrailingZeros ? "true" : "false",
343
+ options: [
344
+ { label: "\u4E0D\u4FDD\u7559", value: "false" },
345
+ { label: "\u4FDD\u7559", value: "true" }
346
+ ],
225
347
  onChange: (value) => {
226
- setPrecision(value);
227
- request.onChangeSummaryPrecision?.(value ?? void 0);
348
+ const enabled = value === "true";
349
+ setPreserveTrailingZeros(enabled);
350
+ request.onChangeSummaryPreserveTrailingZeros?.(enabled);
228
351
  }
229
352
  }
230
353
  )
@@ -421,7 +544,7 @@ function MenuAction(props) {
421
544
  );
422
545
  }
423
546
  function MenuSubmenu(props) {
424
- const { label, items, footer, children, minWidth = 220 } = props;
547
+ const { label, items, footer, header, children, minWidth = 220 } = props;
425
548
  const menuItems = items.filter((item) => item.onClick || item.disabled);
426
549
  const reserveSelectionIcon = menuItems.some(
427
550
  (item) => typeof item.selected === "boolean"
@@ -429,7 +552,7 @@ function MenuSubmenu(props) {
429
552
  const triggerRef = react.useRef(null);
430
553
  const [open, setOpen] = react.useState(false);
431
554
  const closeTimerRef = react.useRef(null);
432
- if (!menuItems.length && !footer && !children) return null;
555
+ if (!menuItems.length && !footer && !header && !children) return null;
433
556
  const clearCloseTimer = () => {
434
557
  if (closeTimerRef.current != null) {
435
558
  window.clearTimeout(closeTimerRef.current);
@@ -496,6 +619,7 @@ function MenuSubmenu(props) {
496
619
  onOpenChange: setOpen,
497
620
  surfaceStyle: { ...CONTEXT_MENU_SURFACE_STYLE, width: minWidth },
498
621
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { onMouseEnter: clearCloseTimer, onMouseLeave: scheduleClose, children: [
622
+ header,
499
623
  menuItems.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
500
624
  item.separatorBefore ? /* @__PURE__ */ jsxRuntime.jsx(MenuDivider, {}) : null,
501
625
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1276,7 +1400,9 @@ var aggregatorOptions = [
1276
1400
  { label: "\u5E73\u5747\u503C", value: "avg" },
1277
1401
  { label: "\u6700\u5927\u503C", value: "max" },
1278
1402
  { label: "\u6700\u5C0F\u503C", value: "min" },
1279
- { label: "\u53BB\u91CD\u8BA1\u6570", value: "distinctCount" }
1403
+ { label: "\u53BB\u91CD\u8BA1\u6570", value: "distinctCount" },
1404
+ { label: "\u884C\u6570", value: "rowCount" },
1405
+ { label: "\u5408\u5E76\u884C\u6570", value: "mergedRowCount" }
1280
1406
  ];
1281
1407
  var popupStyle = {
1282
1408
  padding: 0,
@@ -1805,6 +1931,7 @@ function ReactPivotTableInner(props, ref) {
1805
1931
  title: override.title ?? field.title,
1806
1932
  indicator: {
1807
1933
  ...field.indicator,
1934
+ ...override,
1808
1935
  title: override.title ?? field.indicator?.title,
1809
1936
  aggregator: override.aggregator ?? field.indicator?.aggregator,
1810
1937
  precision: "precision" in override ? override.precision : field.indicator?.precision,
@@ -1824,6 +1951,7 @@ function ReactPivotTableInner(props, ref) {
1824
1951
  if (!override) return indicator;
1825
1952
  return {
1826
1953
  ...indicator,
1954
+ ...override,
1827
1955
  title: override.title ?? indicator.title,
1828
1956
  aggregator: override.aggregator ?? indicator.aggregator,
1829
1957
  precision: "precision" in override ? override.precision : indicator.precision,
@@ -1860,8 +1988,35 @@ function ReactPivotTableInner(props, ref) {
1860
1988
  onChangeDataFormat: fieldKey == null ? void 0 : (dataFormat) => updateField(fieldKey, { dataFormat })
1861
1989
  };
1862
1990
  if (request.target === "summary" && fieldKey != null) {
1863
- enhancedRequest.onChangeSummaryAggregator = (aggregator) => updateField(fieldKey, { aggregator });
1864
- enhancedRequest.onChangeSummaryPrecision = (precision) => updateField(fieldKey, { precision });
1991
+ const changeSummary = (patch, menuPatch) => {
1992
+ updateField(fieldKey, patch);
1993
+ setContextMenuRequest(
1994
+ (current) => current?.target === "summary" && current.indicatorKey === fieldKey ? { ...current, ...menuPatch } : current
1995
+ );
1996
+ };
1997
+ enhancedRequest.onChangeSummaryAggregator = (aggregator) => changeSummary(
1998
+ {
1999
+ aggregator,
2000
+ summaryAggregator: aggregator,
2001
+ summaryDisabled: false
2002
+ },
2003
+ { summaryAggregator: aggregator, summaryDisabled: false }
2004
+ );
2005
+ enhancedRequest.onChangeSummaryPrecision = (precision) => changeSummary({ precision }, { summaryPrecision: precision });
2006
+ enhancedRequest.onChangeSummaryTitle = (summaryTitle) => changeSummary({ summaryTitle }, { summaryTitle });
2007
+ enhancedRequest.onChangeSummaryShowTypePrefix = (summaryShowTypePrefix) => changeSummary(
2008
+ { summaryShowTypePrefix },
2009
+ { summaryShowTypePrefix }
2010
+ );
2011
+ enhancedRequest.onChangeSummaryRoundingMode = (summaryRoundingMode) => changeSummary({ summaryRoundingMode }, { summaryRoundingMode });
2012
+ enhancedRequest.onChangeSummaryPreserveTrailingZeros = (summaryPreserveTrailingZeros) => changeSummary(
2013
+ { summaryPreserveTrailingZeros },
2014
+ { summaryPreserveTrailingZeros }
2015
+ );
2016
+ enhancedRequest.onClearSummary = () => changeSummary(
2017
+ { summaryDisabled: true },
2018
+ { summaryDisabled: true }
2019
+ );
1865
2020
  }
1866
2021
  setContextMenuRequest(enhancedRequest);
1867
2022
  return;
@@ -1881,10 +2036,10 @@ function ReactPivotTableInner(props, ref) {
1881
2036
  };
1882
2037
  const sharedFilterRequest = react.useMemo(() => {
1883
2038
  if (!filterRequest) return null;
1884
- const { axis, dimensionKey } = filterRequest;
2039
+ const { axis, dimensionKey, columnPathKey } = filterRequest;
1885
2040
  return toSharedFilterRequest(filterRequest, (value) => {
1886
2041
  setFilterRequest(
1887
- (current) => current?.axis === axis && current.dimensionKey === dimensionKey ? { ...current, value } : current
2042
+ (current) => current?.axis === axis && current.dimensionKey === dimensionKey && current.columnPathKey === columnPathKey ? { ...current, value } : current
1888
2043
  );
1889
2044
  });
1890
2045
  }, [filterRequest]);
@@ -1935,6 +2090,7 @@ function ReactPivotTableInner(props, ref) {
1935
2090
  title: patch.title ?? field.title,
1936
2091
  indicator: {
1937
2092
  ...field.indicator,
2093
+ ...patch,
1938
2094
  title: patch.title ?? field.indicator?.title,
1939
2095
  aggregator: patch.aggregator ?? field.indicator?.aggregator,
1940
2096
  precision: "precision" in patch ? patch.precision : field.indicator?.precision,
@@ -1986,6 +2142,7 @@ function ReactPivotTableInner(props, ref) {
1986
2142
  react.useImperativeHandle(
1987
2143
  ref,
1988
2144
  () => ({
2145
+ autoFitColumnWidths: (target, fillContainer) => tableRef.current?.autoFitColumnWidths(target, fillContainer) ?? false,
1989
2146
  getPivotModel: () => tableRef.current?.getPivotModel() ?? null,
1990
2147
  getVisibleRowNodes: () => tableRef.current?.getVisibleRowNodes() ?? [],
1991
2148
  getVisibleColumnNodes: () => tableRef.current?.getVisibleColumnNodes() ?? [],
@@ -2007,6 +2164,15 @@ function ReactPivotTableInner(props, ref) {
2007
2164
  expandAll: (axis) => tableRef.current?.expandAll(axis) ?? 0,
2008
2165
  collapseAll: (axis) => tableRef.current?.collapseAll(axis) ?? 0,
2009
2166
  setDimensionFilter: (axis, dimensionKey, filter) => tableRef.current?.setDimensionFilter(axis, dimensionKey, filter) ?? null,
2167
+ setIndicatorFilter: (indicatorKey, columnPathKey, filter) => tableRef.current?.setIndicatorFilter(
2168
+ indicatorKey,
2169
+ columnPathKey,
2170
+ filter
2171
+ ) ?? null,
2172
+ getIndicatorFilterOptions: (indicatorKey, columnPathKey) => tableRef.current?.getIndicatorFilterOptions(
2173
+ indicatorKey,
2174
+ columnPathKey
2175
+ ) ?? [],
2010
2176
  getDimensionFilterOptions: (axis, dimensionKey) => tableRef.current?.getDimensionFilterOptions(axis, dimensionKey) ?? [],
2011
2177
  resetFilters: () => tableRef.current?.resetFilters() ?? null,
2012
2178
  setDimensionSort: (axis, dimensionKey, direction) => tableRef.current?.setDimensionSort(axis, dimensionKey, direction) ?? [],