@smallwebco/tinypivot-react 1.0.24 → 1.0.26

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
@@ -45,8 +45,8 @@ __export(index_exports, {
45
45
  module.exports = __toCommonJS(index_exports);
46
46
 
47
47
  // src/components/DataGrid.tsx
48
- var import_react8 = require("react");
49
- var import_react_dom = require("react-dom");
48
+ var import_react9 = require("react");
49
+ var import_react_dom2 = require("react-dom");
50
50
 
51
51
  // src/hooks/useExcelGrid.ts
52
52
  var import_react = require("react");
@@ -312,6 +312,7 @@ function usePivotTable(data) {
312
312
  const [valueFields, setValueFields] = (0, import_react3.useState)([]);
313
313
  const [showRowTotals, setShowRowTotals] = (0, import_react3.useState)(true);
314
314
  const [showColumnTotals, setShowColumnTotals] = (0, import_react3.useState)(true);
315
+ const [calculatedFields, setCalculatedFields] = (0, import_react3.useState)(() => (0, import_tinypivot_core3.loadCalculatedFields)());
315
316
  const [currentStorageKey, setCurrentStorageKey] = (0, import_react3.useState)(null);
316
317
  const availableFields = (0, import_react3.useMemo)(() => {
317
318
  return (0, import_tinypivot_core3.computeAvailableFields)(data);
@@ -336,9 +337,10 @@ function usePivotTable(data) {
336
337
  columnFields,
337
338
  valueFields,
338
339
  showRowTotals,
339
- showColumnTotals
340
+ showColumnTotals,
341
+ calculatedFields
340
342
  });
341
- }, [data, isConfigured, canUsePivot, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals]);
343
+ }, [data, isConfigured, canUsePivot, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields]);
342
344
  (0, import_react3.useEffect)(() => {
343
345
  if (data.length === 0) return;
344
346
  const newKeys = Object.keys(data[0]);
@@ -352,6 +354,9 @@ function usePivotTable(data) {
352
354
  setValueFields(savedConfig.valueFields);
353
355
  setShowRowTotals(savedConfig.showRowTotals);
354
356
  setShowColumnTotals(savedConfig.showColumnTotals);
357
+ if (savedConfig.calculatedFields) {
358
+ setCalculatedFields(savedConfig.calculatedFields);
359
+ }
355
360
  } else {
356
361
  const currentConfig = {
357
362
  rowFields,
@@ -375,10 +380,11 @@ function usePivotTable(data) {
375
380
  columnFields,
376
381
  valueFields,
377
382
  showRowTotals,
378
- showColumnTotals
383
+ showColumnTotals,
384
+ calculatedFields
379
385
  };
380
386
  (0, import_tinypivot_core3.savePivotConfig)(currentStorageKey, config);
381
- }, [currentStorageKey, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals]);
387
+ }, [currentStorageKey, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields]);
382
388
  const addRowField = (0, import_react3.useCallback)(
383
389
  (field) => {
384
390
  if (!requirePro("Pivot Table - Row Fields")) return;
@@ -457,6 +463,27 @@ function usePivotTable(data) {
457
463
  setValueFields([{ field: numericFields[0].field, aggregation: "sum" }]);
458
464
  }
459
465
  }, [availableFields, requirePro]);
