react-open-source-grid 1.6.4 → 1.6.5

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.
@@ -355,6 +355,7 @@ __export(index_exports, {
355
355
  LocalStorageAdapter: () => LocalStorageAdapter,
356
356
  MarketDataEngine: () => MarketDataEngine,
357
357
  MarketDataGrid: () => MarketDataGrid,
358
+ PivotToolbar: () => PivotToolbar,
358
359
  PriorityIndicator: () => PriorityIndicator,
359
360
  ProgressBar: () => ProgressBar,
360
361
  Rating: () => Rating,
@@ -367,6 +368,7 @@ __export(index_exports, {
367
368
  VirtualScroller: () => VirtualScroller,
368
369
  WebSocketMockFeed: () => WebSocketMockFeed,
369
370
  alpineTheme: () => alpineTheme,
371
+ buildPivot: () => buildPivot,
370
372
  buildTreeFromFlat: () => buildTreeFromFlat,
371
373
  collapseAllNodes: () => collapseAllNodes,
372
374
  countTreeNodes: () => countTreeNodes,
@@ -377,7 +379,9 @@ __export(index_exports, {
377
379
  createPreset: () => createPreset,
378
380
  darkTheme: () => darkTheme,
379
381
  densityConfigs: () => densityConfigs,
382
+ downloadCSV: () => downloadCSV,
380
383
  expandAllNodes: () => expandAllNodes,
384
+ exportPivotToCSV: () => exportPivotToCSV,
381
385
  exportToCSV: () => exportToCSV,
382
386
  exportToXLSX: () => exportToXLSX,
383
387
  filterTree: () => filterTree,
@@ -8445,6 +8449,195 @@ var GridApiImpl = class {
8445
8449
  }
8446
8450
  };
8447
8451
 
8452
+ // src/components/DataGrid/pivotEngine.ts
8453
+ var AGGREGATORS = {
8454
+ sum: (values) => values.reduce((acc, val) => acc + val, 0),
8455
+ count: (values) => values.length,
8456
+ avg: (values) => values.length > 0 ? values.reduce((acc, val) => acc + val, 0) / values.length : 0,
8457
+ min: (values) => values.length > 0 ? Math.min(...values) : 0,
8458
+ max: (values) => values.length > 0 ? Math.max(...values) : 0
8459
+ };
8460
+ function getUniqueValues(data, column) {
8461
+ const uniqueSet = /* @__PURE__ */ new Set();
8462
+ data.forEach((row) => {
8463
+ const value = row[column];
8464
+ if (value !== null && value !== void 0) {
8465
+ uniqueSet.add(String(value));
8466
+ }
8467
+ });
8468
+ return Array.from(uniqueSet).sort();
8469
+ }
8470
+ function getAggregatorFn(aggregator) {
8471
+ if (typeof aggregator === "function") {
8472
+ return aggregator;
8473
+ }
8474
+ return AGGREGATORS[aggregator] || AGGREGATORS.sum;
8475
+ }
8476
+ function toNumber(value) {
8477
+ if (typeof value === "number") return value;
8478
+ if (typeof value === "string") {
8479
+ const num = parseFloat(value);
8480
+ return isNaN(num) ? 0 : num;
8481
+ }
8482
+ return 0;
8483
+ }
8484
+ function buildPivot(data, config) {
8485
+ const {
8486
+ pivotColumn,
8487
+ valueColumn,
8488
+ rowGroupColumn,
8489
+ aggregator,
8490
+ showTotals = false,
8491
+ showGrandTotal = false
8492
+ } = config;
8493
+ if (!data || data.length === 0) {
8494
+ return {
8495
+ columns: [],
8496
+ rows: [],
8497
+ pivotValues: []
8498
+ };
8499
+ }
8500
+ const pivotValues = getUniqueValues(data, pivotColumn);
8501
+ const rowGroupValues = getUniqueValues(data, rowGroupColumn);
8502
+ const aggregatorFn = getAggregatorFn(aggregator);
8503
+ const groupedData = /* @__PURE__ */ new Map();
8504
+ rowGroupValues.forEach((rowValue) => {
8505
+ const pivotMap = /* @__PURE__ */ new Map();
8506
+ pivotValues.forEach((pivotValue) => {
8507
+ pivotMap.set(pivotValue, []);
8508
+ });
8509
+ groupedData.set(rowValue, pivotMap);
8510
+ });
8511
+ data.forEach((row) => {
8512
+ const rowValue = String(row[rowGroupColumn] ?? "");
8513
+ const pivotValue = String(row[pivotColumn] ?? "");
8514
+ const value = toNumber(row[valueColumn]);
8515
+ if (groupedData.has(rowValue)) {
8516
+ const pivotMap = groupedData.get(rowValue);
8517
+ if (pivotMap.has(pivotValue)) {
8518
+ pivotMap.get(pivotValue).push(value);
8519
+ }
8520
+ }
8521
+ });
8522
+ const columns = [
8523
+ {
8524
+ field: rowGroupColumn,
8525
+ headerName: formatHeaderName(rowGroupColumn),
8526
+ width: 180,
8527
+ sortable: true,
8528
+ filterable: true,
8529
+ isPivotColumn: false
8530
+ }
8531
+ ];
8532
+ pivotValues.forEach((pivotValue) => {
8533
+ columns.push({
8534
+ field: pivotValue,
8535
+ headerName: pivotValue,
8536
+ width: 120,
8537
+ sortable: true,
8538
+ filterable: true,
8539
+ isPivotColumn: true
8540
+ });
8541
+ });
8542
+ if (showGrandTotal) {
8543
+ columns.push({
8544
+ field: "__grandTotal",
8545
+ headerName: "Grand Total",
8546
+ width: 120,
8547
+ sortable: true,
8548
+ filterable: false,
8549
+ isTotalColumn: true
8550
+ });
8551
+ }
8552
+ const rows = [];
8553
+ rowGroupValues.forEach((rowValue) => {
8554
+ const pivotMap = groupedData.get(rowValue);
8555
+ const row = {
8556
+ [rowGroupColumn]: rowValue,
8557
+ __id: rowValue
8558
+ // Add unique ID for grid
8559
+ };
8560
+ let grandTotal = 0;
8561
+ pivotValues.forEach((pivotValue) => {
8562
+ const values = pivotMap.get(pivotValue);
8563
+ const aggregatedValue = aggregatorFn(values);
8564
+ row[pivotValue] = aggregatedValue;
8565
+ grandTotal += aggregatedValue;
8566
+ });
8567
+ if (showGrandTotal) {
8568
+ row["__grandTotal"] = grandTotal;
8569
+ }
8570
+ rows.push(row);
8571
+ });
8572
+ let totalsRow;
8573
+ if (showTotals) {
8574
+ totalsRow = {
8575
+ [rowGroupColumn]: "Total",
8576
+ __id: "__totals",
8577
+ __isTotal: true
8578
+ };
8579
+ let overallGrandTotal = 0;
8580
+ pivotValues.forEach((pivotValue) => {
8581
+ const allValues = [];
8582
+ groupedData.forEach((pivotMap) => {
8583
+ const values = pivotMap.get(pivotValue);
8584
+ allValues.push(...values);
8585
+ });
8586
+ const total = aggregatorFn(allValues);
8587
+ totalsRow[pivotValue] = total;
8588
+ overallGrandTotal += total;
8589
+ });
8590
+ if (showGrandTotal) {
8591
+ totalsRow["__grandTotal"] = overallGrandTotal;
8592
+ }
8593
+ }
8594
+ return {
8595
+ columns,
8596
+ rows,
8597
+ pivotValues,
8598
+ totalsRow
8599
+ };
8600
+ }
8601
+ function formatHeaderName(field) {
8602
+ return field.split(/(?=[A-Z])|_|-/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
8603
+ }
8604
+ function exportPivotToCSV(pivotResult) {
8605
+ const { columns, rows, totalsRow } = pivotResult;
8606
+ const headers = columns.map((col) => col.headerName).join(",");
8607
+ const dataRows = rows.map((row) => {
8608
+ return columns.map((col) => {
8609
+ const value = row[col.field];
8610
+ if (typeof value === "string" && value.includes(",")) {
8611
+ return `"${value}"`;
8612
+ }
8613
+ return value ?? "";
8614
+ }).join(",");
8615
+ });
8616
+ if (totalsRow) {
8617
+ const totalRow = columns.map((col) => {
8618
+ const value = totalsRow[col.field];
8619
+ if (typeof value === "string" && value.includes(",")) {
8620
+ return `"${value}"`;
8621
+ }
8622
+ return value ?? "";
8623
+ }).join(",");
8624
+ dataRows.push(totalRow);
8625
+ }
8626
+ return [headers, ...dataRows].join("\n");
8627
+ }
8628
+ function downloadCSV(csvContent, filename = "pivot-table.csv") {
8629
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
8630
+ const link = document.createElement("a");
8631
+ const url = URL.createObjectURL(blob);
8632
+ link.setAttribute("href", url);
8633
+ link.setAttribute("download", filename);
8634
+ link.style.visibility = "hidden";
8635
+ document.body.appendChild(link);
8636
+ link.click();
8637
+ document.body.removeChild(link);
8638
+ URL.revokeObjectURL(url);
8639
+ }
8640
+
8448
8641
  // src/components/DataGrid/DataGrid.tsx
8449
8642
  var DataGrid = (0, import_react23.forwardRef)(({
8450
8643
  columns,
@@ -8459,6 +8652,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8459
8652
  rowPinConfig,
8460
8653
  contextMenuConfig,
8461
8654
  tooltipConfig,
8655
+ pivotConfig,
8462
8656
  tableId,
8463
8657
  theme: _theme = "quartz",
8464
8658
  densityMode: _densityMode = "normal",
@@ -8479,6 +8673,42 @@ var DataGrid = (0, import_react23.forwardRef)(({
8479
8673
  );
8480
8674
  const [internalRows, setInternalRows] = (0, import_react23.useState)(null);
8481
8675
  const activeRows = internalRows !== null ? internalRows : rows;
8676
+ const { pivotedData, effectiveColumns } = (0, import_react23.useMemo)(() => {
8677
+ if (!pivotConfig) {
8678
+ return { pivotedData: activeRows, effectiveColumns: columns };
8679
+ }
8680
+ const pivotResult = buildPivot(activeRows, pivotConfig);
8681
+ console.log("Pivot Result:", {
8682
+ columnsCount: pivotResult.columns.length,
8683
+ columns: pivotResult.columns.map((c) => c.field),
8684
+ rowsCount: pivotResult.rows.length,
8685
+ sampleRow: pivotResult.rows[0]
8686
+ });
8687
+ const pivotColumns = pivotResult.columns.map((col) => ({
8688
+ field: col.field,
8689
+ headerName: col.headerName,
8690
+ width: col.width || 120,
8691
+ sortable: col.sortable !== false,
8692
+ filterable: col.filterable !== false,
8693
+ editable: false,
8694
+ renderCell: col.isTotalColumn || col.isPivotColumn ? (row) => {
8695
+ const value = row[col.field];
8696
+ if (typeof value === "number") {
8697
+ return /* @__PURE__ */ import_react23.default.createElement("span", { style: {
8698
+ fontWeight: col.isTotalColumn ? "700" : "600",
8699
+ color: col.isTotalColumn ? "#0f766e" : "#475569"
8700
+ } }, value.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
8701
+ }
8702
+ return value;
8703
+ } : void 0
8704
+ }));
8705
+ const allRows = pivotResult.totalsRow ? [...pivotResult.rows, pivotResult.totalsRow] : pivotResult.rows;
8706
+ const rowsWithId = allRows.map((row, index) => ({
8707
+ ...row,
8708
+ id: row.__id || row.id || `pivot-row-${index}`
8709
+ }));
8710
+ return { pivotedData: rowsWithId, effectiveColumns: pivotColumns };
8711
+ }, [activeRows, columns, pivotConfig]);
8482
8712
  const rowsRef = (0, import_react23.useRef)(rows);
8483
8713
  (0, import_react23.useEffect)(() => {
8484
8714
  if (rows !== rowsRef.current) {
@@ -8581,8 +8811,8 @@ var DataGrid = (0, import_react23.forwardRef)(({
8581
8811
  gridApiRef.current = new GridApiImpl(
8582
8812
  state,
8583
8813
  dispatch,
8584
- columns,
8585
- activeRows,
8814
+ effectiveColumns,
8815
+ pivotedData,
8586
8816
  containerRef,
8587
8817
  persistenceManager,
8588
8818
  setInternalRows
@@ -8592,24 +8822,24 @@ var DataGrid = (0, import_react23.forwardRef)(({
8592
8822
  (0, import_react23.useEffect)(() => {
8593
8823
  if (gridApiRef.current && !gridApiRef.current.isDestroyed()) {
8594
8824
  gridApiRef.current.updateState(state);
8595
- gridApiRef.current.updateData(columns, activeRows);
8825
+ gridApiRef.current.updateData(effectiveColumns, pivotedData);
8596
8826
  gridApiRef.current.updateCallbacks(setInternalRows);
8597
8827
  }
8598
- }, [state, columns, activeRows, setInternalRows]);
8828
+ }, [state, effectiveColumns, pivotedData, setInternalRows]);
8599
8829
  (0, import_react23.useImperativeHandle)(ref, () => {
8600
8830
  if (!gridApiRef.current || gridApiRef.current.isDestroyed()) {
8601
8831
  gridApiRef.current = new GridApiImpl(
8602
8832
  state,
8603
8833
  dispatch,
8604
- columns,
8605
- activeRows,
8834
+ effectiveColumns,
8835
+ pivotedData,
8606
8836
  containerRef,
8607
8837
  persistenceManager,
8608
8838
  setInternalRows
8609
8839
  );
8610
8840
  }
8611
8841
  return gridApiRef.current;
8612
- }, [state, columns, activeRows, persistenceManager]);
8842
+ }, [state, effectiveColumns, pivotedData, persistenceManager]);
8613
8843
  const onGridReadyCalledRef = (0, import_react23.useRef)(false);
8614
8844
  const onGridReadyCallbackRef = (0, import_react23.useRef)(onGridReady);
8615
8845
  (0, import_react23.useEffect)(() => {
@@ -8690,9 +8920,11 @@ var DataGrid = (0, import_react23.forwardRef)(({
8690
8920
  ...middleColumns,
8691
8921
  ...pinnedRightFields
8692
8922
  ];
8923
+ console.log("Display column order:", displayColumnOrder, "from state.columnOrder:", state.columnOrder);
8693
8924
  (0, import_react23.useEffect)(() => {
8694
- dispatch({ type: "RESET_COLUMNS", payload: columns });
8695
- }, [columns]);
8925
+ console.log("Dispatching RESET_COLUMNS with", effectiveColumns.length, "columns:", effectiveColumns.map((c) => c.field));
8926
+ dispatch({ type: "RESET_COLUMNS", payload: effectiveColumns });
8927
+ }, [effectiveColumns]);
8696
8928
  (0, import_react23.useEffect)(() => {
8697
8929
  if (onSelectionChange) {
8698
8930
  onSelectionChange(Array.from(state.selection.selectedRows));
@@ -8708,17 +8940,17 @@ var DataGrid = (0, import_react23.forwardRef)(({
8708
8940
  }, [state.pinnedRowsTop, state.pinnedRowsBottom]);
8709
8941
  (0, import_react23.useEffect)(() => {
8710
8942
  if (state.sortConfig.field) {
8711
- const column = columns.find((c) => c.field === state.sortConfig.field);
8943
+ const column = effectiveColumns.find((c) => c.field === state.sortConfig.field);
8712
8944
  if (column) {
8713
8945
  announceSorting(column.headerName, state.sortConfig.direction);
8714
8946
  }
8715
8947
  }
8716
- }, [state.sortConfig.field, state.sortConfig.direction]);
8948
+ }, [state.sortConfig.field, state.sortConfig.direction, effectiveColumns]);
8717
8949
  const sortedRows = (0, import_react23.useMemo)(() => {
8718
8950
  if (!state.sortConfig.field || !state.sortConfig.direction) {
8719
- return activeRows;
8951
+ return pivotedData;
8720
8952
  }
8721
- const sorted = [...activeRows].sort((a, b) => {
8953
+ const sorted = [...pivotedData].sort((a, b) => {
8722
8954
  const aValue = a[state.sortConfig.field];
8723
8955
  const bValue = b[state.sortConfig.field];
8724
8956
  if (aValue == null && bValue == null) return 0;
@@ -8735,7 +8967,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8735
8967
  sorted.reverse();
8736
8968
  }
8737
8969
  return sorted;
8738
- }, [activeRows, state.sortConfig]);
8970
+ }, [pivotedData, state.sortConfig]);
8739
8971
  const filteredRows = (0, import_react23.useMemo)(() => {
8740
8972
  if (!hasActiveFilters(state.filterConfig)) {
8741
8973
  return sortedRows;
@@ -8881,7 +9113,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8881
9113
  /* @__PURE__ */ import_react23.default.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center", justifyContent: "space-between", paddingLeft: "16px", paddingRight: "16px", paddingTop: "10px", paddingBottom: "10px", backgroundColor: "var(--grid-bg-alt)", borderBottom: "var(--grid-border-width, 1px) solid var(--grid-border)", zIndex: 30 } }, /* @__PURE__ */ import_react23.default.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react23.default.createElement(
8882
9114
  ColumnChooser,
8883
9115
  {
8884
- columns,
9116
+ columns: effectiveColumns,
8885
9117
  columnOrder: state.columnOrder,
8886
9118
  hiddenColumns: state.hiddenColumns,
8887
9119
  onToggleVisibility: (field) => dispatch({ type: "TOGGLE_COLUMN_VISIBILITY", payload: field }),
@@ -8891,7 +9123,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8891
9123
  ), /* @__PURE__ */ import_react23.default.createElement(
8892
9124
  ExportMenu,
8893
9125
  {
8894
- columns,
9126
+ columns: effectiveColumns,
8895
9127
  fullDataset: rows,
8896
9128
  filteredData: filteredRows.filter((r) => !("isGroup" in r)),
8897
9129
  selectedRows: state.selection.selectedRows,
@@ -8909,7 +9141,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8909
9141
  /* @__PURE__ */ import_react23.default.createElement(
8910
9142
  GroupByPanel,
8911
9143
  {
8912
- columns,
9144
+ columns: effectiveColumns,
8913
9145
  groupBy: state.groupBy,
8914
9146
  dispatch
8915
9147
  }
@@ -8917,7 +9149,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8917
9149
  /* @__PURE__ */ import_react23.default.createElement("div", { role: "rowgroup", style: { position: "sticky", top: 0, zIndex: 20, width: "100%" } }, /* @__PURE__ */ import_react23.default.createElement(
8918
9150
  GridHeader,
8919
9151
  {
8920
- columns,
9152
+ columns: effectiveColumns,
8921
9153
  columnOrder: state.columnOrder,
8922
9154
  displayColumnOrder,
8923
9155
  columnWidths: state.columnWidths,
@@ -8936,7 +9168,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8936
9168
  ), /* @__PURE__ */ import_react23.default.createElement(
8937
9169
  ColumnFilters,
8938
9170
  {
8939
- columns,
9171
+ columns: effectiveColumns,
8940
9172
  displayColumnOrder,
8941
9173
  columnWidths: state.columnWidths,
8942
9174
  filterConfig: state.filterConfig,
@@ -8949,7 +9181,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8949
9181
  /* @__PURE__ */ import_react23.default.createElement(
8950
9182
  GridBody,
8951
9183
  {
8952
- columns,
9184
+ columns: effectiveColumns,
8953
9185
  rows: (virtualScrollConfig == null ? void 0 : virtualScrollConfig.enabled) ? unpinnedRows : paginatedRows,
8954
9186
  pinnedRowsTop: pinnedRowsTopData,
8955
9187
  pinnedRowsBottom: pinnedRowsBottomData,
@@ -8989,7 +9221,7 @@ var DataGrid = (0, import_react23.forwardRef)(({
8989
9221
  (footerConfig == null ? void 0 : footerConfig.show) && footerConfig.aggregates && /* @__PURE__ */ import_react23.default.createElement(
8990
9222
  GridFooter,
8991
9223
  {
8992
- columns,
9224
+ columns: effectiveColumns,
8993
9225
  displayColumnOrder,
8994
9226
  columnWidths: state.columnWidths,
8995
9227
  aggregates: globalAggregates,
@@ -12157,6 +12389,258 @@ function createMockFeed(config) {
12157
12389
  createConnection: () => createMockWebSocket(feed)
12158
12390
  };
12159
12391
  }
12392
+
12393
+ // src/components/DataGrid/PivotToolbar.tsx
12394
+ var import_react33 = __toESM(require("react"), 1);
12395
+ var AGGREGATOR_OPTIONS = [
12396
+ { value: "sum", label: "Sum" },
12397
+ { value: "avg", label: "Average" },
12398
+ { value: "count", label: "Count" },
12399
+ { value: "min", label: "Minimum" },
12400
+ { value: "max", label: "Maximum" }
12401
+ ];
12402
+ var PivotToolbar = ({
12403
+ columns,
12404
+ pivotConfig,
12405
+ onPivotToggle,
12406
+ onConfigChange,
12407
+ isPivotMode = false,
12408
+ style,
12409
+ className
12410
+ }) => {
12411
+ const [isExpanded, setIsExpanded] = (0, import_react33.useState)(isPivotMode);
12412
+ const [rowGroupColumn, setRowGroupColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.rowGroupColumn) || "");
12413
+ const [pivotColumn, setPivotColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.pivotColumn) || "");
12414
+ const [valueColumn, setValueColumn] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.valueColumn) || "");
12415
+ const [aggregator, setAggregator] = (0, import_react33.useState)(
12416
+ (pivotConfig == null ? void 0 : pivotConfig.aggregator) || "sum"
12417
+ );
12418
+ const [showTotals, setShowTotals] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.showTotals) ?? true);
12419
+ const [showGrandTotal, setShowGrandTotal] = (0, import_react33.useState)((pivotConfig == null ? void 0 : pivotConfig.showGrandTotal) ?? true);
12420
+ const isConfigValid = (0, import_react33.useMemo)(() => {
12421
+ return rowGroupColumn && pivotColumn && valueColumn;
12422
+ }, [rowGroupColumn, pivotColumn, valueColumn]);
12423
+ const handleApply = () => {
12424
+ if (!isConfigValid) return;
12425
+ const config = {
12426
+ rowGroupColumn,
12427
+ pivotColumn,
12428
+ valueColumn,
12429
+ aggregator,
12430
+ showTotals,
12431
+ showGrandTotal
12432
+ };
12433
+ onConfigChange(config);
12434
+ onPivotToggle(true);
12435
+ };
12436
+ const handleClear = () => {
12437
+ setRowGroupColumn("");
12438
+ setPivotColumn("");
12439
+ setValueColumn("");
12440
+ setAggregator("sum");
12441
+ setShowTotals(true);
12442
+ setShowGrandTotal(true);
12443
+ onConfigChange(null);
12444
+ onPivotToggle(false);
12445
+ setIsExpanded(false);
12446
+ };
12447
+ const handleToggle = () => {
12448
+ setIsExpanded(!isExpanded);
12449
+ };
12450
+ return /* @__PURE__ */ import_react33.default.createElement(
12451
+ "div",
12452
+ {
12453
+ className,
12454
+ style: {
12455
+ backgroundColor: "#f8fafc",
12456
+ border: "1px solid #e2e8f0",
12457
+ borderRadius: "8px",
12458
+ padding: "12px",
12459
+ ...style
12460
+ }
12461
+ },
12462
+ /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: isExpanded ? "12px" : "0" } }, /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "center", gap: "8px" } }, /* @__PURE__ */ import_react33.default.createElement("span", { style: { fontSize: "20px" } }, "\u{1F4CA}"), /* @__PURE__ */ import_react33.default.createElement("h3", { style: { margin: 0, fontSize: "14px", fontWeight: "600", color: "#1e293b" } }, "Pivot Table"), isPivotMode && /* @__PURE__ */ import_react33.default.createElement("span", { style: {
12463
+ backgroundColor: "#10b981",
12464
+ color: "white",
12465
+ padding: "2px 8px",
12466
+ borderRadius: "12px",
12467
+ fontSize: "11px",
12468
+ fontWeight: "600"
12469
+ } }, "Active")), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", gap: "8px" } }, isPivotMode && /* @__PURE__ */ import_react33.default.createElement(
12470
+ "button",
12471
+ {
12472
+ onClick: handleClear,
12473
+ style: {
12474
+ padding: "6px 12px",
12475
+ fontSize: "13px",
12476
+ fontWeight: "500",
12477
+ color: "#dc2626",
12478
+ backgroundColor: "#fee2e2",
12479
+ border: "1px solid #fecaca",
12480
+ borderRadius: "6px",
12481
+ cursor: "pointer",
12482
+ transition: "all 0.15s"
12483
+ },
12484
+ onMouseEnter: (e) => {
12485
+ e.currentTarget.style.backgroundColor = "#fecaca";
12486
+ },
12487
+ onMouseLeave: (e) => {
12488
+ e.currentTarget.style.backgroundColor = "#fee2e2";
12489
+ }
12490
+ },
12491
+ "Clear Pivot"
12492
+ ), /* @__PURE__ */ import_react33.default.createElement(
12493
+ "button",
12494
+ {
12495
+ onClick: handleToggle,
12496
+ style: {
12497
+ padding: "6px 10px",
12498
+ fontSize: "13px",
12499
+ color: "#64748b",
12500
+ backgroundColor: "white",
12501
+ border: "1px solid #cbd5e1",
12502
+ borderRadius: "6px",
12503
+ cursor: "pointer",
12504
+ transition: "all 0.15s"
12505
+ },
12506
+ onMouseEnter: (e) => {
12507
+ e.currentTarget.style.backgroundColor = "#f1f5f9";
12508
+ },
12509
+ onMouseLeave: (e) => {
12510
+ e.currentTarget.style.backgroundColor = "white";
12511
+ }
12512
+ },
12513
+ isExpanded ? "\u25B2" : "\u25BC"
12514
+ ))),
12515
+ isExpanded && /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: "12px" } }, /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Row Group By ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12516
+ "select",
12517
+ {
12518
+ value: rowGroupColumn,
12519
+ onChange: (e) => setRowGroupColumn(e.target.value),
12520
+ style: {
12521
+ width: "100%",
12522
+ padding: "8px",
12523
+ fontSize: "13px",
12524
+ border: "1px solid #cbd5e1",
12525
+ borderRadius: "6px",
12526
+ backgroundColor: "white",
12527
+ color: "#1e293b",
12528
+ cursor: "pointer"
12529
+ }
12530
+ },
12531
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12532
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12533
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Pivot Column ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12534
+ "select",
12535
+ {
12536
+ value: pivotColumn,
12537
+ onChange: (e) => setPivotColumn(e.target.value),
12538
+ style: {
12539
+ width: "100%",
12540
+ padding: "8px",
12541
+ fontSize: "13px",
12542
+ border: "1px solid #cbd5e1",
12543
+ borderRadius: "6px",
12544
+ backgroundColor: "white",
12545
+ color: "#1e293b",
12546
+ cursor: "pointer"
12547
+ }
12548
+ },
12549
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12550
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12551
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Value Column ", /* @__PURE__ */ import_react33.default.createElement("span", { style: { color: "#dc2626" } }, "*")), /* @__PURE__ */ import_react33.default.createElement(
12552
+ "select",
12553
+ {
12554
+ value: valueColumn,
12555
+ onChange: (e) => setValueColumn(e.target.value),
12556
+ style: {
12557
+ width: "100%",
12558
+ padding: "8px",
12559
+ fontSize: "13px",
12560
+ border: "1px solid #cbd5e1",
12561
+ borderRadius: "6px",
12562
+ backgroundColor: "white",
12563
+ color: "#1e293b",
12564
+ cursor: "pointer"
12565
+ }
12566
+ },
12567
+ /* @__PURE__ */ import_react33.default.createElement("option", { value: "" }, "Select column..."),
12568
+ columns.map((col) => /* @__PURE__ */ import_react33.default.createElement("option", { key: col.field, value: col.field }, col.headerName))
12569
+ )), /* @__PURE__ */ import_react33.default.createElement("div", null, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "block", fontSize: "12px", fontWeight: "600", color: "#475569", marginBottom: "6px" } }, "Aggregation"), /* @__PURE__ */ import_react33.default.createElement(
12570
+ "select",
12571
+ {
12572
+ value: aggregator,
12573
+ onChange: (e) => setAggregator(e.target.value),
12574
+ style: {
12575
+ width: "100%",
12576
+ padding: "8px",
12577
+ fontSize: "13px",
12578
+ border: "1px solid #cbd5e1",
12579
+ borderRadius: "6px",
12580
+ backgroundColor: "white",
12581
+ color: "#1e293b",
12582
+ cursor: "pointer"
12583
+ }
12584
+ },
12585
+ AGGREGATOR_OPTIONS.map((opt) => /* @__PURE__ */ import_react33.default.createElement("option", { key: opt.value, value: opt.value }, opt.label))
12586
+ )), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "8px", justifyContent: "center" } }, /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "flex", alignItems: "center", gap: "6px", fontSize: "13px", color: "#475569", cursor: "pointer" } }, /* @__PURE__ */ import_react33.default.createElement(
12587
+ "input",
12588
+ {
12589
+ type: "checkbox",
12590
+ checked: showTotals,
12591
+ onChange: (e) => setShowTotals(e.target.checked),
12592
+ style: { cursor: "pointer" }
12593
+ }
12594
+ ), "Show Totals Row"), /* @__PURE__ */ import_react33.default.createElement("label", { style: { display: "flex", alignItems: "center", gap: "6px", fontSize: "13px", color: "#475569", cursor: "pointer" } }, /* @__PURE__ */ import_react33.default.createElement(
12595
+ "input",
12596
+ {
12597
+ type: "checkbox",
12598
+ checked: showGrandTotal,
12599
+ onChange: (e) => setShowGrandTotal(e.target.checked),
12600
+ style: { cursor: "pointer" }
12601
+ }
12602
+ ), "Show Grand Total Column")), /* @__PURE__ */ import_react33.default.createElement("div", { style: { display: "flex", alignItems: "flex-end" } }, /* @__PURE__ */ import_react33.default.createElement(
12603
+ "button",
12604
+ {
12605
+ onClick: handleApply,
12606
+ disabled: !isConfigValid,
12607
+ style: {
12608
+ width: "100%",
12609
+ padding: "10px",
12610
+ fontSize: "14px",
12611
+ fontWeight: "600",
12612
+ color: "white",
12613
+ backgroundColor: isConfigValid ? "#2563eb" : "#94a3b8",
12614
+ border: "none",
12615
+ borderRadius: "6px",
12616
+ cursor: isConfigValid ? "pointer" : "not-allowed",
12617
+ transition: "all 0.15s",
12618
+ boxShadow: isConfigValid ? "0 2px 4px rgba(37, 99, 235, 0.2)" : "none"
12619
+ },
12620
+ onMouseEnter: (e) => {
12621
+ if (isConfigValid) {
12622
+ e.currentTarget.style.backgroundColor = "#1d4ed8";
12623
+ }
12624
+ },
12625
+ onMouseLeave: (e) => {
12626
+ if (isConfigValid) {
12627
+ e.currentTarget.style.backgroundColor = "#2563eb";
12628
+ }
12629
+ }
12630
+ },
12631
+ "Apply Pivot"
12632
+ ))),
12633
+ isExpanded && /* @__PURE__ */ import_react33.default.createElement("div", { style: {
12634
+ marginTop: "12px",
12635
+ padding: "10px",
12636
+ backgroundColor: "#eff6ff",
12637
+ border: "1px solid #bfdbfe",
12638
+ borderRadius: "6px",
12639
+ fontSize: "12px",
12640
+ color: "#1e40af"
12641
+ } }, /* @__PURE__ */ import_react33.default.createElement("strong", null, "\u{1F4A1} Tip:"), " Select a Row Group column to organize data by, a Pivot column whose values become new columns, and a Value column to aggregate.")
12642
+ );
12643
+ };
12160
12644
  // Annotate the CommonJS export names for ESM import in node:
12161
12645
  0 && (module.exports = {
12162
12646
  AdvancedFilterBuilder,
@@ -12180,6 +12664,7 @@ function createMockFeed(config) {
12180
12664
  LocalStorageAdapter,
12181
12665
  MarketDataEngine,
12182
12666
  MarketDataGrid,
12667
+ PivotToolbar,
12183
12668
  PriorityIndicator,
12184
12669
  ProgressBar,
12185
12670
  Rating,
@@ -12192,6 +12677,7 @@ function createMockFeed(config) {
12192
12677
  VirtualScroller,
12193
12678
  WebSocketMockFeed,
12194
12679
  alpineTheme,
12680
+ buildPivot,
12195
12681
  buildTreeFromFlat,
12196
12682
  collapseAllNodes,
12197
12683
  countTreeNodes,
@@ -12202,7 +12688,9 @@ function createMockFeed(config) {
12202
12688
  createPreset,
12203
12689
  darkTheme,
12204
12690
  densityConfigs,
12691
+ downloadCSV,
12205
12692
  expandAllNodes,
12693
+ exportPivotToCSV,
12206
12694
  exportToCSV,
12207
12695
  exportToXLSX,
12208
12696
  filterTree,