466
+ const addCalculatedField = (0, import_react3.useCallback)((field) => {
467
+ setCalculatedFields((prev) => {
468
+ const existing = prev.findIndex((f) => f.id === field.id);
469
+ let updated;
470
+ if (existing >= 0) {
471
+ updated = [...prev.slice(0, existing), field, ...prev.slice(existing + 1)];
472
+ } else {
473
+ updated = [...prev, field];
474
+ }
475
+ (0, import_tinypivot_core3.saveCalculatedFields)(updated);
476
+ return updated;
477
+ });
478
+ }, []);
479
+ const removeCalculatedField = (0, import_react3.useCallback)((id) => {
480
+ setCalculatedFields((prev) => {
481
+ const updated = prev.filter((f) => f.id !== id);
482
+ (0, import_tinypivot_core3.saveCalculatedFields)(updated);
483
+ return updated;
484
+ });
485
+ setValueFields((prev) => prev.filter((v) => v.field !== `calc:${id}`));
486
+ }, []);
460
487
  return {
461
488
  // State
462
489
  rowFields,
@@ -464,6 +491,7 @@ function usePivotTable(data) {
464
491
  valueFields,
465
492
  showRowTotals,
466
493
  showColumnTotals,
494
+ calculatedFields,
467
495
  // Computed
468
496
  availableFields,
469
497
  unassignedFields,
@@ -482,7 +510,9 @@ function usePivotTable(data) {
482
510
  setShowColumnTotals,
483
511
  autoSuggestConfig,
484
512
  setRowFields,
485
- setColumnFields
513
+ setColumnFields,
514
+ addCalculatedField,
515
+ removeCalculatedField
486
516
  };
487
517
  }
488
518
 
@@ -954,10 +984,197 @@ function ColumnFilter({
954
984
  }
955
985
 
956
986
  // src/components/PivotConfig.tsx
987
+ var import_react7 = require("react");
988
+ var import_tinypivot_core6 = require("@smallwebco/tinypivot-core");
989
+
990
+ // src/components/CalculatedFieldModal.tsx
957
991
  var import_react6 = require("react");
992
+ var import_react_dom = require("react-dom");
958
993
  var import_tinypivot_core5 = require("@smallwebco/tinypivot-core");
959
994
  var import_jsx_runtime2 = require("react/jsx-runtime");
960
- function getFieldIcon(type) {
995
+ function CalculatedFieldModal({
996
+ show,
997
+ availableFields,
998
+ existingField,
999
+ onClose,
1000
+ onSave
1001
+ }) {
1002
+ const [name, setName] = (0, import_react6.useState)("");
1003
+ const [formula, setFormula] = (0, import_react6.useState)("");
1004
+ const [formatAs, setFormatAs] = (0, import_react6.useState)("number");
1005
+ const [decimals, setDecimals] = (0, import_react6.useState)(2);
1006
+ const [error, setError] = (0, import_react6.useState)(null);
1007
+ (0, import_react6.useEffect)(() => {
1008
+ if (show) {
1009
+ if (existingField) {
1010
+ setName(existingField.name);
1011
+ setFormula(existingField.formula);
1012
+ setFormatAs(existingField.formatAs || "number");
1013
+ setDecimals(existingField.decimals ?? 2);
1014
+ } else {
1015
+ setName("");
1016
+ setFormula("");
1017
+ setFormatAs("number");
1018
+ setDecimals(2);
1019
+ }
1020
+ setError(null);
1021
+ }
1022
+ }, [show, existingField]);
1023
+ const validationError = (0, import_react6.useMemo)(() => {
1024
+ if (!formula.trim()) return null;
1025
+ return (0, import_tinypivot_core5.validateSimpleFormula)(formula, availableFields);
1026
+ }, [formula, availableFields]);
1027
+ const insertField = (0, import_react6.useCallback)((field) => {
1028
+ setFormula((prev) => {
1029
+ if (prev.trim() && !prev.endsWith(" ")) {
1030
+ return prev + " " + field;
1031
+ }
1032
+ return prev + field;
1033
+ });
1034
+ }, []);
1035
+ const insertOperator = (0, import_react6.useCallback)((op) => {
1036
+ setFormula((prev) => {
1037
+ if (prev.trim() && !prev.endsWith(" ")) {
1038
+ return prev + " " + op + " ";
1039
+ }
1040
+ return prev + op + " ";
1041
+ });
1042
+ }, []);
1043
+ const handleSave = (0, import_react6.useCallback)(() => {
1044
+ if (!name.trim()) {
1045
+ setError("Name is required");
1046
+ return;
1047
+ }
1048
+ const validationResult = (0, import_tinypivot_core5.validateSimpleFormula)(formula, availableFields);
1049
+ if (validationResult) {
1050
+ setError(validationResult);
1051
+ return;
1052
+ }
1053
+ const field = {
1054
+ id: existingField?.id || `calc_${Date.now()}`,
1055
+ name: name.trim(),
1056
+ formula: formula.trim(),
1057
+ formatAs,
1058
+ decimals
1059
+ };
1060
+ onSave(field);
1061
+ onClose();
1062
+ }, [name, formula, formatAs, decimals, existingField, availableFields, onSave, onClose]);
1063
+ const handleOverlayClick = (0, import_react6.useCallback)((e) => {
1064
+ if (e.target === e.currentTarget) {
1065
+ onClose();
1066
+ }
1067
+ }, [onClose]);
1068
+ if (!show) return null;
1069
+ const modalContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-modal-overlay", onClick: handleOverlayClick, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-modal", children: [
1070
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-modal-header", children: [
1071
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { children: [
1072
+ existingField ? "Edit" : "Create",
1073
+ " Calculated Field"
1074
+ ] }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-modal-close", onClick: onClose, children: "\xD7" })
1076
+ ] }),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-modal-body", children: [
1078
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group", children: [
1079
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label", children: "Name" }),
1080
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1081
+ "input",
1082
+ {
1083
+ type: "text",
1084
+ className: "vpg-input",
1085
+ placeholder: "e.g., Profit Margin %",
1086
+ value: name,
1087
+ onChange: (e) => setName(e.target.value)
1088
+ }
1089
+ )
1090
+ ] }),
1091
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group", children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label", children: "Formula" }),
1093
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1094
+ "textarea",
1095
+ {
1096
+ className: "vpg-textarea",
1097
+ placeholder: "e.g., revenue / units",
1098
+ rows: 2,
1099
+ value: formula,
1100
+ onChange: (e) => setFormula(e.target.value)
1101
+ }
1102
+ ),
1103
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-formula-hint", children: "Use field names with math operators: + - * / ( )" }),
1104
+ validationError && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-error", children: validationError })
1105
+ ] }),
1106
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group", children: [
1107
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label-small", children: "Operators" }),
1108
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-button-group", children: [
1109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("+"), children: "+" }),
1110
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("-"), children: "\u2212" }),
1111
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("*"), children: "\xD7" }),
1112
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("/"), children: "\xF7" }),
1113
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("("), children: "(" }),
1114
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator(")"), children: ")" })
1115
+ ] })
1116
+ ] }),
1117
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group", children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label-small", children: "Insert Field" }),
1119
+ availableFields.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-button-group vpg-field-buttons", children: availableFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1120
+ "button",
1121
+ {
1122
+ className: "vpg-insert-btn vpg-field-btn",
1123
+ onClick: () => insertField(field),
1124
+ children: field
1125
+ },
1126
+ field
1127
+ )) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-no-fields", children: "No numeric fields available" })
1128
+ ] }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-row", children: [
1130
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group vpg-form-group-half", children: [
1131
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label", children: "Format As" }),
1132
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1133
+ "select",
1134
+ {
1135
+ className: "vpg-select",
1136
+ value: formatAs,
1137
+ onChange: (e) => setFormatAs(e.target.value),
1138
+ children: [
1139
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "number", children: "Number" }),
1140
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "percent", children: "Percentage" }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "currency", children: "Currency ($)" })
1142
+ ]
1143
+ }
1144
+ )
1145
+ ] }),
1146
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-form-group vpg-form-group-half", children: [
1147
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: "vpg-label", children: "Decimals" }),
1148
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1149
+ "input",
1150
+ {
1151
+ type: "number",
1152
+ className: "vpg-input",
1153
+ min: 0,
1154
+ max: 6,
1155
+ value: decimals,
1156
+ onChange: (e) => setDecimals(Number(e.target.value))
1157
+ }
1158
+ )
1159
+ ] })
1160
+ ] }),
1161
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-error vpg-error-box", children: error })
1162
+ ] }),
1163
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-modal-footer", children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-btn vpg-btn-secondary", onClick: onClose, children: "Cancel" }),
1165
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "vpg-btn vpg-btn-primary", onClick: handleSave, children: [
1166
+ existingField ? "Update" : "Add",
1167
+ " Field"
1168
+ ] })
1169
+ ] })
1170
+ ] }) });
1171
+ return (0, import_react_dom.createPortal)(modalContent, document.body);
1172
+ }
1173
+
1174
+ // src/components/PivotConfig.tsx
1175
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1176
+ function getFieldIcon(type, isCalculated) {
1177
+ if (isCalculated) return "\u0192";
961
1178
  switch (type) {
962
1179
  case "number":
963
1180
  return "#";
@@ -975,7 +1192,9 @@ function PivotConfig({
975
1192
  columnFields,
976
1193
  valueFields,
977
1194
  showRowTotals,
1195
+ calculatedFields,
978
1196
  onShowRowTotalsChange,
1197
+ onShowColumnTotalsChange,
979
1198
  onClearConfig,
980
1199
  onAutoSuggest,
981
1200
  onDragStart,
@@ -985,35 +1204,70 @@ function PivotConfig({
985
1204
  onRemoveColumnField,
986
1205
  onRemoveValueField,
987
1206
  onAddRowField,
988
- onAddColumnField
1207
+ onAddColumnField,
1208
+ onAddCalculatedField,
1209
+ onRemoveCalculatedField,
1210
+ onUpdateCalculatedField
989
1211
  }) {
990
- const { showWatermark } = useLicense();
991
- const [fieldSearch, setFieldSearch] = (0, import_react6.useState)("");
992
- const assignedFields = (0, import_react6.useMemo)(() => {
1212
+ const [fieldSearch, setFieldSearch] = (0, import_react7.useState)("");
1213
+ const [showCalcModal, setShowCalcModal] = (0, import_react7.useState)(false);
1214
+ const [editingCalcField, setEditingCalcField] = (0, import_react7.useState)(null);
1215
+ const numericFieldNames = (0, import_react7.useMemo)(
1216
+ () => availableFields.filter((f) => f.isNumeric).map((f) => f.field),
1217
+ [availableFields]
1218
+ );
1219
+ const calculatedFieldsAsStats = (0, import_react7.useMemo)(() => {
1220
+ if (!calculatedFields) return [];
1221
+ return calculatedFields.map((calc) => ({
1222
+ field: `calc:${calc.id}`,
1223
+ type: "number",
1224
+ uniqueCount: 0,
1225
+ isNumeric: true,
1226
+ isCalculated: true,
1227
+ calcId: calc.id,
1228
+ calcName: calc.name,
1229
+ calcFormula: calc.formula
1230
+ }));
1231
+ }, [calculatedFields]);
1232
+ const allAvailableFields = (0, import_react7.useMemo)(() => [
1233
+ ...availableFields.map((f) => ({ ...f, isCalculated: false })),
1234
+ ...calculatedFieldsAsStats
1235
+ ], [availableFields, calculatedFieldsAsStats]);
1236
+ const assignedFields = (0, import_react7.useMemo)(() => {
993
1237
  const rowSet = new Set(rowFields);
994
1238
  const colSet = new Set(columnFields);
995
1239
  const valueMap = new Map(valueFields.map((v) => [v.field, v]));
996
- return availableFields.filter((f) => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field)).map((f) => ({
1240
+ return allAvailableFields.filter((f) => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field)).map((f) => ({
997
1241
  ...f,
998
1242
  assignedTo: rowSet.has(f.field) ? "row" : colSet.has(f.field) ? "column" : "value",
999
1243
  valueConfig: valueMap.get(f.field)
1000
1244
  }));
1001
- }, [availableFields, rowFields, columnFields, valueFields]);
1002
- const unassignedFields = (0, import_react6.useMemo)(() => {
1245
+ }, [allAvailableFields, rowFields, columnFields, valueFields]);
1246
+ const unassignedFields = (0, import_react7.useMemo)(() => {
1003
1247
  const rowSet = new Set(rowFields);
1004
1248
  const colSet = new Set(columnFields);
1005
1249
  const valSet = new Set(valueFields.map((v) => v.field));
1006
- return availableFields.filter(
1250
+ return allAvailableFields.filter(
1007
1251
  (f) => !rowSet.has(f.field) && !colSet.has(f.field) && !valSet.has(f.field)
1008
1252
  );
1009
- }, [availableFields, rowFields, columnFields, valueFields]);
1010
- const filteredUnassignedFields = (0, import_react6.useMemo)(() => {
1253
+ }, [allAvailableFields, rowFields, columnFields, valueFields]);
1254
+ const filteredUnassignedFields = (0, import_react7.useMemo)(() => {
1011
1255
  if (!fieldSearch.trim()) return unassignedFields;
1012
1256
  const search = fieldSearch.toLowerCase().trim();
1013
- return unassignedFields.filter((f) => f.field.toLowerCase().includes(search));
1257
+ return unassignedFields.filter((f) => {
1258
+ const fieldName = f.field.toLowerCase();
1259
+ const displayName = f.isCalculated && f.calcName ? f.calcName.toLowerCase() : "";
1260
+ return fieldName.includes(search) || displayName.includes(search);
1261
+ });
1014
1262
  }, [unassignedFields, fieldSearch]);
1015
1263
  const assignedCount = assignedFields.length;
1016
- const handleDragStart = (0, import_react6.useCallback)(
1264
+ const getFieldDisplayName = (0, import_react7.useCallback)((field) => {
1265
+ if (field.isCalculated && field.calcName) {
1266
+ return field.calcName;
1267
+ }
1268
+ return field.field;
1269
+ }, []);
1270
+ const handleDragStart = (0, import_react7.useCallback)(
1017
1271
  (field, event) => {
1018
1272
  event.dataTransfer?.setData("text/plain", field);
1019
1273
  event.dataTransfer.effectAllowed = "move";
@@ -1021,13 +1275,13 @@ function PivotConfig({
1021
1275
  },
1022
1276
  [onDragStart]
1023
1277
  );
1024
- const handleAggregationChange = (0, import_react6.useCallback)(
1278
+ const handleAggregationChange = (0, import_react7.useCallback)(
1025
1279
  (field, currentAgg, newAgg) => {
1026
1280
  onUpdateAggregation(field, currentAgg, newAgg);
1027
1281
  },
1028
1282
  [onUpdateAggregation]
1029
1283
  );
1030
- const toggleRowColumn = (0, import_react6.useCallback)(
1284
+ const toggleRowColumn = (0, import_react7.useCallback)(
1031
1285
  (field, currentAssignment) => {
1032
1286
  if (currentAssignment === "row") {
1033
1287
  onRemoveRowField(field);
@@ -1039,7 +1293,7 @@ function PivotConfig({
1039
1293
  },
1040
1294
  [onRemoveRowField, onAddColumnField, onRemoveColumnField, onAddRowField]
1041
1295
  );
1042
- const removeField = (0, import_react6.useCallback)(
1296
+ const removeField = (0, import_react7.useCallback)(
1043
1297
  (field, assignedTo, valueConfig) => {
1044
1298
  if (assignedTo === "row") {
1045
1299
  onRemoveRowField(field);
@@ -1051,10 +1305,31 @@ function PivotConfig({
1051
1305
  },
1052
1306
  [onRemoveRowField, onRemoveColumnField, onRemoveValueField]
1053
1307
  );
1054
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-pivot-config", children: [
1055
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-config-header", children: [
1056
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { className: "vpg-config-title", children: [
1057
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1308
+ const handleTotalsToggle = (0, import_react7.useCallback)((checked) => {
1309
+ onShowRowTotalsChange(checked);
1310
+ onShowColumnTotalsChange(checked);
1311
+ }, [onShowRowTotalsChange, onShowColumnTotalsChange]);
1312
+ const openCalcModal = (0, import_react7.useCallback)((field) => {
1313
+ setEditingCalcField(field || null);
1314
+ setShowCalcModal(true);
1315
+ }, []);
1316
+ const handleSaveCalcField = (0, import_react7.useCallback)((field) => {
1317
+ if (editingCalcField && onUpdateCalculatedField) {
1318
+ onUpdateCalculatedField(field);
1319
+ } else if (onAddCalculatedField) {
1320
+ onAddCalculatedField(field);
1321
+ }
1322
+ setShowCalcModal(false);
1323
+ setEditingCalcField(null);
1324
+ }, [editingCalcField, onAddCalculatedField, onUpdateCalculatedField]);
1325
+ const handleCloseCalcModal = (0, import_react7.useCallback)(() => {
1326
+ setShowCalcModal(false);
1327
+ setEditingCalcField(null);
1328
+ }, []);
1329
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-pivot-config", children: [
1330
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-config-header", children: [
1331
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("h3", { className: "vpg-config-title", children: [
1332
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1058
1333
  "path",
1059
1334
  {
1060
1335
  strokeLinecap: "round",
@@ -1065,13 +1340,13 @@ function PivotConfig({
1065
1340
  ) }),
1066
1341
  "Fields"
1067
1342
  ] }),
1068
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-header-actions", children: assignedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1343
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-header-actions", children: assignedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1069
1344
  "button",
1070
1345
  {
1071
1346
  className: "vpg-action-btn vpg-clear-btn",
1072
1347
  title: "Clear all",
1073
1348
  onClick: onClearConfig,
1074
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1349
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1075
1350
  "path",
1076
1351
  {
1077
1352
  strokeLinecap: "round",
@@ -1083,23 +1358,23 @@ function PivotConfig({
1083
1358
  }
1084
1359
  ) })
1085
1360
  ] }),
1086
- assignedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-assigned-section", children: [
1087
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-section-label", children: "Active" }),
1088
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-assigned-list", children: assignedFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1361
+ assignedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-assigned-section", children: [
1362
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-section-label", children: "Active" }),
1363
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-assigned-list", children: assignedFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1089
1364
  "div",
1090
1365
  {
1091
- className: `vpg-assigned-item vpg-type-${field.assignedTo}`,
1092
- title: field.field,
1366
+ className: `vpg-assigned-item vpg-type-${field.assignedTo}${field.isCalculated ? " vpg-type-calc" : ""}`,
1367
+ title: field.isCalculated ? field.calcFormula : field.field,
1093
1368
  draggable: true,
1094
1369
  onDragStart: (e) => handleDragStart(field.field, e),
1095
1370
  onDragEnd,
1096
1371
  children: [
1097
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-item-main", children: [
1098
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `vpg-item-badge ${field.assignedTo}`, children: field.assignedTo === "row" ? "R" : field.assignedTo === "column" ? "C" : (0, import_tinypivot_core5.getAggregationSymbol)(field.valueConfig?.aggregation || "sum") }),
1099
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vpg-item-name", children: field.field })
1372
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-item-main", children: [
1373
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `vpg-item-badge ${field.assignedTo}${field.isCalculated ? " calc" : ""}`, children: field.isCalculated ? "\u0192" : field.assignedTo === "row" ? "R" : field.assignedTo === "column" ? "C" : (0, import_tinypivot_core6.getAggregationSymbol)(field.valueConfig?.aggregation || "sum") }),
1374
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-item-name", children: getFieldDisplayName(field) })
1100
1375
  ] }),
1101
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-item-actions", children: [
1102
- (field.assignedTo === "row" || field.assignedTo === "column") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1376
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-item-actions", children: [
1377
+ (field.assignedTo === "row" || field.assignedTo === "column") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1103
1378
  "button",
1104
1379
  {
1105
1380
  className: "vpg-toggle-btn",
@@ -1108,14 +1383,14 @@ function PivotConfig({
1108
1383
  e.stopPropagation();
1109
1384
  toggleRowColumn(field.field, field.assignedTo);
1110
1385
  },
1111
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1386
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1112
1387
  "svg",
1113
1388
  {
1114
1389
  className: "vpg-icon-xs",
1115
1390
  fill: "none",
1116
1391
  stroke: "currentColor",
1117
1392
  viewBox: "0 0 24 24",
1118
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1393
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1119
1394
  "path",
1120
1395
  {
1121
1396
  strokeLinecap: "round",
@@ -1128,7 +1403,7 @@ function PivotConfig({
1128
1403
  )
1129
1404
  }
1130
1405
  ),
1131
- field.assignedTo === "value" && field.valueConfig && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1406
+ field.assignedTo === "value" && field.valueConfig && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1132
1407
  "select",
1133
1408
  {
1134
1409
  className: "vpg-agg-select",
@@ -1142,14 +1417,14 @@ function PivotConfig({
1142
1417
  );
1143
1418
  },
1144
1419
  onClick: (e) => e.stopPropagation(),
1145
- children: import_tinypivot_core5.AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: agg.value, children: [
1420
+ children: import_tinypivot_core6.AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("option", { value: agg.value, children: [
1146
1421
  agg.symbol,
1147
1422
  " ",
1148
1423
  agg.label
1149
1424
  ] }, agg.value))
1150
1425
  }
1151
1426
  ),
1152
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1427
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1153
1428
  "button",
1154
1429
  {
1155
1430
  className: "vpg-remove-btn",
@@ -1167,13 +1442,13 @@ function PivotConfig({
1167
1442
  field.field
1168
1443
  )) })
1169
1444
  ] }),
1170
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-unassigned-section", children: [
1171
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-section-header", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-section-label", children: [
1445
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-unassigned-section", children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-section-header", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-section-label", children: [
1172
1447
  "Available ",
1173
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vpg-count", children: unassignedFields.length })
1448
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-count", children: unassignedFields.length })
1174
1449
  ] }) }),
1175
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-field-search", children: [
1176
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "vpg-search-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1450
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-field-search", children: [
1451
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-search-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1177
1452
  "path",
1178
1453
  {
1179
1454
  strokeLinecap: "round",
@@ -1182,7 +1457,7 @@ function PivotConfig({
1182
1457
  d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
1183
1458
  }
1184
1459
  ) }),
1185
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1460
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1186
1461
  "input",
1187
1462
  {
1188
1463
  type: "text",
@@ -1192,7 +1467,7 @@ function PivotConfig({
1192
1467
  className: "vpg-search-input"
1193
1468
  }
1194
1469
  ),
1195
- fieldSearch && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "vpg-clear-search", onClick: () => setFieldSearch(""), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "vpg-icon-xs", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1470
+ fieldSearch && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { className: "vpg-clear-search", onClick: () => setFieldSearch(""), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-icon-xs", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1196
1471
  "path",
1197
1472
  {
1198
1473
  strokeLinecap: "round",
@@ -1202,64 +1477,93 @@ function PivotConfig({
1202
1477
  }
1203
1478
  ) }) })
1204
1479
  ] }),
1205
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-field-list", children: [
1206
- filteredUnassignedFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1480
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-field-list", children: [
1481
+ filteredUnassignedFields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1207
1482
  "div",
1208
1483
  {
1209
- className: `vpg-field-item ${field.isNumeric ? "vpg-is-numeric" : ""}`,
1210
- title: field.field,
1484
+ className: `vpg-field-item${field.isNumeric && !field.isCalculated ? " vpg-is-numeric" : ""}${field.isCalculated ? " vpg-is-calculated" : ""}`,
1485
+ title: field.isCalculated ? field.calcFormula : field.field,
1211
1486
  draggable: true,
1212
1487
  onDragStart: (e) => handleDragStart(field.field, e),
1213
1488
  onDragEnd,
1214
1489
  children: [
1215
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vpg-field-type-icon", title: field.type, children: getFieldIcon(field.type) }),
1216
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vpg-field-name", children: field.field }),
1217
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vpg-unique-count", children: field.uniqueCount })
1490
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `vpg-field-type-icon${field.isCalculated ? " vpg-calc-type" : ""}`, title: field.type, children: getFieldIcon(field.type, field.isCalculated) }),
1491
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-field-name", children: getFieldDisplayName(field) }),
1492
+ field.isCalculated ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1493
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1494
+ "button",
1495
+ {
1496
+ className: "vpg-field-edit",
1497
+ title: "Edit calculated field",
1498
+ onClick: (e) => {
1499
+ e.stopPropagation();
1500
+ const calcField = calculatedFields?.find((c) => c.id === field.calcId);
1501
+ if (calcField) openCalcModal(calcField);
1502
+ },
1503
+ children: "\u270E"
1504
+ }
1505
+ ),
1506
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1507
+ "button",
1508
+ {
1509
+ className: "vpg-field-delete",
1510
+ title: "Delete calculated field",
1511
+ onClick: (e) => {
1512
+ e.stopPropagation();
1513
+ if (field.calcId && onRemoveCalculatedField) {
1514
+ onRemoveCalculatedField(field.calcId);
1515
+ }
1516
+ },
1517
+ children: "\xD7"
1518
+ }
1519
+ )
1520
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-unique-count", children: field.uniqueCount })
1218
1521
  ]
1219
1522
  },
1220
1523
  field.field
1221
1524
  )),
1222
- filteredUnassignedFields.length === 0 && fieldSearch && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-empty-hint", children: [
1525
+ filteredUnassignedFields.length === 0 && fieldSearch && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-empty-hint", children: [
1223
1526
  'No fields match "',
1224
1527
  fieldSearch,
1225
1528
  '"'
1226
1529
  ] }),
1227
- unassignedFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-empty-hint", children: "All fields assigned" })
1530
+ unassignedFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-empty-hint", children: "All fields assigned" })
1228
1531
  ] })
1229
1532
  ] }),
1230
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vpg-options-section", children: [
1231
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "vpg-option-toggle", children: [
1232
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1533
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-options-section", children: [
1534
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "vpg-option-toggle", children: [
1535
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1233
1536
  "input",
1234
1537
  {
1235
1538
  type: "checkbox",
1236
1539
  checked: showRowTotals,
1237
- onChange: (e) => onShowRowTotalsChange(e.target.checked)
1540
+ onChange: (e) => handleTotalsToggle(e.target.checked)
1238
1541
  }
1239
1542
  ),
1240
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "Totals" })
1543
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Totals" })
1241
1544
  ] }),
1242
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: "vpg-auto-btn", onClick: onAutoSuggest, children: [
1243
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1244
- "path",
1245
- {
1246
- strokeLinecap: "round",
1247
- strokeLinejoin: "round",
1248
- strokeWidth: 2,
1249
- d: "M13 10V3L4 14h7v7l9-11h-7z"
1250
- }
1251
- ) }),
1252
- "Auto"
1545
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { className: "vpg-calc-btn", onClick: () => openCalcModal(), title: "Add calculated field (e.g. Profit Margin %)", children: [
1546
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-calc-icon", children: "\u0192" }),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "+ Calc" })
1253
1548
  ] })
1254
1549
  ] }),
1255
- showWatermark && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "vpg-watermark", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "TinyPivot" }) })
1550
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1551
+ CalculatedFieldModal,
1552
+ {
1553
+ show: showCalcModal,
1554
+ availableFields: numericFieldNames,
1555
+ existingField: editingCalcField,
1556
+ onClose: handleCloseCalcModal,
1557
+ onSave: handleSaveCalcField
1558
+ }
1559
+ )
1256
1560
  ] });
1257
1561
  }
1258
1562
 
1259
1563
  // src/components/PivotSkeleton.tsx
1260
- var import_react7 = require("react");
1261
- var import_tinypivot_core6 = require("@smallwebco/tinypivot-core");
1262
- var import_jsx_runtime3 = require("react/jsx-runtime");
1564
+ var import_react8 = require("react");
1565
+ var import_tinypivot_core7 = require("@smallwebco/tinypivot-core");
1566
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1263
1567
  function PivotSkeleton({
1264
1568
  rowFields,
1265
1569
  columnFields,
@@ -1281,12 +1585,12 @@ function PivotSkeleton({
1281
1585
  onReorderColumnFields
1282
1586
  }) {
1283
1587
  const { showWatermark, canUsePivot, isDemo } = useLicense();
1284
- const [dragOverArea, setDragOverArea] = (0, import_react7.useState)(null);
1285
- const [reorderDragSource, setReorderDragSource] = (0, import_react7.useState)(null);
1286
- const [reorderDropTarget, setReorderDropTarget] = (0, import_react7.useState)(null);
1287
- const [sortDirection, setSortDirection] = (0, import_react7.useState)("asc");
1288
- const [sortTarget, setSortTarget] = (0, import_react7.useState)("row");
1289
- const toggleSort = (0, import_react7.useCallback)((target = "row") => {
1588
+ const [dragOverArea, setDragOverArea] = (0, import_react8.useState)(null);
1589
+ const [reorderDragSource, setReorderDragSource] = (0, import_react8.useState)(null);
1590
+ const [reorderDropTarget, setReorderDropTarget] = (0, import_react8.useState)(null);
1591
+ const [sortDirection, setSortDirection] = (0, import_react8.useState)("asc");
1592
+ const [sortTarget, setSortTarget] = (0, import_react8.useState)("row");
1593
+ const toggleSort = (0, import_react8.useCallback)((target = "row") => {
1290
1594
  if (sortTarget === target) {
1291
1595
  setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
1292
1596
  } else {
@@ -1294,7 +1598,7 @@ function PivotSkeleton({
1294
1598
  setSortDirection("asc");
1295
1599
  }
1296
1600
  }, [sortTarget]);
1297
- const sortedRowIndices = (0, import_react7.useMemo)(() => {
1601
+ const sortedRowIndices = (0, import_react8.useMemo)(() => {
1298
1602
  if (!pivotResult) return [];
1299
1603
  const indices = pivotResult.rowHeaders.map((_, i) => i);
1300
1604
  const headers = pivotResult.rowHeaders;
@@ -1318,11 +1622,11 @@ function PivotSkeleton({
1318
1622
  });
1319
1623
  return indices;
1320
1624
  }, [pivotResult, sortTarget, sortDirection]);
1321
- const columnHeaderCells = (0, import_react7.useMemo)(() => {
1625
+ const columnHeaderCells = (0, import_react8.useMemo)(() => {
1322
1626
  if (!pivotResult || pivotResult.headers.length === 0) {
1323
1627
  return [
1324
1628
  valueFields.map((vf) => ({
1325
- label: `${vf.field} (${(0, import_tinypivot_core6.getAggregationLabel)(vf.aggregation)})`,
1629
+ label: `${vf.field} (${(0, import_tinypivot_core7.getAggregationLabel)(vf.aggregation)})`,
1326
1630
  colspan: 1
1327
1631
  }))
1328
1632
  ];
@@ -1346,12 +1650,12 @@ function PivotSkeleton({
1346
1650
  return result;
1347
1651
  }, [pivotResult, valueFields]);
1348
1652
  const hasActiveFilters = activeFilters && activeFilters.length > 0;
1349
- const filterSummary = (0, import_react7.useMemo)(() => {
1653
+ const filterSummary = (0, import_react8.useMemo)(() => {
1350
1654
  if (!activeFilters || activeFilters.length === 0) return "";
1351
1655
  return activeFilters.map((f) => f.column).join(", ");
1352
1656
  }, [activeFilters]);
1353
- const [showFilterTooltip, setShowFilterTooltip] = (0, import_react7.useState)(false);
1354
- const filterTooltipDetails = (0, import_react7.useMemo)(() => {
1657
+ const [showFilterTooltip, setShowFilterTooltip] = (0, import_react8.useState)(false);
1658
+ const filterTooltipDetails = (0, import_react8.useMemo)(() => {
1355
1659
  if (!activeFilters || activeFilters.length === 0) return [];
1356
1660
  return activeFilters.map((f) => {
1357
1661
  const maxDisplay = 5;
@@ -1364,7 +1668,7 @@ function PivotSkeleton({
1364
1668
  };
1365
1669
  });
1366
1670
  }, [activeFilters]);
1367
- const handleDragOver = (0, import_react7.useCallback)(
1671
+ const handleDragOver = (0, import_react8.useCallback)(
1368
1672
  (area, event) => {
1369
1673
  event.preventDefault();
1370
1674
  event.dataTransfer.dropEffect = "move";
@@ -1372,10 +1676,10 @@ function PivotSkeleton({
1372
1676
  },
1373
1677
  []
1374
1678
  );
1375
- const handleDragLeave = (0, import_react7.useCallback)(() => {
1679
+ const handleDragLeave = (0, import_react8.useCallback)(() => {
1376
1680
  setDragOverArea(null);
1377
1681
  }, []);
1378
- const handleDrop = (0, import_react7.useCallback)(
1682
+ const handleDrop = (0, import_react8.useCallback)(
1379
1683
  (area, event) => {
1380
1684
  event.preventDefault();
1381
1685
  const field = event.dataTransfer?.getData("text/plain");
@@ -1402,7 +1706,7 @@ function PivotSkeleton({
1402
1706
  },
1403
1707
  [rowFields, columnFields, valueFields, onAddRowField, onRemoveRowField, onAddColumnField, onRemoveColumnField, onAddValueField, onRemoveValueField]
1404
1708
  );
1405
- const handleChipDragStart = (0, import_react7.useCallback)(
1709
+ const handleChipDragStart = (0, import_react8.useCallback)(
1406
1710
  (zone, index, event) => {
1407
1711
  setReorderDragSource({ zone, index });
1408
1712
  event.dataTransfer.effectAllowed = "move";
@@ -1413,11 +1717,11 @@ function PivotSkeleton({
1413
1717
  },
1414
1718
  []
1415
1719
  );
1416
- const handleChipDragEnd = (0, import_react7.useCallback)(() => {
1720
+ const handleChipDragEnd = (0, import_react8.useCallback)(() => {
1417
1721
  setReorderDragSource(null);
1418
1722
  setReorderDropTarget(null);
1419
1723
  }, []);
1420
- const handleChipDragOver = (0, import_react7.useCallback)(
1724
+ const handleChipDragOver = (0, import_react8.useCallback)(
1421
1725
  (zone, index, event) => {
1422
1726
  event.preventDefault();
1423
1727
  if (reorderDragSource && reorderDragSource.zone === zone) {
@@ -1427,10 +1731,10 @@ function PivotSkeleton({
1427
1731
  },
1428
1732
  [reorderDragSource]
1429
1733
  );
1430
- const handleChipDragLeave = (0, import_react7.useCallback)(() => {
1734
+ const handleChipDragLeave = (0, import_react8.useCallback)(() => {
1431
1735
  setReorderDropTarget(null);
1432
1736
  }, []);
1433
- const handleChipDrop = (0, import_react7.useCallback)(
1737
+ const handleChipDrop = (0, import_react8.useCallback)(
1434
1738
  (zone, targetIndex, event) => {
1435
1739
  event.preventDefault();
1436
1740
  event.stopPropagation();
@@ -1456,27 +1760,27 @@ function PivotSkeleton({
1456
1760
  },
1457
1761
  [reorderDragSource, rowFields, columnFields, onReorderRowFields, onReorderColumnFields]
1458
1762
  );
1459
- const isChipDragSource = (0, import_react7.useCallback)(
1763
+ const isChipDragSource = (0, import_react8.useCallback)(
1460
1764
  (zone, index) => {
1461
1765
  return reorderDragSource?.zone === zone && reorderDragSource?.index === index;
1462
1766
  },
1463
1767
  [reorderDragSource]
1464
1768
  );
1465
- const isChipDropTarget = (0, import_react7.useCallback)(
1769
+ const isChipDropTarget = (0, import_react8.useCallback)(
1466
1770
  (zone, index) => {
1467
1771
  return reorderDropTarget?.zone === zone && reorderDropTarget?.index === index;
1468
1772
  },
1469
1773
  [reorderDropTarget]
1470
1774
  );
1471
1775
  const currentFontSize = fontSize;
1472
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1776
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1473
1777
  "div",
1474
1778
  {
1475
1779
  className: `vpg-pivot-skeleton vpg-font-${currentFontSize} ${draggingField ? "vpg-is-dragging" : ""}`,
1476
1780
  children: [
1477
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-skeleton-header", children: [
1478
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-skeleton-title", children: [
1479
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1781
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-skeleton-header", children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-skeleton-title", children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1480
1784
  "path",
1481
1785
  {
1482
1786
  strokeLinecap: "round",
@@ -1485,24 +1789,24 @@ function PivotSkeleton({
1485
1789
  d: "M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"
1486
1790
  }
1487
1791
  ) }),
1488
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Pivot Table" })
1792
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Pivot Table" })
1489
1793
  ] }),
1490
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-header-right", children: [
1491
- hasActiveFilters && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1794
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-header-right", children: [
1795
+ hasActiveFilters && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1492
1796
  "div",
1493
1797
  {
1494
1798
  className: "vpg-filter-indicator",
1495
1799
  onMouseEnter: () => setShowFilterTooltip(true),
1496
1800
  onMouseLeave: () => setShowFilterTooltip(false),
1497
1801
  children: [
1498
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1802
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1499
1803
  "svg",
1500
1804
  {
1501
1805
  className: "vpg-filter-icon",
1502
1806
  fill: "none",
1503
1807
  stroke: "currentColor",
1504
1808
  viewBox: "0 0 24 24",
1505
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1809
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1506
1810
  "path",
1507
1811
  {
1508
1812
  strokeLinecap: "round",
@@ -1513,10 +1817,10 @@ function PivotSkeleton({
1513
1817
  )
1514
1818
  }
1515
1819
  ),
1516
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-filter-text", children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-filter-text", children: [
1517
1821
  "Filtered: ",
1518
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: filterSummary }),
1519
- filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-filter-count", children: [
1822
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: filterSummary }),
1823
+ filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-filter-count", children: [
1520
1824
  "(",
1521
1825
  filteredRowCount.toLocaleString(),
1522
1826
  " of ",
@@ -1524,20 +1828,20 @@ function PivotSkeleton({
1524
1828
  " rows)"
1525
1829
  ] })
1526
1830
  ] }),
1527
- showFilterTooltip && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-filter-tooltip", children: [
1528
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-tooltip-header", children: "Active Filters" }),
1529
- filterTooltipDetails.map((filter) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-tooltip-filter", children: [
1530
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-tooltip-column", children: filter.column }),
1531
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-tooltip-values", children: [
1532
- filter.values.map((val, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-tooltip-value", children: val }, idx)),
1533
- filter.remaining > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-tooltip-more", children: [
1831
+ showFilterTooltip && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-filter-tooltip", children: [
1832
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-tooltip-header", children: "Active Filters" }),
1833
+ filterTooltipDetails.map((filter) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-tooltip-filter", children: [
1834
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-tooltip-column", children: filter.column }),
1835
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-tooltip-values", children: [
1836
+ filter.values.map((val, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-tooltip-value", children: val }, idx)),
1837
+ filter.remaining > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-tooltip-more", children: [
1534
1838
  "+",
1535
1839
  filter.remaining,
1536
1840
  " more"
1537
1841
  ] })
1538
1842
  ] })
1539
1843
  ] }, filter.column)),
1540
- filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-tooltip-summary", children: [
1844
+ filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-tooltip-summary", children: [
1541
1845
  "Showing ",
1542
1846
  filteredRowCount.toLocaleString(),
1543
1847
  " of ",
@@ -1548,18 +1852,18 @@ function PivotSkeleton({
1548
1852
  ]
1549
1853
  }
1550
1854
  ),
1551
- isConfigured && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-config-summary", children: [
1552
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-summary-badge vpg-rows", children: [
1855
+ isConfigured && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-config-summary", children: [
1856
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-summary-badge vpg-rows", children: [
1553
1857
  rowFields.length,
1554
1858
  " row",
1555
1859
  rowFields.length !== 1 ? "s" : ""
1556
1860
  ] }),
1557
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-summary-badge vpg-cols", children: [
1861
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-summary-badge vpg-cols", children: [
1558
1862
  columnFields.length,
1559
1863
  " col",
1560
1864
  columnFields.length !== 1 ? "s" : ""
1561
1865
  ] }),
1562
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "vpg-summary-badge vpg-vals", children: [
1866
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-summary-badge vpg-vals", children: [
1563
1867
  valueFields.length,
1564
1868
  " val",
1565
1869
  valueFields.length !== 1 ? "s" : ""
@@ -1567,8 +1871,8 @@ function PivotSkeleton({
1567
1871
  ] })
1568
1872
  ] })
1569
1873
  ] }),
1570
- !canUsePivot ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-pro-required", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-pro-content", children: [
1571
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { className: "vpg-pro-icon", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1874
+ !canUsePivot ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-pro-required", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-pro-content", children: [
1875
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-pro-icon", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1572
1876
  "path",
1573
1877
  {
1574
1878
  strokeLinecap: "round",
@@ -1577,12 +1881,12 @@ function PivotSkeleton({
1577
1881
  d: "M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"
1578
1882
  }
1579
1883
  ) }),
1580
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { children: "Pro Feature" }),
1581
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "Pivot Table functionality requires a Pro license." }),
1582
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", className: "vpg-pro-link", children: "Get Pro License \u2192" })
1583
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1584
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-config-bar", children: [
1585
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1884
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: "Pro Feature" }),
1885
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "Pivot Table functionality requires a Pro license." }),
1886
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", className: "vpg-pro-link", children: "Get Pro License \u2192" })
1887
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1888
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-config-bar", children: [
1889
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1586
1890
  "div",
1587
1891
  {
1588
1892
  className: `vpg-drop-zone vpg-row-zone ${dragOverArea === "row" ? "vpg-drag-over" : ""}`,
@@ -1590,12 +1894,12 @@ function PivotSkeleton({
1590
1894
  onDragLeave: handleDragLeave,
1591
1895
  onDrop: (e) => handleDrop("row", e),
1592
1896
  children: [
1593
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-header", children: [
1594
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-icon vpg-row-icon", children: "\u2193" }),
1595
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-label", children: "Rows" })
1897
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-header", children: [
1898
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-icon vpg-row-icon", children: "\u2193" }),
1899
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-label", children: "Rows" })
1596
1900
  ] }),
1597
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-chips", children: [
1598
- rowFields.map((field, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1901
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-chips", children: [
1902
+ rowFields.map((field, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1599
1903
  "div",
1600
1904
  {
1601
1905
  className: `vpg-mini-chip vpg-row-chip ${isChipDragSource("row", idx) ? "vpg-chip-dragging" : ""} ${isChipDropTarget("row", idx) ? "vpg-chip-drop-target" : ""}`,
@@ -1606,9 +1910,9 @@ function PivotSkeleton({
1606
1910
  onDragLeave: handleChipDragLeave,
1607
1911
  onDrop: (e) => handleChipDrop("row", idx, e),
1608
1912
  children: [
1609
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1610
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-mini-name", children: field }),
1611
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1913
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-mini-name", children: field }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1612
1916
  "button",
1613
1917
  {
1614
1918
  className: "vpg-mini-remove",
@@ -1623,12 +1927,12 @@ function PivotSkeleton({
1623
1927
  },
1624
1928
  field
1625
1929
  )),
1626
- rowFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-hint", children: "Drop here" })
1930
+ rowFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-hint", children: "Drop here" })
1627
1931
  ] })
1628
1932
  ]
1629
1933
  }
1630
1934
  ),
1631
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1935
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1632
1936
  "div",
1633
1937
  {
1634
1938
  className: `vpg-drop-zone vpg-column-zone ${dragOverArea === "column" ? "vpg-drag-over" : ""}`,
@@ -1636,12 +1940,12 @@ function PivotSkeleton({
1636
1940
  onDragLeave: handleDragLeave,
1637
1941
  onDrop: (e) => handleDrop("column", e),
1638
1942
  children: [
1639
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-header", children: [
1640
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-icon vpg-column-icon", children: "\u2192" }),
1641
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-label", children: "Columns" })
1943
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-header", children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-icon vpg-column-icon", children: "\u2192" }),
1945
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-label", children: "Columns" })
1642
1946
  ] }),
1643
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-chips", children: [
1644
- columnFields.map((field, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1947
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-chips", children: [
1948
+ columnFields.map((field, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1645
1949
  "div",
1646
1950
  {
1647
1951
  className: `vpg-mini-chip vpg-column-chip ${isChipDragSource("column", idx) ? "vpg-chip-dragging" : ""} ${isChipDropTarget("column", idx) ? "vpg-chip-drop-target" : ""}`,
@@ -1652,9 +1956,9 @@ function PivotSkeleton({
1652
1956
  onDragLeave: handleChipDragLeave,
1653
1957
  onDrop: (e) => handleChipDrop("column", idx, e),
1654
1958
  children: [
1655
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-mini-name", children: field }),
1657
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1959
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1960
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-mini-name", children: field }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1658
1962
  "button",
1659
1963
  {
1660
1964
  className: "vpg-mini-remove",
@@ -1669,12 +1973,12 @@ function PivotSkeleton({
1669
1973
  },
1670
1974
  field
1671
1975
  )),
1672
- columnFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-hint", children: "Drop here" })
1976
+ columnFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-hint", children: "Drop here" })
1673
1977
  ] })
1674
1978
  ]
1675
1979
  }
1676
1980
  ),
1677
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1981
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1678
1982
  "div",
1679
1983
  {
1680
1984
  className: `vpg-drop-zone vpg-value-zone ${dragOverArea === "value" ? "vpg-drag-over" : ""}`,
@@ -1682,19 +1986,19 @@ function PivotSkeleton({
1682
1986
  onDragLeave: handleDragLeave,
1683
1987
  onDrop: (e) => handleDrop("value", e),
1684
1988
  children: [
1685
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-header", children: [
1686
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-icon vpg-value-icon", children: "\u03A3" }),
1687
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-label", children: "Values" })
1989
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-header", children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-icon vpg-value-icon", children: "\u03A3" }),
1991
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-label", children: "Values" })
1688
1992
  ] }),
1689
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-zone-chips", children: [
1690
- valueFields.map((vf) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1993
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-zone-chips", children: [
1994
+ valueFields.map((vf) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1691
1995
  "div",
1692
1996
  {
1693
1997
  className: "vpg-mini-chip vpg-value-chip",
1694
1998
  children: [
1695
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-agg-symbol", children: (0, import_tinypivot_core6.getAggregationSymbol)(vf.aggregation) }),
1696
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-mini-name", children: vf.field }),
1697
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1999
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-agg-symbol", children: (0, import_tinypivot_core7.getAggregationSymbol)(vf.aggregation) }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-mini-name", children: vf.field }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1698
2002
  "button",
1699
2003
  {
1700
2004
  className: "vpg-mini-remove",
@@ -1706,21 +2010,21 @@ function PivotSkeleton({
1706
2010
  },
1707
2011
  `${vf.field}-${vf.aggregation}`
1708
2012
  )),
1709
- valueFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-zone-hint", children: "Drop numeric" })
2013
+ valueFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-zone-hint", children: "Drop numeric" })
1710
2014
  ] })
1711
2015
  ]
1712
2016
  }
1713
2017
  )
1714
2018
  ] }),
1715
- (!isConfigured || !pivotResult) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-placeholder-content", children: [
1716
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2019
+ (!isConfigured || !pivotResult) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-placeholder", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-placeholder-content", children: [
2020
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1717
2021
  "svg",
1718
2022
  {
1719
2023
  className: "vpg-placeholder-icon",
1720
2024
  fill: "none",
1721
2025
  viewBox: "0 0 24 24",
1722
2026
  stroke: "currentColor",
1723
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2027
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1724
2028
  "path",
1725
2029
  {
1726
2030
  strokeLinecap: "round",
@@ -1731,51 +2035,51 @@ function PivotSkeleton({
1731
2035
  )
1732
2036
  }
1733
2037
  ),
1734
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-placeholder-text", children: valueFields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2038
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-placeholder-text", children: valueFields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1735
2039
  "Add a ",
1736
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Values" }),
2040
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Values" }),
1737
2041
  " field to see your pivot table"
1738
- ] }) : rowFields.length === 0 && columnFields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2042
+ ] }) : rowFields.length === 0 && columnFields.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1739
2043
  "Add ",
1740
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Row" }),
2044
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Row" }),
1741
2045
  " or ",
1742
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: "Column" }),
2046
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "Column" }),
1743
2047
  " fields to group your data"
1744
2048
  ] }) : "Your pivot table will appear here" })
1745
2049
  ] }) }),
1746
- isConfigured && pivotResult && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-table-container", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("table", { className: "vpg-pivot-table", children: [
1747
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("thead", { children: columnHeaderCells.map((headerRow, levelIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "vpg-column-header-row", children: [
1748
- levelIdx === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2050
+ isConfigured && pivotResult && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-table-container", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "vpg-pivot-table", children: [
2051
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: columnHeaderCells.map((headerRow, levelIdx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "vpg-column-header-row", children: [
2052
+ levelIdx === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1749
2053
  "th",
1750
2054
  {
1751
2055
  className: "vpg-row-header-label",
1752
2056
  rowSpan: columnHeaderCells.length,
1753
2057
  onClick: () => toggleSort("row"),
1754
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-header-content", children: [
1755
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: rowFields.join(" / ") || "Rows" }),
1756
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2058
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-header-content", children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: rowFields.join(" / ") || "Rows" }),
2060
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
1757
2061
  ] })
1758
2062
  }
1759
2063
  ),
1760
- headerRow.map((cell, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2064
+ headerRow.map((cell, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1761
2065
  "th",
1762
2066
  {
1763
2067
  className: "vpg-column-header-cell",
1764
2068
  colSpan: cell.colspan,
1765
2069
  onClick: () => levelIdx === columnHeaderCells.length - 1 && toggleSort(idx),
1766
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "vpg-header-content", children: [
1767
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: cell.label }),
1768
- levelIdx === columnHeaderCells.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: `vpg-sort-indicator ${sortTarget === idx ? "active" : ""}`, children: sortTarget === idx ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2070
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-header-content", children: [
2071
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: cell.label }),
2072
+ levelIdx === columnHeaderCells.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `vpg-sort-indicator ${sortTarget === idx ? "active" : ""}`, children: sortTarget === idx ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
1769
2073
  ] })
1770
2074
  },
1771
2075
  idx
1772
2076
  )),
1773
- pivotResult.rowTotals.length > 0 && levelIdx === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "vpg-total-header", rowSpan: columnHeaderCells.length, children: "Total" })
2077
+ pivotResult.rowTotals.length > 0 && levelIdx === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "vpg-total-header", rowSpan: columnHeaderCells.length, children: "Total" })
1774
2078
  ] }, `header-${levelIdx}`)) }),
1775
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tbody", { children: [
1776
- sortedRowIndices.map((sortedIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "vpg-data-row", children: [
1777
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "vpg-row-header-cell", children: pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-row-value", children: val }, idx)) }),
1778
- pivotResult.data[sortedIdx].map((cell, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2079
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tbody", { children: [
2080
+ sortedRowIndices.map((sortedIdx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "vpg-data-row", children: [
2081
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "vpg-row-header-cell", children: pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-row-value", children: val }, idx)) }),
2082
+ pivotResult.data[sortedIdx].map((cell, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1779
2083
  "td",
1780
2084
  {
1781
2085
  className: `vpg-data-cell ${cell.value === null ? "vpg-is-null" : ""}`,
@@ -1783,26 +2087,26 @@ function PivotSkeleton({
1783
2087
  },
1784
2088
  colIdx
1785
2089
  )),
1786
- pivotResult.rowTotals[sortedIdx] && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "vpg-data-cell vpg-total-cell", children: pivotResult.rowTotals[sortedIdx].formattedValue })
2090
+ pivotResult.rowTotals[sortedIdx] && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "vpg-data-cell vpg-total-cell", children: pivotResult.rowTotals[sortedIdx].formattedValue })
1787
2091
  ] }, sortedIdx)),
1788
- pivotResult.columnTotals.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("tr", { className: "vpg-totals-row", children: [
1789
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("th", { className: "vpg-row-header-cell vpg-total-label", children: "Total" }),
1790
- pivotResult.columnTotals.map((cell, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "vpg-data-cell vpg-total-cell", children: cell.formattedValue }, colIdx)),
1791
- pivotResult.rowTotals.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("td", { className: "vpg-data-cell vpg-grand-total-cell", children: pivotResult.grandTotal.formattedValue })
2092
+ pivotResult.columnTotals.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { className: "vpg-totals-row", children: [
2093
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { className: "vpg-row-header-cell vpg-total-label", children: "Total" }),
2094
+ pivotResult.columnTotals.map((cell, colIdx) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "vpg-data-cell vpg-total-cell", children: cell.formattedValue }, colIdx)),
2095
+ pivotResult.rowTotals.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { className: "vpg-data-cell vpg-grand-total-cell", children: pivotResult.grandTotal.formattedValue })
1792
2096
  ] })
1793
2097
  ] })
1794
2098
  ] }) }),
1795
- isConfigured && pivotResult && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vpg-skeleton-footer", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
2099
+ isConfigured && pivotResult && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-skeleton-footer", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1796
2100
  pivotResult.rowHeaders.length,
1797
2101
  " rows \xD7 ",
1798
2102
  pivotResult.data[0]?.length || 0,
1799
2103
  " columns"
1800
2104
  ] }) })
1801
2105
  ] }),
1802
- showWatermark && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: `vpg-watermark ${isDemo ? "vpg-demo-mode" : ""}`, children: isDemo ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1803
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "vpg-demo-badge", children: "DEMO" }),
1804
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Pro features unlocked for evaluation" }),
1805
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2106
+ showWatermark && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `vpg-watermark ${isDemo ? "vpg-demo-mode" : ""}`, children: isDemo ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2107
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-demo-badge", children: "DEMO" }),
2108
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Pro features unlocked for evaluation" }),
2109
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1806
2110
  "a",
1807
2111
  {
1808
2112
  href: "https://tiny-pivot.com/#pricing",
@@ -1812,14 +2116,14 @@ function PivotSkeleton({
1812
2116
  children: "Get Pro License \u2192"
1813
2117
  }
1814
2118
  )
1815
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "Powered by TinyPivot" }) })
2119
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "Powered by TinyPivot" }) })
1816
2120
  ]
1817
2121
  }
1818
2122
  );
1819
2123
  }
1820
2124
 
1821
2125
  // src/components/DataGrid.tsx
1822
- var import_jsx_runtime4 = require("react/jsx-runtime");
2126
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1823
2127
  var MIN_COL_WIDTH = 120;
1824
2128
  var MAX_COL_WIDTH = 350;
1825
2129
  function DataGrid({
@@ -1845,37 +2149,37 @@ function DataGrid({
1845
2149
  onCopy
1846
2150
  }) {
1847
2151
  const { showWatermark, canUsePivot, isDemo } = useLicense();
1848
- const currentTheme = (0, import_react8.useMemo)(() => {
2152
+ const currentTheme = (0, import_react9.useMemo)(() => {
1849
2153
  if (theme === "auto") {
1850
2154
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1851
2155
  }
1852
2156
  return theme;
1853
2157
  }, [theme]);
1854
- const [currentFontSize, setCurrentFontSize] = (0, import_react8.useState)(initialFontSize);
1855
- const [globalSearchTerm, setGlobalSearchTerm] = (0, import_react8.useState)("");
1856
- const [showSearchInput, setShowSearchInput] = (0, import_react8.useState)(false);
1857
- const [currentPage, setCurrentPage] = (0, import_react8.useState)(1);
1858
- const [columnWidths, setColumnWidths] = (0, import_react8.useState)({});
1859
- const [resizingColumnId, setResizingColumnId] = (0, import_react8.useState)(null);
1860
- const [resizeStartX, setResizeStartX] = (0, import_react8.useState)(0);
1861
- const [resizeStartWidth, setResizeStartWidth] = (0, import_react8.useState)(0);
1862
- const [gridHeight, setGridHeight] = (0, import_react8.useState)(initialHeight);
1863
- const [isResizingVertically, setIsResizingVertically] = (0, import_react8.useState)(false);
1864
- const [verticalResizeStartY, setVerticalResizeStartY] = (0, import_react8.useState)(0);
1865
- const [verticalResizeStartHeight, setVerticalResizeStartHeight] = (0, import_react8.useState)(0);
1866
- const [showCopyToast, setShowCopyToast] = (0, import_react8.useState)(false);
1867
- const [copyToastMessage, setCopyToastMessage] = (0, import_react8.useState)("");
1868
- const [viewMode, setViewMode] = (0, import_react8.useState)("grid");
1869
- const [showPivotConfig, setShowPivotConfig] = (0, import_react8.useState)(true);
1870
- const [draggingField, setDraggingField] = (0, import_react8.useState)(null);
1871
- const [activeFilterColumn, setActiveFilterColumn] = (0, import_react8.useState)(null);
1872
- const [filterDropdownPosition, setFilterDropdownPosition] = (0, import_react8.useState)({ top: 0, left: 0, maxHeight: 400 });
1873
- const [selectedCell, setSelectedCell] = (0, import_react8.useState)(null);
1874
- const [selectionStart, setSelectionStart] = (0, import_react8.useState)(null);
1875
- const [selectionEnd, setSelectionEnd] = (0, import_react8.useState)(null);
1876
- const [isSelecting, setIsSelecting] = (0, import_react8.useState)(false);
1877
- const tableContainerRef = (0, import_react8.useRef)(null);
1878
- const tableBodyRef = (0, import_react8.useRef)(null);
2158
+ const [currentFontSize, setCurrentFontSize] = (0, import_react9.useState)(initialFontSize);
2159
+ const [globalSearchTerm, setGlobalSearchTerm] = (0, import_react9.useState)("");
2160
+ const [showSearchInput, setShowSearchInput] = (0, import_react9.useState)(false);
2161
+ const [currentPage, setCurrentPage] = (0, import_react9.useState)(1);
2162
+ const [columnWidths, setColumnWidths] = (0, import_react9.useState)({});
2163
+ const [resizingColumnId, setResizingColumnId] = (0, import_react9.useState)(null);
2164
+ const [resizeStartX, setResizeStartX] = (0, import_react9.useState)(0);
2165
+ const [resizeStartWidth, setResizeStartWidth] = (0, import_react9.useState)(0);
2166
+ const [gridHeight, setGridHeight] = (0, import_react9.useState)(initialHeight);
2167
+ const [isResizingVertically, setIsResizingVertically] = (0, import_react9.useState)(false);
2168
+ const [verticalResizeStartY, setVerticalResizeStartY] = (0, import_react9.useState)(0);
2169
+ const [verticalResizeStartHeight, setVerticalResizeStartHeight] = (0, import_react9.useState)(0);
2170
+ const [showCopyToast, setShowCopyToast] = (0, import_react9.useState)(false);
2171
+ const [copyToastMessage, setCopyToastMessage] = (0, import_react9.useState)("");
2172
+ const [viewMode, setViewMode] = (0, import_react9.useState)("grid");
2173
+ const [showPivotConfig, setShowPivotConfig] = (0, import_react9.useState)(true);
2174
+ const [draggingField, setDraggingField] = (0, import_react9.useState)(null);
2175
+ const [activeFilterColumn, setActiveFilterColumn] = (0, import_react9.useState)(null);
2176
+ const [filterDropdownPosition, setFilterDropdownPosition] = (0, import_react9.useState)({ top: 0, left: 0, maxHeight: 400 });
2177
+ const [selectedCell, setSelectedCell] = (0, import_react9.useState)(null);
2178
+ const [selectionStart, setSelectionStart] = (0, import_react9.useState)(null);
2179
+ const [selectionEnd, setSelectionEnd] = (0, import_react9.useState)(null);
2180
+ const [isSelecting, setIsSelecting] = (0, import_react9.useState)(false);
2181
+ const tableContainerRef = (0, import_react9.useRef)(null);
2182
+ const tableBodyRef = (0, import_react9.useRef)(null);
1879
2183
  const fontSizeOptions = [
1880
2184
  { value: "xs", label: "S" },
1881
2185
  { value: "sm", label: "M" },
@@ -1896,7 +2200,7 @@ function DataGrid({
1896
2200
  columnFilters,
1897
2201
  activeFilters
1898
2202
  } = useExcelGrid({ data, enableSorting: true, enableFiltering: true });
1899
- const filteredDataForPivot = (0, import_react8.useMemo)(() => {
2203
+ const filteredDataForPivot = (0, import_react9.useMemo)(() => {
1900
2204
  const filteredRows = table.getFilteredRowModel().rows;
1901
2205
  return filteredRows.map((row) => row.original);
1902
2206
  }, [table, columnFilters]);
@@ -1906,6 +2210,7 @@ function DataGrid({
1906
2210
  valueFields: pivotValueFields,
1907
2211
  showRowTotals: pivotShowRowTotals,
1908
2212
  showColumnTotals: pivotShowColumnTotals,
2213
+ calculatedFields: pivotCalculatedFields,
1909
2214
  availableFields: pivotAvailableFields,
1910
2215
  isConfigured: pivotIsConfigured,
1911
2216
  pivotResult,
@@ -1921,9 +2226,11 @@ function DataGrid({
1921
2226
  setShowRowTotals: setPivotShowRowTotals,
1922
2227
  setShowColumnTotals: setPivotShowColumnTotals,
1923
2228
  setRowFields,
1924
- setColumnFields
2229
+ setColumnFields,
2230
+ addCalculatedField,
2231
+ removeCalculatedField
1925
2232
  } = usePivotTable(filteredDataForPivot);
1926
- const activeFilterInfo = (0, import_react8.useMemo)(() => {
2233
+ const activeFilterInfo = (0, import_react9.useMemo)(() => {
1927
2234
  if (activeFilters.length === 0) return null;
1928
2235
  return activeFilters.map((f) => ({
1929
2236
  column: f.column,
@@ -1931,8 +2238,8 @@ function DataGrid({
1931
2238
  values: f.values || []
1932
2239
  }));
1933
2240
  }, [activeFilters]);
1934
- const rows = (0, import_react8.useMemo)(() => table.getFilteredRowModel().rows, [table, columnFilters]);
1935
- const searchFilteredData = (0, import_react8.useMemo)(() => {
2241
+ const rows = (0, import_react9.useMemo)(() => table.getFilteredRowModel().rows, [table, columnFilters]);
2242
+ const searchFilteredData = (0, import_react9.useMemo)(() => {
1936
2243
  if (!globalSearchTerm.trim() || !enableSearch) {
1937
2244
  return rows;
1938
2245
  }
@@ -1949,20 +2256,20 @@ function DataGrid({
1949
2256
  });
1950
2257
  }, [rows, globalSearchTerm, enableSearch, columnKeys]);
1951
2258
  const totalSearchedRows = searchFilteredData.length;
1952
- const totalPages = (0, import_react8.useMemo)(() => {
2259
+ const totalPages = (0, import_react9.useMemo)(() => {
1953
2260
  if (!enablePagination) return 1;
1954
2261
  return Math.max(1, Math.ceil(totalSearchedRows / pageSize));
1955
2262
  }, [enablePagination, totalSearchedRows, pageSize]);
1956
- const paginatedRows = (0, import_react8.useMemo)(() => {
2263
+ const paginatedRows = (0, import_react9.useMemo)(() => {
1957
2264
  if (!enablePagination) return searchFilteredData;
1958
2265
  const start = (currentPage - 1) * pageSize;
1959
2266
  const end = start + pageSize;
1960
2267
  return searchFilteredData.slice(start, end);
1961
2268
  }, [enablePagination, searchFilteredData, currentPage, pageSize]);
1962
- (0, import_react8.useEffect)(() => {
2269
+ (0, import_react9.useEffect)(() => {
1963
2270
  setCurrentPage(1);
1964
2271
  }, [columnFilters, globalSearchTerm]);
1965
- const selectionBounds = (0, import_react8.useMemo)(() => {
2272
+ const selectionBounds = (0, import_react9.useMemo)(() => {
1966
2273
  if (!selectionStart || !selectionEnd) return null;
1967
2274
  return {
1968
2275
  minRow: Math.min(selectionStart.row, selectionEnd.row),
@@ -1971,7 +2278,7 @@ function DataGrid({
1971
2278
  maxCol: Math.max(selectionStart.col, selectionEnd.col)
1972
2279
  };
1973
2280
  }, [selectionStart, selectionEnd]);
1974
- const selectionStats = (0, import_react8.useMemo)(() => {
2281
+ const selectionStats = (0, import_react9.useMemo)(() => {
1975
2282
  if (!selectionBounds) return null;
1976
2283
  const { minRow, maxRow, minCol, maxCol } = selectionBounds;
1977
2284
  const values = [];
@@ -1997,7 +2304,7 @@ function DataGrid({
1997
2304
  const avg = sum / values.length;
1998
2305
  return { count, sum, avg, numericCount: values.length };
1999
2306
  }, [selectionBounds, rows, columnKeys]);
2000
- (0, import_react8.useEffect)(() => {
2307
+ (0, import_react9.useEffect)(() => {
2001
2308
  if (data.length === 0) return;
2002
2309
  const widths = {};
2003
2310
  const sampleSize = Math.min(100, data.length);
@@ -2017,7 +2324,7 @@ function DataGrid({
2017
2324
  }
2018
2325
  setColumnWidths(widths);
2019
2326
  }, [data, columnKeys]);
2020
- const startColumnResize = (0, import_react8.useCallback)(
2327
+ const startColumnResize = (0, import_react9.useCallback)(
2021
2328
  (columnId, event) => {
2022
2329
  if (!enableColumnResize) return;
2023
2330
  event.preventDefault();
@@ -2028,7 +2335,7 @@ function DataGrid({
2028
2335
  },
2029
2336
  [enableColumnResize, columnWidths]
2030
2337
  );
2031
- (0, import_react8.useEffect)(() => {
2338
+ (0, import_react9.useEffect)(() => {
2032
2339
  if (!resizingColumnId) return;
2033
2340
  const handleResizeMove = (event) => {
2034
2341
  const diff = event.clientX - resizeStartX;
@@ -2048,7 +2355,7 @@ function DataGrid({
2048
2355
  document.removeEventListener("mouseup", handleResizeEnd);
2049
2356
  };
2050
2357
  }, [resizingColumnId, resizeStartX, resizeStartWidth]);
2051
- const startVerticalResize = (0, import_react8.useCallback)(
2358
+ const startVerticalResize = (0, import_react9.useCallback)(
2052
2359
  (event) => {
2053
2360
  if (!enableVerticalResize) return;
2054
2361
  event.preventDefault();
@@ -2058,7 +2365,7 @@ function DataGrid({
2058
2365
  },
2059
2366
  [enableVerticalResize, gridHeight]
2060
2367
  );
2061
- (0, import_react8.useEffect)(() => {
2368
+ (0, import_react9.useEffect)(() => {
2062
2369
  if (!isResizingVertically) return;
2063
2370
  const handleVerticalResizeMove = (event) => {
2064
2371
  const diff = event.clientY - verticalResizeStartY;
@@ -2075,7 +2382,7 @@ function DataGrid({
2075
2382
  document.removeEventListener("mouseup", handleVerticalResizeEnd);
2076
2383
  };
2077
2384
  }, [isResizingVertically, verticalResizeStartY, verticalResizeStartHeight, minHeight, maxHeight]);
2078
- const handleExport = (0, import_react8.useCallback)(() => {
2385
+ const handleExport = (0, import_react9.useCallback)(() => {
2079
2386
  if (viewMode === "pivot") {
2080
2387
  if (!pivotResult) return;
2081
2388
  const pivotFilename = exportFilename.replace(".csv", "-pivot.csv");
@@ -2120,7 +2427,7 @@ function DataGrid({
2120
2427
  columnKeys,
2121
2428
  onExport
2122
2429
  ]);
2123
- const copySelectionToClipboard = (0, import_react8.useCallback)(() => {
2430
+ const copySelectionToClipboard = (0, import_react9.useCallback)(() => {
2124
2431
  if (!selectionBounds || !enableClipboard) return;
2125
2432
  const text = formatSelectionForClipboard(
2126
2433
  rows.map((r) => r.original),
@@ -2144,7 +2451,7 @@ function DataGrid({
2144
2451
  }
2145
2452
  );
2146
2453
  }, [selectionBounds, enableClipboard, rows, columnKeys, onCopy]);
2147
- const handleMouseDown = (0, import_react8.useCallback)(
2454
+ const handleMouseDown = (0, import_react9.useCallback)(
2148
2455
  (rowIndex, colIndex, event) => {
2149
2456
  event.preventDefault();
2150
2457
  if (event.shiftKey && selectedCell) {
@@ -2168,7 +2475,7 @@ function DataGrid({
2168
2475
  },
2169
2476
  [selectedCell, rows, columnKeys, onCellClick]
2170
2477
  );
2171
- const handleMouseEnter = (0, import_react8.useCallback)(
2478
+ const handleMouseEnter = (0, import_react9.useCallback)(
2172
2479
  (rowIndex, colIndex) => {
2173
2480
  if (isSelecting) {
2174
2481
  setSelectionEnd({ row: rowIndex, col: colIndex });
@@ -2176,12 +2483,12 @@ function DataGrid({
2176
2483
  },
2177
2484
  [isSelecting]
2178
2485
  );
2179
- (0, import_react8.useEffect)(() => {
2486
+ (0, import_react9.useEffect)(() => {
2180
2487
  const handleMouseUp = () => setIsSelecting(false);
2181
2488
  document.addEventListener("mouseup", handleMouseUp);
2182
2489
  return () => document.removeEventListener("mouseup", handleMouseUp);
2183
2490
  }, []);
2184
- (0, import_react8.useEffect)(() => {
2491
+ (0, import_react9.useEffect)(() => {
2185
2492
  const handleKeydown = (event) => {
2186
2493
  if ((event.ctrlKey || event.metaKey) && event.key === "c" && selectionBounds) {
2187
2494
  event.preventDefault();
@@ -2199,7 +2506,7 @@ function DataGrid({
2199
2506
  document.addEventListener("keydown", handleKeydown);
2200
2507
  return () => document.removeEventListener("keydown", handleKeydown);
2201
2508
  }, [selectionBounds, copySelectionToClipboard]);
2202
- const openFilterDropdown = (0, import_react8.useCallback)(
2509
+ const openFilterDropdown = (0, import_react9.useCallback)(
2203
2510
  (columnId, event) => {
2204
2511
  event.stopPropagation();
2205
2512
  const target = event.currentTarget;
@@ -2228,16 +2535,16 @@ function DataGrid({
2228
2535
  },
2229
2536
  []
2230
2537
  );
2231
- const closeFilterDropdown = (0, import_react8.useCallback)(() => {
2538
+ const closeFilterDropdown = (0, import_react9.useCallback)(() => {
2232
2539
  setActiveFilterColumn(null);
2233
2540
  }, []);
2234
- const handleFilter = (0, import_react8.useCallback)(
2541
+ const handleFilter = (0, import_react9.useCallback)(
2235
2542
  (columnId, values) => {
2236
2543
  setColumnFilter(columnId, values);
2237
2544
  },
2238
2545
  [setColumnFilter]
2239
2546
  );
2240
- const handleSort = (0, import_react8.useCallback)(
2547
+ const handleSort = (0, import_react9.useCallback)(
2241
2548
  (columnId, direction) => {
2242
2549
  if (direction === null) {
2243
2550
  const current = getSortDirection(columnId);
@@ -2261,7 +2568,7 @@ function DataGrid({
2261
2568
  },
2262
2569
  [getSortDirection, toggleSort]
2263
2570
  );
2264
- const isCellSelected = (0, import_react8.useCallback)(
2571
+ const isCellSelected = (0, import_react9.useCallback)(
2265
2572
  (rowIndex, colIndex) => {
2266
2573
  if (!selectionBounds) {
2267
2574
  return selectedCell?.row === rowIndex && selectedCell?.col === colIndex;
@@ -2299,30 +2606,30 @@ function DataGrid({
2299
2606
  }
2300
2607
  return String(value);
2301
2608
  };
2302
- const totalTableWidth = (0, import_react8.useMemo)(() => {
2609
+ const totalTableWidth = (0, import_react9.useMemo)(() => {
2303
2610
  return columnKeys.reduce((sum, key) => sum + (columnWidths[key] || MIN_COL_WIDTH), 0);
2304
2611
  }, [columnKeys, columnWidths]);
2305
2612
  const activeFilterCount = columnFilters.length;
2306
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2613
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2307
2614
  "div",
2308
2615
  {
2309
2616
  className: `vpg-data-grid vpg-font-${currentFontSize} vpg-theme-${currentTheme} ${stripedRows ? "vpg-striped" : ""} ${resizingColumnId ? "vpg-resizing" : ""} ${isResizingVertically ? "vpg-resizing-vertical" : ""}`,
2310
2617
  style: { height: `${gridHeight}px` },
2311
2618
  children: [
2312
- showCopyToast && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-toast", children: [
2313
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
2619
+ showCopyToast && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-toast", children: [
2620
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
2314
2621
  copyToastMessage
2315
2622
  ] }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-toolbar", children: [
2317
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-toolbar-left", children: [
2318
- showPivot && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-view-toggle", children: [
2319
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2623
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-toolbar", children: [
2624
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-toolbar-left", children: [
2625
+ showPivot && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-view-toggle", children: [
2626
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2320
2627
  "button",
2321
2628
  {
2322
2629
  className: `vpg-view-btn ${viewMode === "grid" ? "active" : ""}`,
2323
2630
  onClick: () => setViewMode("grid"),
2324
2631
  children: [
2325
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2632
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2326
2633
  "path",
2327
2634
  {
2328
2635
  strokeLinecap: "round",
@@ -2335,13 +2642,13 @@ function DataGrid({
2335
2642
  ]
2336
2643
  }
2337
2644
  ),
2338
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2645
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2339
2646
  "button",
2340
2647
  {
2341
2648
  className: `vpg-view-btn vpg-pivot-btn ${viewMode === "pivot" ? "active" : ""}`,
2342
2649
  onClick: () => setViewMode("pivot"),
2343
2650
  children: [
2344
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2345
2652
  "path",
2346
2653
  {
2347
2654
  strokeLinecap: "round",
@@ -2355,14 +2662,14 @@ function DataGrid({
2355
2662
  }
2356
2663
  )
2357
2664
  ] }),
2358
- viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2359
- enableSearch && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-search-container", children: !showSearchInput ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2665
+ viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2666
+ enableSearch && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-search-container", children: !showSearchInput ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2360
2667
  "button",
2361
2668
  {
2362
2669
  className: "vpg-icon-btn",
2363
2670
  title: "Search (Ctrl+F)",
2364
2671
  onClick: () => setShowSearchInput(true),
2365
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2672
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2366
2673
  "path",
2367
2674
  {
2368
2675
  strokeLinecap: "round",
@@ -2372,15 +2679,15 @@ function DataGrid({
2372
2679
  }
2373
2680
  ) })
2374
2681
  }
2375
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-search-box", children: [
2376
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2682
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-search-box", children: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2377
2684
  "svg",
2378
2685
  {
2379
2686
  className: "vpg-search-icon",
2380
2687
  fill: "none",
2381
2688
  stroke: "currentColor",
2382
2689
  viewBox: "0 0 24 24",
2383
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2690
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2384
2691
  "path",
2385
2692
  {
2386
2693
  strokeLinecap: "round",
@@ -2391,7 +2698,7 @@ function DataGrid({
2391
2698
  )
2392
2699
  }
2393
2700
  ),
2394
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2701
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2395
2702
  "input",
2396
2703
  {
2397
2704
  type: "text",
@@ -2408,14 +2715,14 @@ function DataGrid({
2408
2715
  autoFocus: true
2409
2716
  }
2410
2717
  ),
2411
- globalSearchTerm && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "vpg-search-clear", onClick: () => setGlobalSearchTerm(""), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2718
+ globalSearchTerm && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "vpg-search-clear", onClick: () => setGlobalSearchTerm(""), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2412
2719
  "svg",
2413
2720
  {
2414
2721
  className: "vpg-icon-xs",
2415
2722
  fill: "none",
2416
2723
  stroke: "currentColor",
2417
2724
  viewBox: "0 0 24 24",
2418
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2725
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2419
2726
  "path",
2420
2727
  {
2421
2728
  strokeLinecap: "round",
@@ -2427,9 +2734,9 @@ function DataGrid({
2427
2734
  }
2428
2735
  ) })
2429
2736
  ] }) }),
2430
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-font-size-control", children: [
2431
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-label", children: "Size:" }),
2432
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-font-size-toggle", children: fontSizeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2737
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-font-size-control", children: [
2738
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-label", children: "Size:" }),
2739
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-font-size-toggle", children: fontSizeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2433
2740
  "button",
2434
2741
  {
2435
2742
  className: `vpg-font-size-btn ${currentFontSize === opt.value ? "active" : ""}`,
@@ -2439,8 +2746,8 @@ function DataGrid({
2439
2746
  opt.value
2440
2747
  )) })
2441
2748
  ] }),
2442
- activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-filter-info", children: [
2443
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2749
+ activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-filter-info", children: [
2750
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2444
2751
  "path",
2445
2752
  {
2446
2753
  fillRule: "evenodd",
@@ -2448,26 +2755,26 @@ function DataGrid({
2448
2755
  clipRule: "evenodd"
2449
2756
  }
2450
2757
  ) }),
2451
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
2758
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
2452
2759
  activeFilterCount,
2453
2760
  " filter",
2454
2761
  activeFilterCount > 1 ? "s" : ""
2455
2762
  ] })
2456
2763
  ] }),
2457
- globalSearchTerm && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-search-info", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
2764
+ globalSearchTerm && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-search-info", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
2458
2765
  totalSearchedRows,
2459
2766
  " match",
2460
2767
  totalSearchedRows !== 1 ? "es" : ""
2461
2768
  ] }) })
2462
2769
  ] }),
2463
- viewMode === "pivot" && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2464
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2770
+ viewMode === "pivot" && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2771
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2465
2772
  "button",
2466
2773
  {
2467
2774
  className: `vpg-config-toggle ${showPivotConfig ? "active" : ""}`,
2468
2775
  onClick: () => setShowPivotConfig(!showPivotConfig),
2469
2776
  children: [
2470
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2777
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2471
2778
  "path",
2472
2779
  {
2473
2780
  strokeLinecap: "round",
@@ -2481,8 +2788,8 @@ function DataGrid({
2481
2788
  ]
2482
2789
  }
2483
2790
  ),
2484
- pivotIsConfigured && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-pivot-status", children: [
2485
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2791
+ pivotIsConfigured && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-pivot-status", children: [
2792
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2486
2793
  "path",
2487
2794
  {
2488
2795
  fillRule: "evenodd",
@@ -2490,13 +2797,13 @@ function DataGrid({
2490
2797
  clipRule: "evenodd"
2491
2798
  }
2492
2799
  ) }),
2493
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Pivot configured" })
2800
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Pivot configured" })
2494
2801
  ] })
2495
2802
  ] })
2496
2803
  ] }),
2497
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-toolbar-right", children: [
2498
- viewMode === "grid" && activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { className: "vpg-clear-filters", onClick: clearAllFilters, children: [
2499
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2804
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-toolbar-right", children: [
2805
+ viewMode === "grid" && activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { className: "vpg-clear-filters", onClick: clearAllFilters, children: [
2806
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2500
2807
  "path",
2501
2808
  {
2502
2809
  strokeLinecap: "round",
@@ -2507,13 +2814,13 @@ function DataGrid({
2507
2814
  ) }),
2508
2815
  "Clear Filters"
2509
2816
  ] }),
2510
- enableClipboard && selectionBounds && viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2817
+ enableClipboard && selectionBounds && viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2511
2818
  "button",
2512
2819
  {
2513
2820
  className: "vpg-icon-btn",
2514
2821
  title: "Copy selection (Ctrl+C)",
2515
2822
  onClick: copySelectionToClipboard,
2516
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2823
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2517
2824
  "path",
2518
2825
  {
2519
2826
  strokeLinecap: "round",
@@ -2524,14 +2831,14 @@ function DataGrid({
2524
2831
  ) })
2525
2832
  }
2526
2833
  ),
2527
- enableExport && (viewMode === "grid" || viewMode === "pivot" && pivotIsConfigured) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2834
+ enableExport && (viewMode === "grid" || viewMode === "pivot" && pivotIsConfigured) && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2528
2835
  "button",
2529
2836
  {
2530
2837
  className: "vpg-export-btn",
2531
2838
  title: viewMode === "pivot" ? "Export Pivot to CSV" : "Export to CSV",
2532
2839
  onClick: handleExport,
2533
2840
  children: [
2534
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2841
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2535
2842
  "path",
2536
2843
  {
2537
2844
  strokeLinecap: "round",
@@ -2547,13 +2854,13 @@ function DataGrid({
2547
2854
  )
2548
2855
  ] })
2549
2856
  ] }),
2550
- viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { ref: tableContainerRef, className: "vpg-grid-container", tabIndex: 0, children: [
2551
- loading && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-loading", children: [
2552
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-spinner" }),
2553
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Loading data..." })
2857
+ viewMode === "grid" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: tableContainerRef, className: "vpg-grid-container", tabIndex: 0, children: [
2858
+ loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-loading", children: [
2859
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-spinner" }),
2860
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Loading data..." })
2554
2861
  ] }),
2555
- !loading && data.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-empty", children: [
2556
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2862
+ !loading && data.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-empty", children: [
2863
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-empty-icon", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2557
2864
  "path",
2558
2865
  {
2559
2866
  strokeLinecap: "round",
@@ -2562,10 +2869,10 @@ function DataGrid({
2562
2869
  d: "M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
2563
2870
  }
2564
2871
  ) }) }),
2565
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "No data available" })
2872
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "No data available" })
2566
2873
  ] }),
2567
- !loading && data.length > 0 && filteredRowCount === 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-empty", children: [
2568
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-empty-icon vpg-warning", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2874
+ !loading && data.length > 0 && filteredRowCount === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-empty", children: [
2875
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-empty-icon vpg-warning", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2569
2876
  "path",
2570
2877
  {
2571
2878
  strokeLinecap: "round",
@@ -2574,11 +2881,11 @@ function DataGrid({
2574
2881
  d: "M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z"
2575
2882
  }
2576
2883
  ) }) }),
2577
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "No matching records" }),
2578
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "vpg-clear-link", onClick: clearAllFilters, children: "Clear all filters" })
2884
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "No matching records" }),
2885
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { className: "vpg-clear-link", onClick: clearAllFilters, children: "Clear all filters" })
2579
2886
  ] }),
2580
- !loading && filteredRowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-table-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "vpg-table", style: { minWidth: `${totalTableWidth}px` }, children: [
2581
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2887
+ !loading && filteredRowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-table-wrapper", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("table", { className: "vpg-table", style: { minWidth: `${totalTableWidth}px` }, children: [
2888
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2582
2889
  "th",
2583
2890
  {
2584
2891
  className: `vpg-header-cell ${hasActiveFilter(colId) ? "vpg-has-filter" : ""} ${getSortDirection(colId) !== null ? "vpg-is-sorted" : ""} ${activeFilterColumn === colId ? "vpg-is-active" : ""}`,
@@ -2593,16 +2900,16 @@ function DataGrid({
2593
2900
  }
2594
2901
  },
2595
2902
  children: [
2596
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-header-content", children: [
2597
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-header-text", children: colId }),
2598
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-header-icons", children: [
2599
- getSortDirection(colId) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-sort-indicator", children: getSortDirection(colId) === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2903
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-header-content", children: [
2904
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-header-text", children: colId }),
2905
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-header-icons", children: [
2906
+ getSortDirection(colId) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-sort-indicator", children: getSortDirection(colId) === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2600
2907
  "svg",
2601
2908
  {
2602
2909
  className: "vpg-icon-sm",
2603
2910
  fill: "currentColor",
2604
2911
  viewBox: "0 0 20 20",
2605
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2912
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2606
2913
  "path",
2607
2914
  {
2608
2915
  fillRule: "evenodd",
@@ -2611,13 +2918,13 @@ function DataGrid({
2611
2918
  }
2612
2919
  )
2613
2920
  }
2614
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2921
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2615
2922
  "svg",
2616
2923
  {
2617
2924
  className: "vpg-icon-sm",
2618
2925
  fill: "currentColor",
2619
2926
  viewBox: "0 0 20 20",
2620
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2927
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2621
2928
  "path",
2622
2929
  {
2623
2930
  fillRule: "evenodd",
@@ -2627,13 +2934,13 @@ function DataGrid({
2627
2934
  )
2628
2935
  }
2629
2936
  ) }),
2630
- hasActiveFilter(colId) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-filter-indicator", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2937
+ hasActiveFilter(colId) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-filter-indicator", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2631
2938
  "svg",
2632
2939
  {
2633
2940
  className: "vpg-icon-xs",
2634
2941
  fill: "currentColor",
2635
2942
  viewBox: "0 0 20 20",
2636
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2943
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2637
2944
  "path",
2638
2945
  {
2639
2946
  fillRule: "evenodd",
@@ -2643,14 +2950,14 @@ function DataGrid({
2643
2950
  )
2644
2951
  }
2645
2952
  ) }),
2646
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-dropdown-arrow", title: "Filter & Sort", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2953
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-dropdown-arrow", title: "Filter & Sort", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2647
2954
  "svg",
2648
2955
  {
2649
2956
  className: "vpg-icon-sm",
2650
2957
  fill: "none",
2651
2958
  stroke: "currentColor",
2652
2959
  viewBox: "0 0 24 24",
2653
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2960
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2654
2961
  "path",
2655
2962
  {
2656
2963
  strokeLinecap: "round",
@@ -2663,7 +2970,7 @@ function DataGrid({
2663
2970
  ) })
2664
2971
  ] })
2665
2972
  ] }),
2666
- enableColumnResize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2973
+ enableColumnResize && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2667
2974
  "div",
2668
2975
  {
2669
2976
  className: "vpg-resize-handle",
@@ -2674,7 +2981,7 @@ function DataGrid({
2674
2981
  },
2675
2982
  colId
2676
2983
  )) }) }),
2677
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { ref: tableBodyRef, children: paginatedRows.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tr", { className: "vpg-row", children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2984
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tbody", { ref: tableBodyRef, children: paginatedRows.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("tr", { className: "vpg-row", children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2678
2985
  "td",
2679
2986
  {
2680
2987
  className: `vpg-cell ${isCellSelected(rowIndex, colIndex) ? "vpg-selected" : ""} ${getColumnStats(colId).type === "number" ? "vpg-is-number" : ""}`,
@@ -2692,8 +2999,8 @@ function DataGrid({
2692
2999
  )) }, row.id)) })
2693
3000
  ] }) })
2694
3001
  ] }),
2695
- viewMode === "pivot" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-pivot-container", children: [
2696
- showPivotConfig && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-pivot-config-panel", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3002
+ viewMode === "pivot" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-pivot-container", children: [
3003
+ showPivotConfig && canUsePivot && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-pivot-config-panel", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2697
3004
  PivotConfig,
2698
3005
  {
2699
3006
  availableFields: pivotAvailableFields,
@@ -2702,6 +3009,7 @@ function DataGrid({
2702
3009
  valueFields: pivotValueFields,
2703
3010
  showRowTotals: pivotShowRowTotals,
2704
3011
  showColumnTotals: pivotShowColumnTotals,
3012
+ calculatedFields: pivotCalculatedFields,
2705
3013
  onShowRowTotalsChange: setPivotShowRowTotals,
2706
3014
  onShowColumnTotalsChange: setPivotShowColumnTotals,
2707
3015
  onClearConfig: clearPivotConfig,
@@ -2714,10 +3022,13 @@ function DataGrid({
2714
3022
  onAddColumnField: addColumnField,
2715
3023
  onRemoveColumnField: removeColumnField,
2716
3024
  onAddValueField: addValueField,
2717
- onRemoveValueField: removeValueField
3025
+ onRemoveValueField: removeValueField,
3026
+ onAddCalculatedField: addCalculatedField,
3027
+ onRemoveCalculatedField: removeCalculatedField,
3028
+ onUpdateCalculatedField: addCalculatedField
2718
3029
  }
2719
3030
  ) }),
2720
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: `vpg-pivot-main ${!showPivotConfig ? "vpg-full-width" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3031
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: `vpg-pivot-main ${!showPivotConfig ? "vpg-full-width" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2721
3032
  PivotSkeleton,
2722
3033
  {
2723
3034
  rowFields: pivotRowFields,
@@ -2742,44 +3053,44 @@ function DataGrid({
2742
3053
  }
2743
3054
  ) })
2744
3055
  ] }),
2745
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-footer", children: [
2746
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-footer-left", children: viewMode === "grid" ? enablePagination ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2747
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3056
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-footer", children: [
3057
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-footer-left", children: viewMode === "grid" ? enablePagination ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3058
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
2748
3059
  ((currentPage - 1) * pageSize + 1).toLocaleString(),
2749
3060
  "-",
2750
3061
  Math.min(currentPage * pageSize, totalSearchedRows).toLocaleString()
2751
3062
  ] }),
2752
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-separator", children: "of" }),
2753
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: totalSearchedRows.toLocaleString() }),
2754
- totalSearchedRows !== totalRowCount && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-filtered-note", children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-separator", children: "of" }),
3064
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: totalSearchedRows.toLocaleString() }),
3065
+ totalSearchedRows !== totalRowCount && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vpg-filtered-note", children: [
2755
3066
  "(",
2756
3067
  totalRowCount.toLocaleString(),
2757
3068
  " total)"
2758
3069
  ] })
2759
- ] }) : filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3070
+ ] }) : filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
2760
3071
  totalRowCount.toLocaleString(),
2761
3072
  " records"
2762
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2763
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-filtered-count", children: totalSearchedRows.toLocaleString() }),
2764
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-separator", children: "of" }),
2765
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: totalRowCount.toLocaleString() }),
2766
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-separator", children: "records" })
2767
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2768
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-pivot-label", children: "Pivot Table" }),
2769
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-separator", children: "\u2022" }),
2770
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3073
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3074
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-filtered-count", children: totalSearchedRows.toLocaleString() }),
3075
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-separator", children: "of" }),
3076
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: totalRowCount.toLocaleString() }),
3077
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-separator", children: "records" })
3078
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3079
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-pivot-label", children: "Pivot Table" }),
3080
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-separator", children: "\u2022" }),
3081
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { children: [
2771
3082
  totalRowCount.toLocaleString(),
2772
3083
  " source records"
2773
3084
  ] })
2774
3085
  ] }) }),
2775
- enablePagination && viewMode === "grid" && totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-pagination", children: [
2776
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3086
+ enablePagination && viewMode === "grid" && totalPages > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-pagination", children: [
3087
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2777
3088
  "button",
2778
3089
  {
2779
3090
  className: "vpg-page-btn",
2780
3091
  disabled: currentPage === 1,
2781
3092
  onClick: () => setCurrentPage(1),
2782
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3093
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2783
3094
  "path",
2784
3095
  {
2785
3096
  strokeLinecap: "round",
@@ -2790,13 +3101,13 @@ function DataGrid({
2790
3101
  ) })
2791
3102
  }
2792
3103
  ),
2793
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3104
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2794
3105
  "button",
2795
3106
  {
2796
3107
  className: "vpg-page-btn",
2797
3108
  disabled: currentPage === 1,
2798
3109
  onClick: () => setCurrentPage((p) => Math.max(1, p - 1)),
2799
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3110
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2800
3111
  "path",
2801
3112
  {
2802
3113
  strokeLinecap: "round",
@@ -2807,19 +3118,19 @@ function DataGrid({
2807
3118
  ) })
2808
3119
  }
2809
3120
  ),
2810
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-page-info", children: [
3121
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vpg-page-info", children: [
2811
3122
  "Page ",
2812
3123
  currentPage,
2813
3124
  " of ",
2814
3125
  totalPages
2815
3126
  ] }),
2816
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3127
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2817
3128
  "button",
2818
3129
  {
2819
3130
  className: "vpg-page-btn",
2820
3131
  disabled: currentPage === totalPages,
2821
3132
  onClick: () => setCurrentPage((p) => Math.min(totalPages, p + 1)),
2822
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3133
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2823
3134
  "path",
2824
3135
  {
2825
3136
  strokeLinecap: "round",
@@ -2830,13 +3141,13 @@ function DataGrid({
2830
3141
  ) })
2831
3142
  }
2832
3143
  ),
2833
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3144
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2834
3145
  "button",
2835
3146
  {
2836
3147
  className: "vpg-page-btn",
2837
3148
  disabled: currentPage === totalPages,
2838
3149
  onClick: () => setCurrentPage(totalPages),
2839
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3150
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2840
3151
  "path",
2841
3152
  {
2842
3153
  strokeLinecap: "round",
@@ -2848,45 +3159,45 @@ function DataGrid({
2848
3159
  }
2849
3160
  )
2850
3161
  ] }),
2851
- viewMode === "grid" && selectionStats && selectionStats.count > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-selection-stats", children: [
2852
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-stat", children: [
2853
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-label", children: "Count:" }),
2854
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-value", children: selectionStats.count })
3162
+ viewMode === "grid" && selectionStats && selectionStats.count > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-selection-stats", children: [
3163
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vpg-stat", children: [
3164
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-label", children: "Count:" }),
3165
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-value", children: selectionStats.count })
2855
3166
  ] }),
2856
- selectionStats.numericCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2857
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-divider", children: "|" }),
2858
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-stat", children: [
2859
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-label", children: "Sum:" }),
2860
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.sum) })
3167
+ selectionStats.numericCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3168
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-divider", children: "|" }),
3169
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vpg-stat", children: [
3170
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-label", children: "Sum:" }),
3171
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.sum) })
2861
3172
  ] }),
2862
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-divider", children: "|" }),
2863
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vpg-stat", children: [
2864
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-label", children: "Avg:" }),
2865
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.avg) })
3173
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-divider", children: "|" }),
3174
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vpg-stat", children: [
3175
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-label", children: "Avg:" }),
3176
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.avg) })
2866
3177
  ] })
2867
3178
  ] })
2868
3179
  ] }),
2869
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-footer-right", children: isDemo ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-demo-banner", children: [
2870
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-demo-badge", children: "DEMO" }),
2871
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "Pro features enabled" }),
2872
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", children: "Get License \u2192" })
2873
- ] }) : showWatermark ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "vpg-watermark-inline", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: [
2874
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2875
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "3", width: "7", height: "7" }),
2876
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "3", width: "7", height: "7" }),
2877
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "14", width: "7", height: "7" }),
2878
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "14", width: "7", height: "7" })
3180
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-footer-right", children: isDemo ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-demo-banner", children: [
3181
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-demo-badge", children: "DEMO" }),
3182
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: "Pro features enabled" }),
3183
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", children: "Get License \u2192" })
3184
+ ] }) : showWatermark ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vpg-watermark-inline", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: [
3185
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3186
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "3", y: "3", width: "7", height: "7" }),
3187
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "14", y: "3", width: "7", height: "7" }),
3188
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "14", y: "14", width: "7", height: "7" }),
3189
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: "3", y: "14", width: "7", height: "7" })
2879
3190
  ] }),
2880
3191
  "Powered by TinyPivot"
2881
3192
  ] }) }) : null })
2882
3193
  ] }),
2883
- enableVerticalResize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vpg-vertical-resize-handle", onMouseDown: startVerticalResize, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vpg-resize-grip", children: [
2884
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", {}),
2885
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", {}),
2886
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", {})
3194
+ enableVerticalResize && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vpg-vertical-resize-handle", onMouseDown: startVerticalResize, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "vpg-resize-grip", children: [
3195
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
3196
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {}),
3197
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", {})
2887
3198
  ] }) }),
2888
- activeFilterColumn && (0, import_react_dom.createPortal)(
2889
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3199
+ activeFilterColumn && (0, import_react_dom2.createPortal)(
3200
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2890
3201
  "div",
2891
3202
  {
2892
3203
  className: "vpg-filter-portal",
@@ -2897,7 +3208,7 @@ function DataGrid({
2897
3208
  maxHeight: `${filterDropdownPosition.maxHeight}px`,
2898
3209
  zIndex: 9999
2899
3210
  },
2900
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3211
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2901
3212
  ColumnFilter,
2902
3213
  {
2903
3214
  columnId: activeFilterColumn,