@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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/components/DataGrid.tsx
2
- import { useState as useState8, useMemo as useMemo8, useCallback as useCallback8, useEffect as useEffect4, useRef as useRef2 } from "react";
3
- import { createPortal } from "react-dom";
2
+ import { useState as useState9, useMemo as useMemo9, useCallback as useCallback9, useEffect as useEffect5, useRef as useRef2 } from "react";
3
+ import { createPortal as createPortal2 } from "react-dom";
4
4
 
5
5
  // src/hooks/useExcelGrid.ts
6
6
  import { useState, useMemo, useCallback, useEffect } from "react";
@@ -189,7 +189,9 @@ import {
189
189
  savePivotConfig,
190
190
  loadPivotConfig,
191
191
  isConfigValidForFields,
192
- getAggregationLabel
192
+ getAggregationLabel,
193
+ loadCalculatedFields,
194
+ saveCalculatedFields
193
195
  } from "@smallwebco/tinypivot-core";
194
196
 
195
197
  // src/hooks/useLicense.ts
@@ -290,6 +292,7 @@ function usePivotTable(data) {
290
292
  const [valueFields, setValueFields] = useState3([]);
291
293
  const [showRowTotals, setShowRowTotals] = useState3(true);
292
294
  const [showColumnTotals, setShowColumnTotals] = useState3(true);
295
+ const [calculatedFields, setCalculatedFields] = useState3(() => loadCalculatedFields());
293
296
  const [currentStorageKey, setCurrentStorageKey] = useState3(null);
294
297
  const availableFields = useMemo3(() => {
295
298
  return computeAvailableFields(data);
@@ -314,9 +317,10 @@ function usePivotTable(data) {
314
317
  columnFields,
315
318
  valueFields,
316
319
  showRowTotals,
317
- showColumnTotals
320
+ showColumnTotals,
321
+ calculatedFields
318
322
  });
319
- }, [data, isConfigured, canUsePivot, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals]);
323
+ }, [data, isConfigured, canUsePivot, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields]);
320
324
  useEffect2(() => {
321
325
  if (data.length === 0) return;
322
326
  const newKeys = Object.keys(data[0]);
@@ -330,6 +334,9 @@ function usePivotTable(data) {
330
334
  setValueFields(savedConfig.valueFields);
331
335
  setShowRowTotals(savedConfig.showRowTotals);
332
336
  setShowColumnTotals(savedConfig.showColumnTotals);
337
+ if (savedConfig.calculatedFields) {
338
+ setCalculatedFields(savedConfig.calculatedFields);
339
+ }
333
340
  } else {
334
341
  const currentConfig = {
335
342
  rowFields,
@@ -353,10 +360,11 @@ function usePivotTable(data) {
353
360
  columnFields,
354
361
  valueFields,
355
362
  showRowTotals,
356
- showColumnTotals
363
+ showColumnTotals,
364
+ calculatedFields
357
365
  };
358
366
  savePivotConfig(currentStorageKey, config);
359
- }, [currentStorageKey, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals]);
367
+ }, [currentStorageKey, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields]);
360
368
  const addRowField = useCallback3(
361
369
  (field) => {
362
370
  if (!requirePro("Pivot Table - Row Fields")) return;
@@ -435,6 +443,27 @@ function usePivotTable(data) {
435
443
  setValueFields([{ field: numericFields[0].field, aggregation: "sum" }]);
436
444
  }
437
445
  }, [availableFields, requirePro]);
446
+ const addCalculatedField = useCallback3((field) => {
447
+ setCalculatedFields((prev) => {
448
+ const existing = prev.findIndex((f) => f.id === field.id);
449
+ let updated;
450
+ if (existing >= 0) {
451
+ updated = [...prev.slice(0, existing), field, ...prev.slice(existing + 1)];
452
+ } else {
453
+ updated = [...prev, field];
454
+ }
455
+ saveCalculatedFields(updated);
456
+ return updated;
457
+ });
458
+ }, []);
459
+ const removeCalculatedField = useCallback3((id) => {
460
+ setCalculatedFields((prev) => {
461
+ const updated = prev.filter((f) => f.id !== id);
462
+ saveCalculatedFields(updated);
463
+ return updated;
464
+ });
465
+ setValueFields((prev) => prev.filter((v) => v.field !== `calc:${id}`));
466
+ }, []);
438
467
  return {
439
468
  // State
440
469
  rowFields,
@@ -442,6 +471,7 @@ function usePivotTable(data) {
442
471
  valueFields,
443
472
  showRowTotals,
444
473
  showColumnTotals,
474
+ calculatedFields,
445
475
  // Computed
446
476
  availableFields,
447
477
  unassignedFields,
@@ -460,7 +490,9 @@ function usePivotTable(data) {
460
490
  setShowColumnTotals,
461
491
  autoSuggestConfig,
462
492
  setRowFields,
463
- setColumnFields
493
+ setColumnFields,
494
+ addCalculatedField,
495
+ removeCalculatedField
464
496
  };
465
497
  }
466
498
 
@@ -937,10 +969,197 @@ function ColumnFilter({
937
969
  }
938
970
 
939
971
  // src/components/PivotConfig.tsx
940
- import { useState as useState6, useMemo as useMemo6, useCallback as useCallback6 } from "react";
972
+ import { useState as useState7, useMemo as useMemo7, useCallback as useCallback7 } from "react";
941
973
  import { AGGREGATION_OPTIONS, getAggregationSymbol } from "@smallwebco/tinypivot-core";
974
+
975
+ // src/components/CalculatedFieldModal.tsx
976
+ import { useState as useState6, useEffect as useEffect4, useMemo as useMemo6, useCallback as useCallback6 } from "react";
977
+ import { createPortal } from "react-dom";
978
+ import { validateSimpleFormula } from "@smallwebco/tinypivot-core";
942
979
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
943
- function getFieldIcon(type) {
980
+ function CalculatedFieldModal({
981
+ show,
982
+ availableFields,
983
+ existingField,
984
+ onClose,
985
+ onSave
986
+ }) {
987
+ const [name, setName] = useState6("");
988
+ const [formula, setFormula] = useState6("");
989
+ const [formatAs, setFormatAs] = useState6("number");
990
+ const [decimals, setDecimals] = useState6(2);
991
+ const [error, setError] = useState6(null);
992
+ useEffect4(() => {
993
+ if (show) {
994
+ if (existingField) {
995
+ setName(existingField.name);
996
+ setFormula(existingField.formula);
997
+ setFormatAs(existingField.formatAs || "number");
998
+ setDecimals(existingField.decimals ?? 2);
999
+ } else {
1000
+ setName("");
1001
+ setFormula("");
1002
+ setFormatAs("number");
1003
+ setDecimals(2);
1004
+ }
1005
+ setError(null);
1006
+ }
1007
+ }, [show, existingField]);
1008
+ const validationError = useMemo6(() => {
1009
+ if (!formula.trim()) return null;
1010
+ return validateSimpleFormula(formula, availableFields);
1011
+ }, [formula, availableFields]);
1012
+ const insertField = useCallback6((field) => {
1013
+ setFormula((prev) => {
1014
+ if (prev.trim() && !prev.endsWith(" ")) {
1015
+ return prev + " " + field;
1016
+ }
1017
+ return prev + field;
1018
+ });
1019
+ }, []);
1020
+ const insertOperator = useCallback6((op) => {
1021
+ setFormula((prev) => {
1022
+ if (prev.trim() && !prev.endsWith(" ")) {
1023
+ return prev + " " + op + " ";
1024
+ }
1025
+ return prev + op + " ";
1026
+ });
1027
+ }, []);
1028
+ const handleSave = useCallback6(() => {
1029
+ if (!name.trim()) {
1030
+ setError("Name is required");
1031
+ return;
1032
+ }
1033
+ const validationResult = validateSimpleFormula(formula, availableFields);
1034
+ if (validationResult) {
1035
+ setError(validationResult);
1036
+ return;
1037
+ }
1038
+ const field = {
1039
+ id: existingField?.id || `calc_${Date.now()}`,
1040
+ name: name.trim(),
1041
+ formula: formula.trim(),
1042
+ formatAs,
1043
+ decimals
1044
+ };
1045
+ onSave(field);
1046
+ onClose();
1047
+ }, [name, formula, formatAs, decimals, existingField, availableFields, onSave, onClose]);
1048
+ const handleOverlayClick = useCallback6((e) => {
1049
+ if (e.target === e.currentTarget) {
1050
+ onClose();
1051
+ }
1052
+ }, [onClose]);
1053
+ if (!show) return null;
1054
+ const modalContent = /* @__PURE__ */ jsx2("div", { className: "vpg-modal-overlay", onClick: handleOverlayClick, children: /* @__PURE__ */ jsxs2("div", { className: "vpg-modal", children: [
1055
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-modal-header", children: [
1056
+ /* @__PURE__ */ jsxs2("h3", { children: [
1057
+ existingField ? "Edit" : "Create",
1058
+ " Calculated Field"
1059
+ ] }),
1060
+ /* @__PURE__ */ jsx2("button", { className: "vpg-modal-close", onClick: onClose, children: "\xD7" })
1061
+ ] }),
1062
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-modal-body", children: [
1063
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group", children: [
1064
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label", children: "Name" }),
1065
+ /* @__PURE__ */ jsx2(
1066
+ "input",
1067
+ {
1068
+ type: "text",
1069
+ className: "vpg-input",
1070
+ placeholder: "e.g., Profit Margin %",
1071
+ value: name,
1072
+ onChange: (e) => setName(e.target.value)
1073
+ }
1074
+ )
1075
+ ] }),
1076
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group", children: [
1077
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label", children: "Formula" }),
1078
+ /* @__PURE__ */ jsx2(
1079
+ "textarea",
1080
+ {
1081
+ className: "vpg-textarea",
1082
+ placeholder: "e.g., revenue / units",
1083
+ rows: 2,
1084
+ value: formula,
1085
+ onChange: (e) => setFormula(e.target.value)
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsx2("div", { className: "vpg-formula-hint", children: "Use field names with math operators: + - * / ( )" }),
1089
+ validationError && /* @__PURE__ */ jsx2("div", { className: "vpg-error", children: validationError })
1090
+ ] }),
1091
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group", children: [
1092
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label-small", children: "Operators" }),
1093
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-button-group", children: [
1094
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("+"), children: "+" }),
1095
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("-"), children: "\u2212" }),
1096
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("*"), children: "\xD7" }),
1097
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("/"), children: "\xF7" }),
1098
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator("("), children: "(" }),
1099
+ /* @__PURE__ */ jsx2("button", { className: "vpg-insert-btn vpg-op-btn", onClick: () => insertOperator(")"), children: ")" })
1100
+ ] })
1101
+ ] }),
1102
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group", children: [
1103
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label-small", children: "Insert Field" }),
1104
+ availableFields.length > 0 ? /* @__PURE__ */ jsx2("div", { className: "vpg-button-group vpg-field-buttons", children: availableFields.map((field) => /* @__PURE__ */ jsx2(
1105
+ "button",
1106
+ {
1107
+ className: "vpg-insert-btn vpg-field-btn",
1108
+ onClick: () => insertField(field),
1109
+ children: field
1110
+ },
1111
+ field
1112
+ )) }) : /* @__PURE__ */ jsx2("div", { className: "vpg-no-fields", children: "No numeric fields available" })
1113
+ ] }),
1114
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-row", children: [
1115
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group vpg-form-group-half", children: [
1116
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label", children: "Format As" }),
1117
+ /* @__PURE__ */ jsxs2(
1118
+ "select",
1119
+ {
1120
+ className: "vpg-select",
1121
+ value: formatAs,
1122
+ onChange: (e) => setFormatAs(e.target.value),
1123
+ children: [
1124
+ /* @__PURE__ */ jsx2("option", { value: "number", children: "Number" }),
1125
+ /* @__PURE__ */ jsx2("option", { value: "percent", children: "Percentage" }),
1126
+ /* @__PURE__ */ jsx2("option", { value: "currency", children: "Currency ($)" })
1127
+ ]
1128
+ }
1129
+ )
1130
+ ] }),
1131
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-form-group vpg-form-group-half", children: [
1132
+ /* @__PURE__ */ jsx2("label", { className: "vpg-label", children: "Decimals" }),
1133
+ /* @__PURE__ */ jsx2(
1134
+ "input",
1135
+ {
1136
+ type: "number",
1137
+ className: "vpg-input",
1138
+ min: 0,
1139
+ max: 6,
1140
+ value: decimals,
1141
+ onChange: (e) => setDecimals(Number(e.target.value))
1142
+ }
1143
+ )
1144
+ ] })
1145
+ ] }),
1146
+ error && /* @__PURE__ */ jsx2("div", { className: "vpg-error vpg-error-box", children: error })
1147
+ ] }),
1148
+ /* @__PURE__ */ jsxs2("div", { className: "vpg-modal-footer", children: [
1149
+ /* @__PURE__ */ jsx2("button", { className: "vpg-btn vpg-btn-secondary", onClick: onClose, children: "Cancel" }),
1150
+ /* @__PURE__ */ jsxs2("button", { className: "vpg-btn vpg-btn-primary", onClick: handleSave, children: [
1151
+ existingField ? "Update" : "Add",
1152
+ " Field"
1153
+ ] })
1154
+ ] })
1155
+ ] }) });
1156
+ return createPortal(modalContent, document.body);
1157
+ }
1158
+
1159
+ // src/components/PivotConfig.tsx
1160
+ import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1161
+ function getFieldIcon(type, isCalculated) {
1162
+ if (isCalculated) return "\u0192";
944
1163
  switch (type) {
945
1164
  case "number":
946
1165
  return "#";
@@ -958,7 +1177,9 @@ function PivotConfig({
958
1177
  columnFields,
959
1178
  valueFields,
960
1179
  showRowTotals,
1180
+ calculatedFields,
961
1181
  onShowRowTotalsChange,
1182
+ onShowColumnTotalsChange,
962
1183
  onClearConfig,
963
1184
  onAutoSuggest,
964
1185
  onDragStart,
@@ -968,35 +1189,70 @@ function PivotConfig({
968
1189
  onRemoveColumnField,
969
1190
  onRemoveValueField,
970
1191
  onAddRowField,
971
- onAddColumnField
1192
+ onAddColumnField,
1193
+ onAddCalculatedField,
1194
+ onRemoveCalculatedField,
1195
+ onUpdateCalculatedField
972
1196
  }) {
973
- const { showWatermark } = useLicense();
974
- const [fieldSearch, setFieldSearch] = useState6("");
975
- const assignedFields = useMemo6(() => {
1197
+ const [fieldSearch, setFieldSearch] = useState7("");
1198
+ const [showCalcModal, setShowCalcModal] = useState7(false);
1199
+ const [editingCalcField, setEditingCalcField] = useState7(null);
1200
+ const numericFieldNames = useMemo7(
1201
+ () => availableFields.filter((f) => f.isNumeric).map((f) => f.field),
1202
+ [availableFields]
1203
+ );
1204
+ const calculatedFieldsAsStats = useMemo7(() => {
1205
+ if (!calculatedFields) return [];
1206
+ return calculatedFields.map((calc) => ({
1207
+ field: `calc:${calc.id}`,
1208
+ type: "number",
1209
+ uniqueCount: 0,
1210
+ isNumeric: true,
1211
+ isCalculated: true,
1212
+ calcId: calc.id,
1213
+ calcName: calc.name,
1214
+ calcFormula: calc.formula
1215
+ }));
1216
+ }, [calculatedFields]);
1217
+ const allAvailableFields = useMemo7(() => [
1218
+ ...availableFields.map((f) => ({ ...f, isCalculated: false })),
1219
+ ...calculatedFieldsAsStats
1220
+ ], [availableFields, calculatedFieldsAsStats]);
1221
+ const assignedFields = useMemo7(() => {
976
1222
  const rowSet = new Set(rowFields);
977
1223
  const colSet = new Set(columnFields);
978
1224
  const valueMap = new Map(valueFields.map((v) => [v.field, v]));
979
- return availableFields.filter((f) => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field)).map((f) => ({
1225
+ return allAvailableFields.filter((f) => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field)).map((f) => ({
980
1226
  ...f,
981
1227
  assignedTo: rowSet.has(f.field) ? "row" : colSet.has(f.field) ? "column" : "value",
982
1228
  valueConfig: valueMap.get(f.field)
983
1229
  }));
984
- }, [availableFields, rowFields, columnFields, valueFields]);
985
- const unassignedFields = useMemo6(() => {
1230
+ }, [allAvailableFields, rowFields, columnFields, valueFields]);
1231
+ const unassignedFields = useMemo7(() => {
986
1232
  const rowSet = new Set(rowFields);
987
1233
  const colSet = new Set(columnFields);
988
1234
  const valSet = new Set(valueFields.map((v) => v.field));
989
- return availableFields.filter(
1235
+ return allAvailableFields.filter(
990
1236
  (f) => !rowSet.has(f.field) && !colSet.has(f.field) && !valSet.has(f.field)
991
1237
  );
992
- }, [availableFields, rowFields, columnFields, valueFields]);
993
- const filteredUnassignedFields = useMemo6(() => {
1238
+ }, [allAvailableFields, rowFields, columnFields, valueFields]);
1239
+ const filteredUnassignedFields = useMemo7(() => {
994
1240
  if (!fieldSearch.trim()) return unassignedFields;
995
1241
  const search = fieldSearch.toLowerCase().trim();
996
- return unassignedFields.filter((f) => f.field.toLowerCase().includes(search));
1242
+ return unassignedFields.filter((f) => {
1243
+ const fieldName = f.field.toLowerCase();
1244
+ const displayName = f.isCalculated && f.calcName ? f.calcName.toLowerCase() : "";
1245
+ return fieldName.includes(search) || displayName.includes(search);
1246
+ });
997
1247
  }, [unassignedFields, fieldSearch]);
998
1248
  const assignedCount = assignedFields.length;
999
- const handleDragStart = useCallback6(
1249
+ const getFieldDisplayName = useCallback7((field) => {
1250
+ if (field.isCalculated && field.calcName) {
1251
+ return field.calcName;
1252
+ }
1253
+ return field.field;
1254
+ }, []);
1255
+ const handleDragStart = useCallback7(
1000
1256
  (field, event) => {
1001
1257
  event.dataTransfer?.setData("text/plain", field);
1002
1258
  event.dataTransfer.effectAllowed = "move";
@@ -1004,13 +1260,13 @@ function PivotConfig({
1004
1260
  },
1005
1261
  [onDragStart]
1006
1262
  );
1007
- const handleAggregationChange = useCallback6(
1263
+ const handleAggregationChange = useCallback7(
1008
1264
  (field, currentAgg, newAgg) => {
1009
1265
  onUpdateAggregation(field, currentAgg, newAgg);
1010
1266
  },
1011
1267
  [onUpdateAggregation]
1012
1268
  );
1013
- const toggleRowColumn = useCallback6(
1269
+ const toggleRowColumn = useCallback7(
1014
1270
  (field, currentAssignment) => {
1015
1271
  if (currentAssignment === "row") {
1016
1272
  onRemoveRowField(field);
@@ -1022,7 +1278,7 @@ function PivotConfig({
1022
1278
  },
1023
1279
  [onRemoveRowField, onAddColumnField, onRemoveColumnField, onAddRowField]
1024
1280
  );
1025
- const removeField = useCallback6(
1281
+ const removeField = useCallback7(
1026
1282
  (field, assignedTo, valueConfig) => {
1027
1283
  if (assignedTo === "row") {
1028
1284
  onRemoveRowField(field);
@@ -1034,10 +1290,31 @@ function PivotConfig({
1034
1290
  },
1035
1291
  [onRemoveRowField, onRemoveColumnField, onRemoveValueField]
1036
1292
  );
1037
- return /* @__PURE__ */ jsxs2("div", { className: "vpg-pivot-config", children: [
1038
- /* @__PURE__ */ jsxs2("div", { className: "vpg-config-header", children: [
1039
- /* @__PURE__ */ jsxs2("h3", { className: "vpg-config-title", children: [
1040
- /* @__PURE__ */ jsx2("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
1293
+ const handleTotalsToggle = useCallback7((checked) => {
1294
+ onShowRowTotalsChange(checked);
1295
+ onShowColumnTotalsChange(checked);
1296
+ }, [onShowRowTotalsChange, onShowColumnTotalsChange]);
1297
+ const openCalcModal = useCallback7((field) => {
1298
+ setEditingCalcField(field || null);
1299
+ setShowCalcModal(true);
1300
+ }, []);
1301
+ const handleSaveCalcField = useCallback7((field) => {
1302
+ if (editingCalcField && onUpdateCalculatedField) {
1303
+ onUpdateCalculatedField(field);
1304
+ } else if (onAddCalculatedField) {
1305
+ onAddCalculatedField(field);
1306
+ }
1307
+ setShowCalcModal(false);
1308
+ setEditingCalcField(null);
1309
+ }, [editingCalcField, onAddCalculatedField, onUpdateCalculatedField]);
1310
+ const handleCloseCalcModal = useCallback7(() => {
1311
+ setShowCalcModal(false);
1312
+ setEditingCalcField(null);
1313
+ }, []);
1314
+ return /* @__PURE__ */ jsxs3("div", { className: "vpg-pivot-config", children: [
1315
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-config-header", children: [
1316
+ /* @__PURE__ */ jsxs3("h3", { className: "vpg-config-title", children: [
1317
+ /* @__PURE__ */ jsx3("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3(
1041
1318
  "path",
1042
1319
  {
1043
1320
  strokeLinecap: "round",
@@ -1048,13 +1325,13 @@ function PivotConfig({
1048
1325
  ) }),
1049
1326
  "Fields"
1050
1327
  ] }),
1051
- /* @__PURE__ */ jsx2("div", { className: "vpg-header-actions", children: assignedCount > 0 && /* @__PURE__ */ jsx2(
1328
+ /* @__PURE__ */ jsx3("div", { className: "vpg-header-actions", children: assignedCount > 0 && /* @__PURE__ */ jsx3(
1052
1329
  "button",
1053
1330
  {
1054
1331
  className: "vpg-action-btn vpg-clear-btn",
1055
1332
  title: "Clear all",
1056
1333
  onClick: onClearConfig,
1057
- children: /* @__PURE__ */ jsx2("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
1334
+ children: /* @__PURE__ */ jsx3("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3(
1058
1335
  "path",
1059
1336
  {
1060
1337
  strokeLinecap: "round",
@@ -1066,23 +1343,23 @@ function PivotConfig({
1066
1343
  }
1067
1344
  ) })
1068
1345
  ] }),
1069
- assignedCount > 0 && /* @__PURE__ */ jsxs2("div", { className: "vpg-assigned-section", children: [
1070
- /* @__PURE__ */ jsx2("div", { className: "vpg-section-label", children: "Active" }),
1071
- /* @__PURE__ */ jsx2("div", { className: "vpg-assigned-list", children: assignedFields.map((field) => /* @__PURE__ */ jsxs2(
1346
+ assignedCount > 0 && /* @__PURE__ */ jsxs3("div", { className: "vpg-assigned-section", children: [
1347
+ /* @__PURE__ */ jsx3("div", { className: "vpg-section-label", children: "Active" }),
1348
+ /* @__PURE__ */ jsx3("div", { className: "vpg-assigned-list", children: assignedFields.map((field) => /* @__PURE__ */ jsxs3(
1072
1349
  "div",
1073
1350
  {
1074
- className: `vpg-assigned-item vpg-type-${field.assignedTo}`,
1075
- title: field.field,
1351
+ className: `vpg-assigned-item vpg-type-${field.assignedTo}${field.isCalculated ? " vpg-type-calc" : ""}`,
1352
+ title: field.isCalculated ? field.calcFormula : field.field,
1076
1353
  draggable: true,
1077
1354
  onDragStart: (e) => handleDragStart(field.field, e),
1078
1355
  onDragEnd,
1079
1356
  children: [
1080
- /* @__PURE__ */ jsxs2("div", { className: "vpg-item-main", children: [
1081
- /* @__PURE__ */ jsx2("span", { className: `vpg-item-badge ${field.assignedTo}`, children: field.assignedTo === "row" ? "R" : field.assignedTo === "column" ? "C" : getAggregationSymbol(field.valueConfig?.aggregation || "sum") }),
1082
- /* @__PURE__ */ jsx2("span", { className: "vpg-item-name", children: field.field })
1357
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-item-main", children: [
1358
+ /* @__PURE__ */ jsx3("span", { className: `vpg-item-badge ${field.assignedTo}${field.isCalculated ? " calc" : ""}`, children: field.isCalculated ? "\u0192" : field.assignedTo === "row" ? "R" : field.assignedTo === "column" ? "C" : getAggregationSymbol(field.valueConfig?.aggregation || "sum") }),
1359
+ /* @__PURE__ */ jsx3("span", { className: "vpg-item-name", children: getFieldDisplayName(field) })
1083
1360
  ] }),
1084
- /* @__PURE__ */ jsxs2("div", { className: "vpg-item-actions", children: [
1085
- (field.assignedTo === "row" || field.assignedTo === "column") && /* @__PURE__ */ jsx2(
1361
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-item-actions", children: [
1362
+ (field.assignedTo === "row" || field.assignedTo === "column") && /* @__PURE__ */ jsx3(
1086
1363
  "button",
1087
1364
  {
1088
1365
  className: "vpg-toggle-btn",
@@ -1091,14 +1368,14 @@ function PivotConfig({
1091
1368
  e.stopPropagation();
1092
1369
  toggleRowColumn(field.field, field.assignedTo);
1093
1370
  },
1094
- children: /* @__PURE__ */ jsx2(
1371
+ children: /* @__PURE__ */ jsx3(
1095
1372
  "svg",
1096
1373
  {
1097
1374
  className: "vpg-icon-xs",
1098
1375
  fill: "none",
1099
1376
  stroke: "currentColor",
1100
1377
  viewBox: "0 0 24 24",
1101
- children: /* @__PURE__ */ jsx2(
1378
+ children: /* @__PURE__ */ jsx3(
1102
1379
  "path",
1103
1380
  {
1104
1381
  strokeLinecap: "round",
@@ -1111,7 +1388,7 @@ function PivotConfig({
1111
1388
  )
1112
1389
  }
1113
1390
  ),
1114
- field.assignedTo === "value" && field.valueConfig && /* @__PURE__ */ jsx2(
1391
+ field.assignedTo === "value" && field.valueConfig && /* @__PURE__ */ jsx3(
1115
1392
  "select",
1116
1393
  {
1117
1394
  className: "vpg-agg-select",
@@ -1125,14 +1402,14 @@ function PivotConfig({
1125
1402
  );
1126
1403
  },
1127
1404
  onClick: (e) => e.stopPropagation(),
1128
- children: AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ jsxs2("option", { value: agg.value, children: [
1405
+ children: AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ jsxs3("option", { value: agg.value, children: [
1129
1406
  agg.symbol,
1130
1407
  " ",
1131
1408
  agg.label
1132
1409
  ] }, agg.value))
1133
1410
  }
1134
1411
  ),
1135
- /* @__PURE__ */ jsx2(
1412
+ /* @__PURE__ */ jsx3(
1136
1413
  "button",
1137
1414
  {
1138
1415
  className: "vpg-remove-btn",
@@ -1150,13 +1427,13 @@ function PivotConfig({
1150
1427
  field.field
1151
1428
  )) })
1152
1429
  ] }),
1153
- /* @__PURE__ */ jsxs2("div", { className: "vpg-unassigned-section", children: [
1154
- /* @__PURE__ */ jsx2("div", { className: "vpg-section-header", children: /* @__PURE__ */ jsxs2("div", { className: "vpg-section-label", children: [
1430
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-unassigned-section", children: [
1431
+ /* @__PURE__ */ jsx3("div", { className: "vpg-section-header", children: /* @__PURE__ */ jsxs3("div", { className: "vpg-section-label", children: [
1155
1432
  "Available ",
1156
- /* @__PURE__ */ jsx2("span", { className: "vpg-count", children: unassignedFields.length })
1433
+ /* @__PURE__ */ jsx3("span", { className: "vpg-count", children: unassignedFields.length })
1157
1434
  ] }) }),
1158
- /* @__PURE__ */ jsxs2("div", { className: "vpg-field-search", children: [
1159
- /* @__PURE__ */ jsx2("svg", { className: "vpg-search-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
1435
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-field-search", children: [
1436
+ /* @__PURE__ */ jsx3("svg", { className: "vpg-search-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3(
1160
1437
  "path",
1161
1438
  {
1162
1439
  strokeLinecap: "round",
@@ -1165,7 +1442,7 @@ function PivotConfig({
1165
1442
  d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
1166
1443
  }
1167
1444
  ) }),
1168
- /* @__PURE__ */ jsx2(
1445
+ /* @__PURE__ */ jsx3(
1169
1446
  "input",
1170
1447
  {
1171
1448
  type: "text",
@@ -1175,7 +1452,7 @@ function PivotConfig({
1175
1452
  className: "vpg-search-input"
1176
1453
  }
1177
1454
  ),
1178
- fieldSearch && /* @__PURE__ */ jsx2("button", { className: "vpg-clear-search", onClick: () => setFieldSearch(""), children: /* @__PURE__ */ jsx2("svg", { className: "vpg-icon-xs", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
1455
+ fieldSearch && /* @__PURE__ */ jsx3("button", { className: "vpg-clear-search", onClick: () => setFieldSearch(""), children: /* @__PURE__ */ jsx3("svg", { className: "vpg-icon-xs", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3(
1179
1456
  "path",
1180
1457
  {
1181
1458
  strokeLinecap: "round",
@@ -1185,64 +1462,93 @@ function PivotConfig({
1185
1462
  }
1186
1463
  ) }) })
1187
1464
  ] }),
1188
- /* @__PURE__ */ jsxs2("div", { className: "vpg-field-list", children: [
1189
- filteredUnassignedFields.map((field) => /* @__PURE__ */ jsxs2(
1465
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-field-list", children: [
1466
+ filteredUnassignedFields.map((field) => /* @__PURE__ */ jsxs3(
1190
1467
  "div",
1191
1468
  {
1192
- className: `vpg-field-item ${field.isNumeric ? "vpg-is-numeric" : ""}`,
1193
- title: field.field,
1469
+ className: `vpg-field-item${field.isNumeric && !field.isCalculated ? " vpg-is-numeric" : ""}${field.isCalculated ? " vpg-is-calculated" : ""}`,
1470
+ title: field.isCalculated ? field.calcFormula : field.field,
1194
1471
  draggable: true,
1195
1472
  onDragStart: (e) => handleDragStart(field.field, e),
1196
1473
  onDragEnd,
1197
1474
  children: [
1198
- /* @__PURE__ */ jsx2("span", { className: "vpg-field-type-icon", title: field.type, children: getFieldIcon(field.type) }),
1199
- /* @__PURE__ */ jsx2("span", { className: "vpg-field-name", children: field.field }),
1200
- /* @__PURE__ */ jsx2("span", { className: "vpg-unique-count", children: field.uniqueCount })
1475
+ /* @__PURE__ */ jsx3("span", { className: `vpg-field-type-icon${field.isCalculated ? " vpg-calc-type" : ""}`, title: field.type, children: getFieldIcon(field.type, field.isCalculated) }),
1476
+ /* @__PURE__ */ jsx3("span", { className: "vpg-field-name", children: getFieldDisplayName(field) }),
1477
+ field.isCalculated ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1478
+ /* @__PURE__ */ jsx3(
1479
+ "button",
1480
+ {
1481
+ className: "vpg-field-edit",
1482
+ title: "Edit calculated field",
1483
+ onClick: (e) => {
1484
+ e.stopPropagation();
1485
+ const calcField = calculatedFields?.find((c) => c.id === field.calcId);
1486
+ if (calcField) openCalcModal(calcField);
1487
+ },
1488
+ children: "\u270E"
1489
+ }
1490
+ ),
1491
+ /* @__PURE__ */ jsx3(
1492
+ "button",
1493
+ {
1494
+ className: "vpg-field-delete",
1495
+ title: "Delete calculated field",
1496
+ onClick: (e) => {
1497
+ e.stopPropagation();
1498
+ if (field.calcId && onRemoveCalculatedField) {
1499
+ onRemoveCalculatedField(field.calcId);
1500
+ }
1501
+ },
1502
+ children: "\xD7"
1503
+ }
1504
+ )
1505
+ ] }) : /* @__PURE__ */ jsx3("span", { className: "vpg-unique-count", children: field.uniqueCount })
1201
1506
  ]
1202
1507
  },
1203
1508
  field.field
1204
1509
  )),
1205
- filteredUnassignedFields.length === 0 && fieldSearch && /* @__PURE__ */ jsxs2("div", { className: "vpg-empty-hint", children: [
1510
+ filteredUnassignedFields.length === 0 && fieldSearch && /* @__PURE__ */ jsxs3("div", { className: "vpg-empty-hint", children: [
1206
1511
  'No fields match "',
1207
1512
  fieldSearch,
1208
1513
  '"'
1209
1514
  ] }),
1210
- unassignedFields.length === 0 && /* @__PURE__ */ jsx2("div", { className: "vpg-empty-hint", children: "All fields assigned" })
1515
+ unassignedFields.length === 0 && /* @__PURE__ */ jsx3("div", { className: "vpg-empty-hint", children: "All fields assigned" })
1211
1516
  ] })
1212
1517
  ] }),
1213
- /* @__PURE__ */ jsxs2("div", { className: "vpg-options-section", children: [
1214
- /* @__PURE__ */ jsxs2("label", { className: "vpg-option-toggle", children: [
1215
- /* @__PURE__ */ jsx2(
1518
+ /* @__PURE__ */ jsxs3("div", { className: "vpg-options-section", children: [
1519
+ /* @__PURE__ */ jsxs3("label", { className: "vpg-option-toggle", children: [
1520
+ /* @__PURE__ */ jsx3(
1216
1521
  "input",
1217
1522
  {
1218
1523
  type: "checkbox",
1219
1524
  checked: showRowTotals,
1220
- onChange: (e) => onShowRowTotalsChange(e.target.checked)
1525
+ onChange: (e) => handleTotalsToggle(e.target.checked)
1221
1526
  }
1222
1527
  ),
1223
- /* @__PURE__ */ jsx2("span", { children: "Totals" })
1528
+ /* @__PURE__ */ jsx3("span", { children: "Totals" })
1224
1529
  ] }),
1225
- /* @__PURE__ */ jsxs2("button", { className: "vpg-auto-btn", onClick: onAutoSuggest, children: [
1226
- /* @__PURE__ */ jsx2("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
1227
- "path",
1228
- {
1229
- strokeLinecap: "round",
1230
- strokeLinejoin: "round",
1231
- strokeWidth: 2,
1232
- d: "M13 10V3L4 14h7v7l9-11h-7z"
1233
- }
1234
- ) }),
1235
- "Auto"
1530
+ /* @__PURE__ */ jsxs3("button", { className: "vpg-calc-btn", onClick: () => openCalcModal(), title: "Add calculated field (e.g. Profit Margin %)", children: [
1531
+ /* @__PURE__ */ jsx3("span", { className: "vpg-calc-icon", children: "\u0192" }),
1532
+ /* @__PURE__ */ jsx3("span", { children: "+ Calc" })
1236
1533
  ] })
1237
1534
  ] }),
1238
- showWatermark && /* @__PURE__ */ jsx2("div", { className: "vpg-watermark", children: /* @__PURE__ */ jsx2("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "TinyPivot" }) })
1535
+ /* @__PURE__ */ jsx3(
1536
+ CalculatedFieldModal,
1537
+ {
1538
+ show: showCalcModal,
1539
+ availableFields: numericFieldNames,
1540
+ existingField: editingCalcField,
1541
+ onClose: handleCloseCalcModal,
1542
+ onSave: handleSaveCalcField
1543
+ }
1544
+ )
1239
1545
  ] });
1240
1546
  }
1241
1547
 
1242
1548
  // src/components/PivotSkeleton.tsx
1243
- import { useState as useState7, useMemo as useMemo7, useCallback as useCallback7 } from "react";
1549
+ import { useState as useState8, useMemo as useMemo8, useCallback as useCallback8 } from "react";
1244
1550
  import { getAggregationLabel as getAggregationLabel2, getAggregationSymbol as getAggregationSymbol2 } from "@smallwebco/tinypivot-core";
1245
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1551
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1246
1552
  function PivotSkeleton({
1247
1553
  rowFields,
1248
1554
  columnFields,
@@ -1264,12 +1570,12 @@ function PivotSkeleton({
1264
1570
  onReorderColumnFields
1265
1571
  }) {
1266
1572
  const { showWatermark, canUsePivot, isDemo } = useLicense();
1267
- const [dragOverArea, setDragOverArea] = useState7(null);
1268
- const [reorderDragSource, setReorderDragSource] = useState7(null);
1269
- const [reorderDropTarget, setReorderDropTarget] = useState7(null);
1270
- const [sortDirection, setSortDirection] = useState7("asc");
1271
- const [sortTarget, setSortTarget] = useState7("row");
1272
- const toggleSort = useCallback7((target = "row") => {
1573
+ const [dragOverArea, setDragOverArea] = useState8(null);
1574
+ const [reorderDragSource, setReorderDragSource] = useState8(null);
1575
+ const [reorderDropTarget, setReorderDropTarget] = useState8(null);
1576
+ const [sortDirection, setSortDirection] = useState8("asc");
1577
+ const [sortTarget, setSortTarget] = useState8("row");
1578
+ const toggleSort = useCallback8((target = "row") => {
1273
1579
  if (sortTarget === target) {
1274
1580
  setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
1275
1581
  } else {
@@ -1277,7 +1583,7 @@ function PivotSkeleton({
1277
1583
  setSortDirection("asc");
1278
1584
  }
1279
1585
  }, [sortTarget]);
1280
- const sortedRowIndices = useMemo7(() => {
1586
+ const sortedRowIndices = useMemo8(() => {
1281
1587
  if (!pivotResult) return [];
1282
1588
  const indices = pivotResult.rowHeaders.map((_, i) => i);
1283
1589
  const headers = pivotResult.rowHeaders;
@@ -1301,7 +1607,7 @@ function PivotSkeleton({
1301
1607
  });
1302
1608
  return indices;
1303
1609
  }, [pivotResult, sortTarget, sortDirection]);
1304
- const columnHeaderCells = useMemo7(() => {
1610
+ const columnHeaderCells = useMemo8(() => {
1305
1611
  if (!pivotResult || pivotResult.headers.length === 0) {
1306
1612
  return [
1307
1613
  valueFields.map((vf) => ({
@@ -1329,12 +1635,12 @@ function PivotSkeleton({
1329
1635
  return result;
1330
1636
  }, [pivotResult, valueFields]);
1331
1637
  const hasActiveFilters = activeFilters && activeFilters.length > 0;
1332
- const filterSummary = useMemo7(() => {
1638
+ const filterSummary = useMemo8(() => {
1333
1639
  if (!activeFilters || activeFilters.length === 0) return "";
1334
1640
  return activeFilters.map((f) => f.column).join(", ");
1335
1641
  }, [activeFilters]);
1336
- const [showFilterTooltip, setShowFilterTooltip] = useState7(false);
1337
- const filterTooltipDetails = useMemo7(() => {
1642
+ const [showFilterTooltip, setShowFilterTooltip] = useState8(false);
1643
+ const filterTooltipDetails = useMemo8(() => {
1338
1644
  if (!activeFilters || activeFilters.length === 0) return [];
1339
1645
  return activeFilters.map((f) => {
1340
1646
  const maxDisplay = 5;
@@ -1347,7 +1653,7 @@ function PivotSkeleton({
1347
1653
  };
1348
1654
  });
1349
1655
  }, [activeFilters]);
1350
- const handleDragOver = useCallback7(
1656
+ const handleDragOver = useCallback8(
1351
1657
  (area, event) => {
1352
1658
  event.preventDefault();
1353
1659
  event.dataTransfer.dropEffect = "move";
@@ -1355,10 +1661,10 @@ function PivotSkeleton({
1355
1661
  },
1356
1662
  []
1357
1663
  );
1358
- const handleDragLeave = useCallback7(() => {
1664
+ const handleDragLeave = useCallback8(() => {
1359
1665
  setDragOverArea(null);
1360
1666
  }, []);
1361
- const handleDrop = useCallback7(
1667
+ const handleDrop = useCallback8(
1362
1668
  (area, event) => {
1363
1669
  event.preventDefault();
1364
1670
  const field = event.dataTransfer?.getData("text/plain");
@@ -1385,7 +1691,7 @@ function PivotSkeleton({
1385
1691
  },
1386
1692
  [rowFields, columnFields, valueFields, onAddRowField, onRemoveRowField, onAddColumnField, onRemoveColumnField, onAddValueField, onRemoveValueField]
1387
1693
  );
1388
- const handleChipDragStart = useCallback7(
1694
+ const handleChipDragStart = useCallback8(
1389
1695
  (zone, index, event) => {
1390
1696
  setReorderDragSource({ zone, index });
1391
1697
  event.dataTransfer.effectAllowed = "move";
@@ -1396,11 +1702,11 @@ function PivotSkeleton({
1396
1702
  },
1397
1703
  []
1398
1704
  );
1399
- const handleChipDragEnd = useCallback7(() => {
1705
+ const handleChipDragEnd = useCallback8(() => {
1400
1706
  setReorderDragSource(null);
1401
1707
  setReorderDropTarget(null);
1402
1708
  }, []);
1403
- const handleChipDragOver = useCallback7(
1709
+ const handleChipDragOver = useCallback8(
1404
1710
  (zone, index, event) => {
1405
1711
  event.preventDefault();
1406
1712
  if (reorderDragSource && reorderDragSource.zone === zone) {
@@ -1410,10 +1716,10 @@ function PivotSkeleton({
1410
1716
  },
1411
1717
  [reorderDragSource]
1412
1718
  );
1413
- const handleChipDragLeave = useCallback7(() => {
1719
+ const handleChipDragLeave = useCallback8(() => {
1414
1720
  setReorderDropTarget(null);
1415
1721
  }, []);
1416
- const handleChipDrop = useCallback7(
1722
+ const handleChipDrop = useCallback8(
1417
1723
  (zone, targetIndex, event) => {
1418
1724
  event.preventDefault();
1419
1725
  event.stopPropagation();
@@ -1439,27 +1745,27 @@ function PivotSkeleton({
1439
1745
  },
1440
1746
  [reorderDragSource, rowFields, columnFields, onReorderRowFields, onReorderColumnFields]
1441
1747
  );
1442
- const isChipDragSource = useCallback7(
1748
+ const isChipDragSource = useCallback8(
1443
1749
  (zone, index) => {
1444
1750
  return reorderDragSource?.zone === zone && reorderDragSource?.index === index;
1445
1751
  },
1446
1752
  [reorderDragSource]
1447
1753
  );
1448
- const isChipDropTarget = useCallback7(
1754
+ const isChipDropTarget = useCallback8(
1449
1755
  (zone, index) => {
1450
1756
  return reorderDropTarget?.zone === zone && reorderDropTarget?.index === index;
1451
1757
  },
1452
1758
  [reorderDropTarget]
1453
1759
  );
1454
1760
  const currentFontSize = fontSize;
1455
- return /* @__PURE__ */ jsxs3(
1761
+ return /* @__PURE__ */ jsxs4(
1456
1762
  "div",
1457
1763
  {
1458
1764
  className: `vpg-pivot-skeleton vpg-font-${currentFontSize} ${draggingField ? "vpg-is-dragging" : ""}`,
1459
1765
  children: [
1460
- /* @__PURE__ */ jsxs3("div", { className: "vpg-skeleton-header", children: [
1461
- /* @__PURE__ */ jsxs3("div", { className: "vpg-skeleton-title", children: [
1462
- /* @__PURE__ */ jsx3("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx3(
1766
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-skeleton-header", children: [
1767
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-skeleton-title", children: [
1768
+ /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
1463
1769
  "path",
1464
1770
  {
1465
1771
  strokeLinecap: "round",
@@ -1468,24 +1774,24 @@ function PivotSkeleton({
1468
1774
  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"
1469
1775
  }
1470
1776
  ) }),
1471
- /* @__PURE__ */ jsx3("span", { children: "Pivot Table" })
1777
+ /* @__PURE__ */ jsx4("span", { children: "Pivot Table" })
1472
1778
  ] }),
1473
- /* @__PURE__ */ jsxs3("div", { className: "vpg-header-right", children: [
1474
- hasActiveFilters && /* @__PURE__ */ jsxs3(
1779
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-header-right", children: [
1780
+ hasActiveFilters && /* @__PURE__ */ jsxs4(
1475
1781
  "div",
1476
1782
  {
1477
1783
  className: "vpg-filter-indicator",
1478
1784
  onMouseEnter: () => setShowFilterTooltip(true),
1479
1785
  onMouseLeave: () => setShowFilterTooltip(false),
1480
1786
  children: [
1481
- /* @__PURE__ */ jsx3(
1787
+ /* @__PURE__ */ jsx4(
1482
1788
  "svg",
1483
1789
  {
1484
1790
  className: "vpg-filter-icon",
1485
1791
  fill: "none",
1486
1792
  stroke: "currentColor",
1487
1793
  viewBox: "0 0 24 24",
1488
- children: /* @__PURE__ */ jsx3(
1794
+ children: /* @__PURE__ */ jsx4(
1489
1795
  "path",
1490
1796
  {
1491
1797
  strokeLinecap: "round",
@@ -1496,10 +1802,10 @@ function PivotSkeleton({
1496
1802
  )
1497
1803
  }
1498
1804
  ),
1499
- /* @__PURE__ */ jsxs3("span", { className: "vpg-filter-text", children: [
1805
+ /* @__PURE__ */ jsxs4("span", { className: "vpg-filter-text", children: [
1500
1806
  "Filtered: ",
1501
- /* @__PURE__ */ jsx3("strong", { children: filterSummary }),
1502
- filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ jsxs3("span", { className: "vpg-filter-count", children: [
1807
+ /* @__PURE__ */ jsx4("strong", { children: filterSummary }),
1808
+ filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ jsxs4("span", { className: "vpg-filter-count", children: [
1503
1809
  "(",
1504
1810
  filteredRowCount.toLocaleString(),
1505
1811
  " of ",
@@ -1507,20 +1813,20 @@ function PivotSkeleton({
1507
1813
  " rows)"
1508
1814
  ] })
1509
1815
  ] }),
1510
- showFilterTooltip && /* @__PURE__ */ jsxs3("div", { className: "vpg-filter-tooltip", children: [
1511
- /* @__PURE__ */ jsx3("div", { className: "vpg-tooltip-header", children: "Active Filters" }),
1512
- filterTooltipDetails.map((filter) => /* @__PURE__ */ jsxs3("div", { className: "vpg-tooltip-filter", children: [
1513
- /* @__PURE__ */ jsx3("div", { className: "vpg-tooltip-column", children: filter.column }),
1514
- /* @__PURE__ */ jsxs3("div", { className: "vpg-tooltip-values", children: [
1515
- filter.values.map((val, idx) => /* @__PURE__ */ jsx3("span", { className: "vpg-tooltip-value", children: val }, idx)),
1516
- filter.remaining > 0 && /* @__PURE__ */ jsxs3("span", { className: "vpg-tooltip-more", children: [
1816
+ showFilterTooltip && /* @__PURE__ */ jsxs4("div", { className: "vpg-filter-tooltip", children: [
1817
+ /* @__PURE__ */ jsx4("div", { className: "vpg-tooltip-header", children: "Active Filters" }),
1818
+ filterTooltipDetails.map((filter) => /* @__PURE__ */ jsxs4("div", { className: "vpg-tooltip-filter", children: [
1819
+ /* @__PURE__ */ jsx4("div", { className: "vpg-tooltip-column", children: filter.column }),
1820
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-tooltip-values", children: [
1821
+ filter.values.map((val, idx) => /* @__PURE__ */ jsx4("span", { className: "vpg-tooltip-value", children: val }, idx)),
1822
+ filter.remaining > 0 && /* @__PURE__ */ jsxs4("span", { className: "vpg-tooltip-more", children: [
1517
1823
  "+",
1518
1824
  filter.remaining,
1519
1825
  " more"
1520
1826
  ] })
1521
1827
  ] })
1522
1828
  ] }, filter.column)),
1523
- filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ jsxs3("div", { className: "vpg-tooltip-summary", children: [
1829
+ filteredRowCount !== void 0 && totalRowCount !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "vpg-tooltip-summary", children: [
1524
1830
  "Showing ",
1525
1831
  filteredRowCount.toLocaleString(),
1526
1832
  " of ",
@@ -1531,18 +1837,18 @@ function PivotSkeleton({
1531
1837
  ]
1532
1838
  }
1533
1839
  ),
1534
- isConfigured && /* @__PURE__ */ jsxs3("div", { className: "vpg-config-summary", children: [
1535
- /* @__PURE__ */ jsxs3("span", { className: "vpg-summary-badge vpg-rows", children: [
1840
+ isConfigured && /* @__PURE__ */ jsxs4("div", { className: "vpg-config-summary", children: [
1841
+ /* @__PURE__ */ jsxs4("span", { className: "vpg-summary-badge vpg-rows", children: [
1536
1842
  rowFields.length,
1537
1843
  " row",
1538
1844
  rowFields.length !== 1 ? "s" : ""
1539
1845
  ] }),
1540
- /* @__PURE__ */ jsxs3("span", { className: "vpg-summary-badge vpg-cols", children: [
1846
+ /* @__PURE__ */ jsxs4("span", { className: "vpg-summary-badge vpg-cols", children: [
1541
1847
  columnFields.length,
1542
1848
  " col",
1543
1849
  columnFields.length !== 1 ? "s" : ""
1544
1850
  ] }),
1545
- /* @__PURE__ */ jsxs3("span", { className: "vpg-summary-badge vpg-vals", children: [
1851
+ /* @__PURE__ */ jsxs4("span", { className: "vpg-summary-badge vpg-vals", children: [
1546
1852
  valueFields.length,
1547
1853
  " val",
1548
1854
  valueFields.length !== 1 ? "s" : ""
@@ -1550,8 +1856,8 @@ function PivotSkeleton({
1550
1856
  ] })
1551
1857
  ] })
1552
1858
  ] }),
1553
- !canUsePivot ? /* @__PURE__ */ jsx3("div", { className: "vpg-pro-required", children: /* @__PURE__ */ jsxs3("div", { className: "vpg-pro-content", children: [
1554
- /* @__PURE__ */ jsx3("svg", { className: "vpg-pro-icon", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx3(
1859
+ !canUsePivot ? /* @__PURE__ */ jsx4("div", { className: "vpg-pro-required", children: /* @__PURE__ */ jsxs4("div", { className: "vpg-pro-content", children: [
1860
+ /* @__PURE__ */ jsx4("svg", { className: "vpg-pro-icon", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx4(
1555
1861
  "path",
1556
1862
  {
1557
1863
  strokeLinecap: "round",
@@ -1560,12 +1866,12 @@ function PivotSkeleton({
1560
1866
  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"
1561
1867
  }
1562
1868
  ) }),
1563
- /* @__PURE__ */ jsx3("h3", { children: "Pro Feature" }),
1564
- /* @__PURE__ */ jsx3("p", { children: "Pivot Table functionality requires a Pro license." }),
1565
- /* @__PURE__ */ jsx3("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", className: "vpg-pro-link", children: "Get Pro License \u2192" })
1566
- ] }) }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
1567
- /* @__PURE__ */ jsxs3("div", { className: "vpg-config-bar", children: [
1568
- /* @__PURE__ */ jsxs3(
1869
+ /* @__PURE__ */ jsx4("h3", { children: "Pro Feature" }),
1870
+ /* @__PURE__ */ jsx4("p", { children: "Pivot Table functionality requires a Pro license." }),
1871
+ /* @__PURE__ */ jsx4("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", className: "vpg-pro-link", children: "Get Pro License \u2192" })
1872
+ ] }) }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
1873
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-config-bar", children: [
1874
+ /* @__PURE__ */ jsxs4(
1569
1875
  "div",
1570
1876
  {
1571
1877
  className: `vpg-drop-zone vpg-row-zone ${dragOverArea === "row" ? "vpg-drag-over" : ""}`,
@@ -1573,12 +1879,12 @@ function PivotSkeleton({
1573
1879
  onDragLeave: handleDragLeave,
1574
1880
  onDrop: (e) => handleDrop("row", e),
1575
1881
  children: [
1576
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-header", children: [
1577
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-icon vpg-row-icon", children: "\u2193" }),
1578
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-label", children: "Rows" })
1882
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-header", children: [
1883
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-icon vpg-row-icon", children: "\u2193" }),
1884
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-label", children: "Rows" })
1579
1885
  ] }),
1580
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-chips", children: [
1581
- rowFields.map((field, idx) => /* @__PURE__ */ jsxs3(
1886
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-chips", children: [
1887
+ rowFields.map((field, idx) => /* @__PURE__ */ jsxs4(
1582
1888
  "div",
1583
1889
  {
1584
1890
  className: `vpg-mini-chip vpg-row-chip ${isChipDragSource("row", idx) ? "vpg-chip-dragging" : ""} ${isChipDropTarget("row", idx) ? "vpg-chip-drop-target" : ""}`,
@@ -1589,9 +1895,9 @@ function PivotSkeleton({
1589
1895
  onDragLeave: handleChipDragLeave,
1590
1896
  onDrop: (e) => handleChipDrop("row", idx, e),
1591
1897
  children: [
1592
- /* @__PURE__ */ jsx3("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1593
- /* @__PURE__ */ jsx3("span", { className: "vpg-mini-name", children: field }),
1594
- /* @__PURE__ */ jsx3(
1898
+ /* @__PURE__ */ jsx4("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1899
+ /* @__PURE__ */ jsx4("span", { className: "vpg-mini-name", children: field }),
1900
+ /* @__PURE__ */ jsx4(
1595
1901
  "button",
1596
1902
  {
1597
1903
  className: "vpg-mini-remove",
@@ -1606,12 +1912,12 @@ function PivotSkeleton({
1606
1912
  },
1607
1913
  field
1608
1914
  )),
1609
- rowFields.length === 0 && /* @__PURE__ */ jsx3("span", { className: "vpg-zone-hint", children: "Drop here" })
1915
+ rowFields.length === 0 && /* @__PURE__ */ jsx4("span", { className: "vpg-zone-hint", children: "Drop here" })
1610
1916
  ] })
1611
1917
  ]
1612
1918
  }
1613
1919
  ),
1614
- /* @__PURE__ */ jsxs3(
1920
+ /* @__PURE__ */ jsxs4(
1615
1921
  "div",
1616
1922
  {
1617
1923
  className: `vpg-drop-zone vpg-column-zone ${dragOverArea === "column" ? "vpg-drag-over" : ""}`,
@@ -1619,12 +1925,12 @@ function PivotSkeleton({
1619
1925
  onDragLeave: handleDragLeave,
1620
1926
  onDrop: (e) => handleDrop("column", e),
1621
1927
  children: [
1622
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-header", children: [
1623
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-icon vpg-column-icon", children: "\u2192" }),
1624
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-label", children: "Columns" })
1928
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-header", children: [
1929
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-icon vpg-column-icon", children: "\u2192" }),
1930
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-label", children: "Columns" })
1625
1931
  ] }),
1626
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-chips", children: [
1627
- columnFields.map((field, idx) => /* @__PURE__ */ jsxs3(
1932
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-chips", children: [
1933
+ columnFields.map((field, idx) => /* @__PURE__ */ jsxs4(
1628
1934
  "div",
1629
1935
  {
1630
1936
  className: `vpg-mini-chip vpg-column-chip ${isChipDragSource("column", idx) ? "vpg-chip-dragging" : ""} ${isChipDropTarget("column", idx) ? "vpg-chip-drop-target" : ""}`,
@@ -1635,9 +1941,9 @@ function PivotSkeleton({
1635
1941
  onDragLeave: handleChipDragLeave,
1636
1942
  onDrop: (e) => handleChipDrop("column", idx, e),
1637
1943
  children: [
1638
- /* @__PURE__ */ jsx3("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1639
- /* @__PURE__ */ jsx3("span", { className: "vpg-mini-name", children: field }),
1640
- /* @__PURE__ */ jsx3(
1944
+ /* @__PURE__ */ jsx4("span", { className: "vpg-drag-handle", children: "\u22EE\u22EE" }),
1945
+ /* @__PURE__ */ jsx4("span", { className: "vpg-mini-name", children: field }),
1946
+ /* @__PURE__ */ jsx4(
1641
1947
  "button",
1642
1948
  {
1643
1949
  className: "vpg-mini-remove",
@@ -1652,12 +1958,12 @@ function PivotSkeleton({
1652
1958
  },
1653
1959
  field
1654
1960
  )),
1655
- columnFields.length === 0 && /* @__PURE__ */ jsx3("span", { className: "vpg-zone-hint", children: "Drop here" })
1961
+ columnFields.length === 0 && /* @__PURE__ */ jsx4("span", { className: "vpg-zone-hint", children: "Drop here" })
1656
1962
  ] })
1657
1963
  ]
1658
1964
  }
1659
1965
  ),
1660
- /* @__PURE__ */ jsxs3(
1966
+ /* @__PURE__ */ jsxs4(
1661
1967
  "div",
1662
1968
  {
1663
1969
  className: `vpg-drop-zone vpg-value-zone ${dragOverArea === "value" ? "vpg-drag-over" : ""}`,
@@ -1665,19 +1971,19 @@ function PivotSkeleton({
1665
1971
  onDragLeave: handleDragLeave,
1666
1972
  onDrop: (e) => handleDrop("value", e),
1667
1973
  children: [
1668
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-header", children: [
1669
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-icon vpg-value-icon", children: "\u03A3" }),
1670
- /* @__PURE__ */ jsx3("span", { className: "vpg-zone-label", children: "Values" })
1974
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-header", children: [
1975
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-icon vpg-value-icon", children: "\u03A3" }),
1976
+ /* @__PURE__ */ jsx4("span", { className: "vpg-zone-label", children: "Values" })
1671
1977
  ] }),
1672
- /* @__PURE__ */ jsxs3("div", { className: "vpg-zone-chips", children: [
1673
- valueFields.map((vf) => /* @__PURE__ */ jsxs3(
1978
+ /* @__PURE__ */ jsxs4("div", { className: "vpg-zone-chips", children: [
1979
+ valueFields.map((vf) => /* @__PURE__ */ jsxs4(
1674
1980
  "div",
1675
1981
  {
1676
1982
  className: "vpg-mini-chip vpg-value-chip",
1677
1983
  children: [
1678
- /* @__PURE__ */ jsx3("span", { className: "vpg-agg-symbol", children: getAggregationSymbol2(vf.aggregation) }),
1679
- /* @__PURE__ */ jsx3("span", { className: "vpg-mini-name", children: vf.field }),
1680
- /* @__PURE__ */ jsx3(
1984
+ /* @__PURE__ */ jsx4("span", { className: "vpg-agg-symbol", children: getAggregationSymbol2(vf.aggregation) }),
1985
+ /* @__PURE__ */ jsx4("span", { className: "vpg-mini-name", children: vf.field }),
1986
+ /* @__PURE__ */ jsx4(
1681
1987
  "button",
1682
1988
  {
1683
1989
  className: "vpg-mini-remove",
@@ -1689,21 +1995,21 @@ function PivotSkeleton({
1689
1995
  },
1690
1996
  `${vf.field}-${vf.aggregation}`
1691
1997
  )),
1692
- valueFields.length === 0 && /* @__PURE__ */ jsx3("span", { className: "vpg-zone-hint", children: "Drop numeric" })
1998
+ valueFields.length === 0 && /* @__PURE__ */ jsx4("span", { className: "vpg-zone-hint", children: "Drop numeric" })
1693
1999
  ] })
1694
2000
  ]
1695
2001
  }
1696
2002
  )
1697
2003
  ] }),
1698
- (!isConfigured || !pivotResult) && /* @__PURE__ */ jsx3("div", { className: "vpg-placeholder", children: /* @__PURE__ */ jsxs3("div", { className: "vpg-placeholder-content", children: [
1699
- /* @__PURE__ */ jsx3(
2004
+ (!isConfigured || !pivotResult) && /* @__PURE__ */ jsx4("div", { className: "vpg-placeholder", children: /* @__PURE__ */ jsxs4("div", { className: "vpg-placeholder-content", children: [
2005
+ /* @__PURE__ */ jsx4(
1700
2006
  "svg",
1701
2007
  {
1702
2008
  className: "vpg-placeholder-icon",
1703
2009
  fill: "none",
1704
2010
  viewBox: "0 0 24 24",
1705
2011
  stroke: "currentColor",
1706
- children: /* @__PURE__ */ jsx3(
2012
+ children: /* @__PURE__ */ jsx4(
1707
2013
  "path",
1708
2014
  {
1709
2015
  strokeLinecap: "round",
@@ -1714,51 +2020,51 @@ function PivotSkeleton({
1714
2020
  )
1715
2021
  }
1716
2022
  ),
1717
- /* @__PURE__ */ jsx3("span", { className: "vpg-placeholder-text", children: valueFields.length === 0 ? /* @__PURE__ */ jsxs3(Fragment, { children: [
2023
+ /* @__PURE__ */ jsx4("span", { className: "vpg-placeholder-text", children: valueFields.length === 0 ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1718
2024
  "Add a ",
1719
- /* @__PURE__ */ jsx3("strong", { children: "Values" }),
2025
+ /* @__PURE__ */ jsx4("strong", { children: "Values" }),
1720
2026
  " field to see your pivot table"
1721
- ] }) : rowFields.length === 0 && columnFields.length === 0 ? /* @__PURE__ */ jsxs3(Fragment, { children: [
2027
+ ] }) : rowFields.length === 0 && columnFields.length === 0 ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
1722
2028
  "Add ",
1723
- /* @__PURE__ */ jsx3("strong", { children: "Row" }),
2029
+ /* @__PURE__ */ jsx4("strong", { children: "Row" }),
1724
2030
  " or ",
1725
- /* @__PURE__ */ jsx3("strong", { children: "Column" }),
2031
+ /* @__PURE__ */ jsx4("strong", { children: "Column" }),
1726
2032
  " fields to group your data"
1727
2033
  ] }) : "Your pivot table will appear here" })
1728
2034
  ] }) }),
1729
- isConfigured && pivotResult && /* @__PURE__ */ jsx3("div", { className: "vpg-table-container", children: /* @__PURE__ */ jsxs3("table", { className: "vpg-pivot-table", children: [
1730
- /* @__PURE__ */ jsx3("thead", { children: columnHeaderCells.map((headerRow, levelIdx) => /* @__PURE__ */ jsxs3("tr", { className: "vpg-column-header-row", children: [
1731
- levelIdx === 0 && /* @__PURE__ */ jsx3(
2035
+ isConfigured && pivotResult && /* @__PURE__ */ jsx4("div", { className: "vpg-table-container", children: /* @__PURE__ */ jsxs4("table", { className: "vpg-pivot-table", children: [
2036
+ /* @__PURE__ */ jsx4("thead", { children: columnHeaderCells.map((headerRow, levelIdx) => /* @__PURE__ */ jsxs4("tr", { className: "vpg-column-header-row", children: [
2037
+ levelIdx === 0 && /* @__PURE__ */ jsx4(
1732
2038
  "th",
1733
2039
  {
1734
2040
  className: "vpg-row-header-label",
1735
2041
  rowSpan: columnHeaderCells.length,
1736
2042
  onClick: () => toggleSort("row"),
1737
- children: /* @__PURE__ */ jsxs3("div", { className: "vpg-header-content", children: [
1738
- /* @__PURE__ */ jsx3("span", { children: rowFields.join(" / ") || "Rows" }),
1739
- /* @__PURE__ */ jsx3("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2043
+ children: /* @__PURE__ */ jsxs4("div", { className: "vpg-header-content", children: [
2044
+ /* @__PURE__ */ jsx4("span", { children: rowFields.join(" / ") || "Rows" }),
2045
+ /* @__PURE__ */ jsx4("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
1740
2046
  ] })
1741
2047
  }
1742
2048
  ),
1743
- headerRow.map((cell, idx) => /* @__PURE__ */ jsx3(
2049
+ headerRow.map((cell, idx) => /* @__PURE__ */ jsx4(
1744
2050
  "th",
1745
2051
  {
1746
2052
  className: "vpg-column-header-cell",
1747
2053
  colSpan: cell.colspan,
1748
2054
  onClick: () => levelIdx === columnHeaderCells.length - 1 && toggleSort(idx),
1749
- children: /* @__PURE__ */ jsxs3("div", { className: "vpg-header-content", children: [
1750
- /* @__PURE__ */ jsx3("span", { children: cell.label }),
1751
- levelIdx === columnHeaderCells.length - 1 && /* @__PURE__ */ jsx3("span", { className: `vpg-sort-indicator ${sortTarget === idx ? "active" : ""}`, children: sortTarget === idx ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2055
+ children: /* @__PURE__ */ jsxs4("div", { className: "vpg-header-content", children: [
2056
+ /* @__PURE__ */ jsx4("span", { children: cell.label }),
2057
+ levelIdx === columnHeaderCells.length - 1 && /* @__PURE__ */ jsx4("span", { className: `vpg-sort-indicator ${sortTarget === idx ? "active" : ""}`, children: sortTarget === idx ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
1752
2058
  ] })
1753
2059
  },
1754
2060
  idx
1755
2061
  )),
1756
- pivotResult.rowTotals.length > 0 && levelIdx === 0 && /* @__PURE__ */ jsx3("th", { className: "vpg-total-header", rowSpan: columnHeaderCells.length, children: "Total" })
2062
+ pivotResult.rowTotals.length > 0 && levelIdx === 0 && /* @__PURE__ */ jsx4("th", { className: "vpg-total-header", rowSpan: columnHeaderCells.length, children: "Total" })
1757
2063
  ] }, `header-${levelIdx}`)) }),
1758
- /* @__PURE__ */ jsxs3("tbody", { children: [
1759
- sortedRowIndices.map((sortedIdx) => /* @__PURE__ */ jsxs3("tr", { className: "vpg-data-row", children: [
1760
- /* @__PURE__ */ jsx3("th", { className: "vpg-row-header-cell", children: pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ jsx3("span", { className: "vpg-row-value", children: val }, idx)) }),
1761
- pivotResult.data[sortedIdx].map((cell, colIdx) => /* @__PURE__ */ jsx3(
2064
+ /* @__PURE__ */ jsxs4("tbody", { children: [
2065
+ sortedRowIndices.map((sortedIdx) => /* @__PURE__ */ jsxs4("tr", { className: "vpg-data-row", children: [
2066
+ /* @__PURE__ */ jsx4("th", { className: "vpg-row-header-cell", children: pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ jsx4("span", { className: "vpg-row-value", children: val }, idx)) }),
2067
+ pivotResult.data[sortedIdx].map((cell, colIdx) => /* @__PURE__ */ jsx4(
1762
2068
  "td",
1763
2069
  {
1764
2070
  className: `vpg-data-cell ${cell.value === null ? "vpg-is-null" : ""}`,
@@ -1766,26 +2072,26 @@ function PivotSkeleton({
1766
2072
  },
1767
2073
  colIdx
1768
2074
  )),
1769
- pivotResult.rowTotals[sortedIdx] && /* @__PURE__ */ jsx3("td", { className: "vpg-data-cell vpg-total-cell", children: pivotResult.rowTotals[sortedIdx].formattedValue })
2075
+ pivotResult.rowTotals[sortedIdx] && /* @__PURE__ */ jsx4("td", { className: "vpg-data-cell vpg-total-cell", children: pivotResult.rowTotals[sortedIdx].formattedValue })
1770
2076
  ] }, sortedIdx)),
1771
- pivotResult.columnTotals.length > 0 && /* @__PURE__ */ jsxs3("tr", { className: "vpg-totals-row", children: [
1772
- /* @__PURE__ */ jsx3("th", { className: "vpg-row-header-cell vpg-total-label", children: "Total" }),
1773
- pivotResult.columnTotals.map((cell, colIdx) => /* @__PURE__ */ jsx3("td", { className: "vpg-data-cell vpg-total-cell", children: cell.formattedValue }, colIdx)),
1774
- pivotResult.rowTotals.length > 0 && /* @__PURE__ */ jsx3("td", { className: "vpg-data-cell vpg-grand-total-cell", children: pivotResult.grandTotal.formattedValue })
2077
+ pivotResult.columnTotals.length > 0 && /* @__PURE__ */ jsxs4("tr", { className: "vpg-totals-row", children: [
2078
+ /* @__PURE__ */ jsx4("th", { className: "vpg-row-header-cell vpg-total-label", children: "Total" }),
2079
+ pivotResult.columnTotals.map((cell, colIdx) => /* @__PURE__ */ jsx4("td", { className: "vpg-data-cell vpg-total-cell", children: cell.formattedValue }, colIdx)),
2080
+ pivotResult.rowTotals.length > 0 && /* @__PURE__ */ jsx4("td", { className: "vpg-data-cell vpg-grand-total-cell", children: pivotResult.grandTotal.formattedValue })
1775
2081
  ] })
1776
2082
  ] })
1777
2083
  ] }) }),
1778
- isConfigured && pivotResult && /* @__PURE__ */ jsx3("div", { className: "vpg-skeleton-footer", children: /* @__PURE__ */ jsxs3("span", { children: [
2084
+ isConfigured && pivotResult && /* @__PURE__ */ jsx4("div", { className: "vpg-skeleton-footer", children: /* @__PURE__ */ jsxs4("span", { children: [
1779
2085
  pivotResult.rowHeaders.length,
1780
2086
  " rows \xD7 ",
1781
2087
  pivotResult.data[0]?.length || 0,
1782
2088
  " columns"
1783
2089
  ] }) })
1784
2090
  ] }),
1785
- showWatermark && canUsePivot && /* @__PURE__ */ jsx3("div", { className: `vpg-watermark ${isDemo ? "vpg-demo-mode" : ""}`, children: isDemo ? /* @__PURE__ */ jsxs3(Fragment, { children: [
1786
- /* @__PURE__ */ jsx3("span", { className: "vpg-demo-badge", children: "DEMO" }),
1787
- /* @__PURE__ */ jsx3("span", { children: "Pro features unlocked for evaluation" }),
1788
- /* @__PURE__ */ jsx3(
2091
+ showWatermark && canUsePivot && /* @__PURE__ */ jsx4("div", { className: `vpg-watermark ${isDemo ? "vpg-demo-mode" : ""}`, children: isDemo ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
2092
+ /* @__PURE__ */ jsx4("span", { className: "vpg-demo-badge", children: "DEMO" }),
2093
+ /* @__PURE__ */ jsx4("span", { children: "Pro features unlocked for evaluation" }),
2094
+ /* @__PURE__ */ jsx4(
1789
2095
  "a",
1790
2096
  {
1791
2097
  href: "https://tiny-pivot.com/#pricing",
@@ -1795,14 +2101,14 @@ function PivotSkeleton({
1795
2101
  children: "Get Pro License \u2192"
1796
2102
  }
1797
2103
  )
1798
- ] }) : /* @__PURE__ */ jsx3("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "Powered by TinyPivot" }) })
2104
+ ] }) : /* @__PURE__ */ jsx4("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: "Powered by TinyPivot" }) })
1799
2105
  ]
1800
2106
  }
1801
2107
  );
1802
2108
  }
1803
2109
 
1804
2110
  // src/components/DataGrid.tsx
1805
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2111
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1806
2112
  var MIN_COL_WIDTH = 120;
1807
2113
  var MAX_COL_WIDTH = 350;
1808
2114
  function DataGrid({
@@ -1828,35 +2134,35 @@ function DataGrid({
1828
2134
  onCopy
1829
2135
  }) {
1830
2136
  const { showWatermark, canUsePivot, isDemo } = useLicense();
1831
- const currentTheme = useMemo8(() => {
2137
+ const currentTheme = useMemo9(() => {
1832
2138
  if (theme === "auto") {
1833
2139
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1834
2140
  }
1835
2141
  return theme;
1836
2142
  }, [theme]);
1837
- const [currentFontSize, setCurrentFontSize] = useState8(initialFontSize);
1838
- const [globalSearchTerm, setGlobalSearchTerm] = useState8("");
1839
- const [showSearchInput, setShowSearchInput] = useState8(false);
1840
- const [currentPage, setCurrentPage] = useState8(1);
1841
- const [columnWidths, setColumnWidths] = useState8({});
1842
- const [resizingColumnId, setResizingColumnId] = useState8(null);
1843
- const [resizeStartX, setResizeStartX] = useState8(0);
1844
- const [resizeStartWidth, setResizeStartWidth] = useState8(0);
1845
- const [gridHeight, setGridHeight] = useState8(initialHeight);
1846
- const [isResizingVertically, setIsResizingVertically] = useState8(false);
1847
- const [verticalResizeStartY, setVerticalResizeStartY] = useState8(0);
1848
- const [verticalResizeStartHeight, setVerticalResizeStartHeight] = useState8(0);
1849
- const [showCopyToast, setShowCopyToast] = useState8(false);
1850
- const [copyToastMessage, setCopyToastMessage] = useState8("");
1851
- const [viewMode, setViewMode] = useState8("grid");
1852
- const [showPivotConfig, setShowPivotConfig] = useState8(true);
1853
- const [draggingField, setDraggingField] = useState8(null);
1854
- const [activeFilterColumn, setActiveFilterColumn] = useState8(null);
1855
- const [filterDropdownPosition, setFilterDropdownPosition] = useState8({ top: 0, left: 0, maxHeight: 400 });
1856
- const [selectedCell, setSelectedCell] = useState8(null);
1857
- const [selectionStart, setSelectionStart] = useState8(null);
1858
- const [selectionEnd, setSelectionEnd] = useState8(null);
1859
- const [isSelecting, setIsSelecting] = useState8(false);
2143
+ const [currentFontSize, setCurrentFontSize] = useState9(initialFontSize);
2144
+ const [globalSearchTerm, setGlobalSearchTerm] = useState9("");
2145
+ const [showSearchInput, setShowSearchInput] = useState9(false);
2146
+ const [currentPage, setCurrentPage] = useState9(1);
2147
+ const [columnWidths, setColumnWidths] = useState9({});
2148
+ const [resizingColumnId, setResizingColumnId] = useState9(null);
2149
+ const [resizeStartX, setResizeStartX] = useState9(0);
2150
+ const [resizeStartWidth, setResizeStartWidth] = useState9(0);
2151
+ const [gridHeight, setGridHeight] = useState9(initialHeight);
2152
+ const [isResizingVertically, setIsResizingVertically] = useState9(false);
2153
+ const [verticalResizeStartY, setVerticalResizeStartY] = useState9(0);
2154
+ const [verticalResizeStartHeight, setVerticalResizeStartHeight] = useState9(0);
2155
+ const [showCopyToast, setShowCopyToast] = useState9(false);
2156
+ const [copyToastMessage, setCopyToastMessage] = useState9("");
2157
+ const [viewMode, setViewMode] = useState9("grid");
2158
+ const [showPivotConfig, setShowPivotConfig] = useState9(true);
2159
+ const [draggingField, setDraggingField] = useState9(null);
2160
+ const [activeFilterColumn, setActiveFilterColumn] = useState9(null);
2161
+ const [filterDropdownPosition, setFilterDropdownPosition] = useState9({ top: 0, left: 0, maxHeight: 400 });
2162
+ const [selectedCell, setSelectedCell] = useState9(null);
2163
+ const [selectionStart, setSelectionStart] = useState9(null);
2164
+ const [selectionEnd, setSelectionEnd] = useState9(null);
2165
+ const [isSelecting, setIsSelecting] = useState9(false);
1860
2166
  const tableContainerRef = useRef2(null);
1861
2167
  const tableBodyRef = useRef2(null);
1862
2168
  const fontSizeOptions = [
@@ -1879,7 +2185,7 @@ function DataGrid({
1879
2185
  columnFilters,
1880
2186
  activeFilters
1881
2187
  } = useExcelGrid({ data, enableSorting: true, enableFiltering: true });
1882
- const filteredDataForPivot = useMemo8(() => {
2188
+ const filteredDataForPivot = useMemo9(() => {
1883
2189
  const filteredRows = table.getFilteredRowModel().rows;
1884
2190
  return filteredRows.map((row) => row.original);
1885
2191
  }, [table, columnFilters]);
@@ -1889,6 +2195,7 @@ function DataGrid({
1889
2195
  valueFields: pivotValueFields,
1890
2196
  showRowTotals: pivotShowRowTotals,
1891
2197
  showColumnTotals: pivotShowColumnTotals,
2198
+ calculatedFields: pivotCalculatedFields,
1892
2199
  availableFields: pivotAvailableFields,
1893
2200
  isConfigured: pivotIsConfigured,
1894
2201
  pivotResult,
@@ -1904,9 +2211,11 @@ function DataGrid({
1904
2211
  setShowRowTotals: setPivotShowRowTotals,
1905
2212
  setShowColumnTotals: setPivotShowColumnTotals,
1906
2213
  setRowFields,
1907
- setColumnFields
2214
+ setColumnFields,
2215
+ addCalculatedField,
2216
+ removeCalculatedField
1908
2217
  } = usePivotTable(filteredDataForPivot);
1909
- const activeFilterInfo = useMemo8(() => {
2218
+ const activeFilterInfo = useMemo9(() => {
1910
2219
  if (activeFilters.length === 0) return null;
1911
2220
  return activeFilters.map((f) => ({
1912
2221
  column: f.column,
@@ -1914,8 +2223,8 @@ function DataGrid({
1914
2223
  values: f.values || []
1915
2224
  }));
1916
2225
  }, [activeFilters]);
1917
- const rows = useMemo8(() => table.getFilteredRowModel().rows, [table, columnFilters]);
1918
- const searchFilteredData = useMemo8(() => {
2226
+ const rows = useMemo9(() => table.getFilteredRowModel().rows, [table, columnFilters]);
2227
+ const searchFilteredData = useMemo9(() => {
1919
2228
  if (!globalSearchTerm.trim() || !enableSearch) {
1920
2229
  return rows;
1921
2230
  }
@@ -1932,20 +2241,20 @@ function DataGrid({
1932
2241
  });
1933
2242
  }, [rows, globalSearchTerm, enableSearch, columnKeys]);
1934
2243
  const totalSearchedRows = searchFilteredData.length;
1935
- const totalPages = useMemo8(() => {
2244
+ const totalPages = useMemo9(() => {
1936
2245
  if (!enablePagination) return 1;
1937
2246
  return Math.max(1, Math.ceil(totalSearchedRows / pageSize));
1938
2247
  }, [enablePagination, totalSearchedRows, pageSize]);
1939
- const paginatedRows = useMemo8(() => {
2248
+ const paginatedRows = useMemo9(() => {
1940
2249
  if (!enablePagination) return searchFilteredData;
1941
2250
  const start = (currentPage - 1) * pageSize;
1942
2251
  const end = start + pageSize;
1943
2252
  return searchFilteredData.slice(start, end);
1944
2253
  }, [enablePagination, searchFilteredData, currentPage, pageSize]);
1945
- useEffect4(() => {
2254
+ useEffect5(() => {
1946
2255
  setCurrentPage(1);
1947
2256
  }, [columnFilters, globalSearchTerm]);
1948
- const selectionBounds = useMemo8(() => {
2257
+ const selectionBounds = useMemo9(() => {
1949
2258
  if (!selectionStart || !selectionEnd) return null;
1950
2259
  return {
1951
2260
  minRow: Math.min(selectionStart.row, selectionEnd.row),
@@ -1954,7 +2263,7 @@ function DataGrid({
1954
2263
  maxCol: Math.max(selectionStart.col, selectionEnd.col)
1955
2264
  };
1956
2265
  }, [selectionStart, selectionEnd]);
1957
- const selectionStats = useMemo8(() => {
2266
+ const selectionStats = useMemo9(() => {
1958
2267
  if (!selectionBounds) return null;
1959
2268
  const { minRow, maxRow, minCol, maxCol } = selectionBounds;
1960
2269
  const values = [];
@@ -1980,7 +2289,7 @@ function DataGrid({
1980
2289
  const avg = sum / values.length;
1981
2290
  return { count, sum, avg, numericCount: values.length };
1982
2291
  }, [selectionBounds, rows, columnKeys]);
1983
- useEffect4(() => {
2292
+ useEffect5(() => {
1984
2293
  if (data.length === 0) return;
1985
2294
  const widths = {};
1986
2295
  const sampleSize = Math.min(100, data.length);
@@ -2000,7 +2309,7 @@ function DataGrid({
2000
2309
  }
2001
2310
  setColumnWidths(widths);
2002
2311
  }, [data, columnKeys]);
2003
- const startColumnResize = useCallback8(
2312
+ const startColumnResize = useCallback9(
2004
2313
  (columnId, event) => {
2005
2314
  if (!enableColumnResize) return;
2006
2315
  event.preventDefault();
@@ -2011,7 +2320,7 @@ function DataGrid({
2011
2320
  },
2012
2321
  [enableColumnResize, columnWidths]
2013
2322
  );
2014
- useEffect4(() => {
2323
+ useEffect5(() => {
2015
2324
  if (!resizingColumnId) return;
2016
2325
  const handleResizeMove = (event) => {
2017
2326
  const diff = event.clientX - resizeStartX;
@@ -2031,7 +2340,7 @@ function DataGrid({
2031
2340
  document.removeEventListener("mouseup", handleResizeEnd);
2032
2341
  };
2033
2342
  }, [resizingColumnId, resizeStartX, resizeStartWidth]);
2034
- const startVerticalResize = useCallback8(
2343
+ const startVerticalResize = useCallback9(
2035
2344
  (event) => {
2036
2345
  if (!enableVerticalResize) return;
2037
2346
  event.preventDefault();
@@ -2041,7 +2350,7 @@ function DataGrid({
2041
2350
  },
2042
2351
  [enableVerticalResize, gridHeight]
2043
2352
  );
2044
- useEffect4(() => {
2353
+ useEffect5(() => {
2045
2354
  if (!isResizingVertically) return;
2046
2355
  const handleVerticalResizeMove = (event) => {
2047
2356
  const diff = event.clientY - verticalResizeStartY;
@@ -2058,7 +2367,7 @@ function DataGrid({
2058
2367
  document.removeEventListener("mouseup", handleVerticalResizeEnd);
2059
2368
  };
2060
2369
  }, [isResizingVertically, verticalResizeStartY, verticalResizeStartHeight, minHeight, maxHeight]);
2061
- const handleExport = useCallback8(() => {
2370
+ const handleExport = useCallback9(() => {
2062
2371
  if (viewMode === "pivot") {
2063
2372
  if (!pivotResult) return;
2064
2373
  const pivotFilename = exportFilename.replace(".csv", "-pivot.csv");
@@ -2103,7 +2412,7 @@ function DataGrid({
2103
2412
  columnKeys,
2104
2413
  onExport
2105
2414
  ]);
2106
- const copySelectionToClipboard = useCallback8(() => {
2415
+ const copySelectionToClipboard = useCallback9(() => {
2107
2416
  if (!selectionBounds || !enableClipboard) return;
2108
2417
  const text = formatSelectionForClipboard(
2109
2418
  rows.map((r) => r.original),
@@ -2127,7 +2436,7 @@ function DataGrid({
2127
2436
  }
2128
2437
  );
2129
2438
  }, [selectionBounds, enableClipboard, rows, columnKeys, onCopy]);
2130
- const handleMouseDown = useCallback8(
2439
+ const handleMouseDown = useCallback9(
2131
2440
  (rowIndex, colIndex, event) => {
2132
2441
  event.preventDefault();
2133
2442
  if (event.shiftKey && selectedCell) {
@@ -2151,7 +2460,7 @@ function DataGrid({
2151
2460
  },
2152
2461
  [selectedCell, rows, columnKeys, onCellClick]
2153
2462
  );
2154
- const handleMouseEnter = useCallback8(
2463
+ const handleMouseEnter = useCallback9(
2155
2464
  (rowIndex, colIndex) => {
2156
2465
  if (isSelecting) {
2157
2466
  setSelectionEnd({ row: rowIndex, col: colIndex });
@@ -2159,12 +2468,12 @@ function DataGrid({
2159
2468
  },
2160
2469
  [isSelecting]
2161
2470
  );
2162
- useEffect4(() => {
2471
+ useEffect5(() => {
2163
2472
  const handleMouseUp = () => setIsSelecting(false);
2164
2473
  document.addEventListener("mouseup", handleMouseUp);
2165
2474
  return () => document.removeEventListener("mouseup", handleMouseUp);
2166
2475
  }, []);
2167
- useEffect4(() => {
2476
+ useEffect5(() => {
2168
2477
  const handleKeydown = (event) => {
2169
2478
  if ((event.ctrlKey || event.metaKey) && event.key === "c" && selectionBounds) {
2170
2479
  event.preventDefault();
@@ -2182,7 +2491,7 @@ function DataGrid({
2182
2491
  document.addEventListener("keydown", handleKeydown);
2183
2492
  return () => document.removeEventListener("keydown", handleKeydown);
2184
2493
  }, [selectionBounds, copySelectionToClipboard]);
2185
- const openFilterDropdown = useCallback8(
2494
+ const openFilterDropdown = useCallback9(
2186
2495
  (columnId, event) => {
2187
2496
  event.stopPropagation();
2188
2497
  const target = event.currentTarget;
@@ -2211,16 +2520,16 @@ function DataGrid({
2211
2520
  },
2212
2521
  []
2213
2522
  );
2214
- const closeFilterDropdown = useCallback8(() => {
2523
+ const closeFilterDropdown = useCallback9(() => {
2215
2524
  setActiveFilterColumn(null);
2216
2525
  }, []);
2217
- const handleFilter = useCallback8(
2526
+ const handleFilter = useCallback9(
2218
2527
  (columnId, values) => {
2219
2528
  setColumnFilter(columnId, values);
2220
2529
  },
2221
2530
  [setColumnFilter]
2222
2531
  );
2223
- const handleSort = useCallback8(
2532
+ const handleSort = useCallback9(
2224
2533
  (columnId, direction) => {
2225
2534
  if (direction === null) {
2226
2535
  const current = getSortDirection(columnId);
@@ -2244,7 +2553,7 @@ function DataGrid({
2244
2553
  },
2245
2554
  [getSortDirection, toggleSort]
2246
2555
  );
2247
- const isCellSelected = useCallback8(
2556
+ const isCellSelected = useCallback9(
2248
2557
  (rowIndex, colIndex) => {
2249
2558
  if (!selectionBounds) {
2250
2559
  return selectedCell?.row === rowIndex && selectedCell?.col === colIndex;
@@ -2282,30 +2591,30 @@ function DataGrid({
2282
2591
  }
2283
2592
  return String(value);
2284
2593
  };
2285
- const totalTableWidth = useMemo8(() => {
2594
+ const totalTableWidth = useMemo9(() => {
2286
2595
  return columnKeys.reduce((sum, key) => sum + (columnWidths[key] || MIN_COL_WIDTH), 0);
2287
2596
  }, [columnKeys, columnWidths]);
2288
2597
  const activeFilterCount = columnFilters.length;
2289
- return /* @__PURE__ */ jsxs4(
2598
+ return /* @__PURE__ */ jsxs5(
2290
2599
  "div",
2291
2600
  {
2292
2601
  className: `vpg-data-grid vpg-font-${currentFontSize} vpg-theme-${currentTheme} ${stripedRows ? "vpg-striped" : ""} ${resizingColumnId ? "vpg-resizing" : ""} ${isResizingVertically ? "vpg-resizing-vertical" : ""}`,
2293
2602
  style: { height: `${gridHeight}px` },
2294
2603
  children: [
2295
- showCopyToast && /* @__PURE__ */ jsxs4("div", { className: "vpg-toast", children: [
2296
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
2604
+ showCopyToast && /* @__PURE__ */ jsxs5("div", { className: "vpg-toast", children: [
2605
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
2297
2606
  copyToastMessage
2298
2607
  ] }),
2299
- /* @__PURE__ */ jsxs4("div", { className: "vpg-toolbar", children: [
2300
- /* @__PURE__ */ jsxs4("div", { className: "vpg-toolbar-left", children: [
2301
- showPivot && /* @__PURE__ */ jsxs4("div", { className: "vpg-view-toggle", children: [
2302
- /* @__PURE__ */ jsxs4(
2608
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-toolbar", children: [
2609
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-toolbar-left", children: [
2610
+ showPivot && /* @__PURE__ */ jsxs5("div", { className: "vpg-view-toggle", children: [
2611
+ /* @__PURE__ */ jsxs5(
2303
2612
  "button",
2304
2613
  {
2305
2614
  className: `vpg-view-btn ${viewMode === "grid" ? "active" : ""}`,
2306
2615
  onClick: () => setViewMode("grid"),
2307
2616
  children: [
2308
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2617
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2309
2618
  "path",
2310
2619
  {
2311
2620
  strokeLinecap: "round",
@@ -2318,13 +2627,13 @@ function DataGrid({
2318
2627
  ]
2319
2628
  }
2320
2629
  ),
2321
- /* @__PURE__ */ jsxs4(
2630
+ /* @__PURE__ */ jsxs5(
2322
2631
  "button",
2323
2632
  {
2324
2633
  className: `vpg-view-btn vpg-pivot-btn ${viewMode === "pivot" ? "active" : ""}`,
2325
2634
  onClick: () => setViewMode("pivot"),
2326
2635
  children: [
2327
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2636
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2328
2637
  "path",
2329
2638
  {
2330
2639
  strokeLinecap: "round",
@@ -2338,14 +2647,14 @@ function DataGrid({
2338
2647
  }
2339
2648
  )
2340
2649
  ] }),
2341
- viewMode === "grid" && /* @__PURE__ */ jsxs4(Fragment2, { children: [
2342
- enableSearch && /* @__PURE__ */ jsx4("div", { className: "vpg-search-container", children: !showSearchInput ? /* @__PURE__ */ jsx4(
2650
+ viewMode === "grid" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2651
+ enableSearch && /* @__PURE__ */ jsx5("div", { className: "vpg-search-container", children: !showSearchInput ? /* @__PURE__ */ jsx5(
2343
2652
  "button",
2344
2653
  {
2345
2654
  className: "vpg-icon-btn",
2346
2655
  title: "Search (Ctrl+F)",
2347
2656
  onClick: () => setShowSearchInput(true),
2348
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2657
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2349
2658
  "path",
2350
2659
  {
2351
2660
  strokeLinecap: "round",
@@ -2355,15 +2664,15 @@ function DataGrid({
2355
2664
  }
2356
2665
  ) })
2357
2666
  }
2358
- ) : /* @__PURE__ */ jsxs4("div", { className: "vpg-search-box", children: [
2359
- /* @__PURE__ */ jsx4(
2667
+ ) : /* @__PURE__ */ jsxs5("div", { className: "vpg-search-box", children: [
2668
+ /* @__PURE__ */ jsx5(
2360
2669
  "svg",
2361
2670
  {
2362
2671
  className: "vpg-search-icon",
2363
2672
  fill: "none",
2364
2673
  stroke: "currentColor",
2365
2674
  viewBox: "0 0 24 24",
2366
- children: /* @__PURE__ */ jsx4(
2675
+ children: /* @__PURE__ */ jsx5(
2367
2676
  "path",
2368
2677
  {
2369
2678
  strokeLinecap: "round",
@@ -2374,7 +2683,7 @@ function DataGrid({
2374
2683
  )
2375
2684
  }
2376
2685
  ),
2377
- /* @__PURE__ */ jsx4(
2686
+ /* @__PURE__ */ jsx5(
2378
2687
  "input",
2379
2688
  {
2380
2689
  type: "text",
@@ -2391,14 +2700,14 @@ function DataGrid({
2391
2700
  autoFocus: true
2392
2701
  }
2393
2702
  ),
2394
- globalSearchTerm && /* @__PURE__ */ jsx4("button", { className: "vpg-search-clear", onClick: () => setGlobalSearchTerm(""), children: /* @__PURE__ */ jsx4(
2703
+ globalSearchTerm && /* @__PURE__ */ jsx5("button", { className: "vpg-search-clear", onClick: () => setGlobalSearchTerm(""), children: /* @__PURE__ */ jsx5(
2395
2704
  "svg",
2396
2705
  {
2397
2706
  className: "vpg-icon-xs",
2398
2707
  fill: "none",
2399
2708
  stroke: "currentColor",
2400
2709
  viewBox: "0 0 24 24",
2401
- children: /* @__PURE__ */ jsx4(
2710
+ children: /* @__PURE__ */ jsx5(
2402
2711
  "path",
2403
2712
  {
2404
2713
  strokeLinecap: "round",
@@ -2410,9 +2719,9 @@ function DataGrid({
2410
2719
  }
2411
2720
  ) })
2412
2721
  ] }) }),
2413
- /* @__PURE__ */ jsxs4("div", { className: "vpg-font-size-control", children: [
2414
- /* @__PURE__ */ jsx4("span", { className: "vpg-label", children: "Size:" }),
2415
- /* @__PURE__ */ jsx4("div", { className: "vpg-font-size-toggle", children: fontSizeOptions.map((opt) => /* @__PURE__ */ jsx4(
2722
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-font-size-control", children: [
2723
+ /* @__PURE__ */ jsx5("span", { className: "vpg-label", children: "Size:" }),
2724
+ /* @__PURE__ */ jsx5("div", { className: "vpg-font-size-toggle", children: fontSizeOptions.map((opt) => /* @__PURE__ */ jsx5(
2416
2725
  "button",
2417
2726
  {
2418
2727
  className: `vpg-font-size-btn ${currentFontSize === opt.value ? "active" : ""}`,
@@ -2422,8 +2731,8 @@ function DataGrid({
2422
2731
  opt.value
2423
2732
  )) })
2424
2733
  ] }),
2425
- activeFilterCount > 0 && /* @__PURE__ */ jsxs4("div", { className: "vpg-filter-info", children: [
2426
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx4(
2734
+ activeFilterCount > 0 && /* @__PURE__ */ jsxs5("div", { className: "vpg-filter-info", children: [
2735
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx5(
2427
2736
  "path",
2428
2737
  {
2429
2738
  fillRule: "evenodd",
@@ -2431,26 +2740,26 @@ function DataGrid({
2431
2740
  clipRule: "evenodd"
2432
2741
  }
2433
2742
  ) }),
2434
- /* @__PURE__ */ jsxs4("span", { children: [
2743
+ /* @__PURE__ */ jsxs5("span", { children: [
2435
2744
  activeFilterCount,
2436
2745
  " filter",
2437
2746
  activeFilterCount > 1 ? "s" : ""
2438
2747
  ] })
2439
2748
  ] }),
2440
- globalSearchTerm && /* @__PURE__ */ jsx4("div", { className: "vpg-search-info", children: /* @__PURE__ */ jsxs4("span", { children: [
2749
+ globalSearchTerm && /* @__PURE__ */ jsx5("div", { className: "vpg-search-info", children: /* @__PURE__ */ jsxs5("span", { children: [
2441
2750
  totalSearchedRows,
2442
2751
  " match",
2443
2752
  totalSearchedRows !== 1 ? "es" : ""
2444
2753
  ] }) })
2445
2754
  ] }),
2446
- viewMode === "pivot" && canUsePivot && /* @__PURE__ */ jsxs4(Fragment2, { children: [
2447
- /* @__PURE__ */ jsxs4(
2755
+ viewMode === "pivot" && canUsePivot && /* @__PURE__ */ jsxs5(Fragment3, { children: [
2756
+ /* @__PURE__ */ jsxs5(
2448
2757
  "button",
2449
2758
  {
2450
2759
  className: `vpg-config-toggle ${showPivotConfig ? "active" : ""}`,
2451
2760
  onClick: () => setShowPivotConfig(!showPivotConfig),
2452
2761
  children: [
2453
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2762
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2454
2763
  "path",
2455
2764
  {
2456
2765
  strokeLinecap: "round",
@@ -2464,8 +2773,8 @@ function DataGrid({
2464
2773
  ]
2465
2774
  }
2466
2775
  ),
2467
- pivotIsConfigured && /* @__PURE__ */ jsxs4("div", { className: "vpg-pivot-status", children: [
2468
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx4(
2776
+ pivotIsConfigured && /* @__PURE__ */ jsxs5("div", { className: "vpg-pivot-status", children: [
2777
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx5(
2469
2778
  "path",
2470
2779
  {
2471
2780
  fillRule: "evenodd",
@@ -2473,13 +2782,13 @@ function DataGrid({
2473
2782
  clipRule: "evenodd"
2474
2783
  }
2475
2784
  ) }),
2476
- /* @__PURE__ */ jsx4("span", { children: "Pivot configured" })
2785
+ /* @__PURE__ */ jsx5("span", { children: "Pivot configured" })
2477
2786
  ] })
2478
2787
  ] })
2479
2788
  ] }),
2480
- /* @__PURE__ */ jsxs4("div", { className: "vpg-toolbar-right", children: [
2481
- viewMode === "grid" && activeFilterCount > 0 && /* @__PURE__ */ jsxs4("button", { className: "vpg-clear-filters", onClick: clearAllFilters, children: [
2482
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2789
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-toolbar-right", children: [
2790
+ viewMode === "grid" && activeFilterCount > 0 && /* @__PURE__ */ jsxs5("button", { className: "vpg-clear-filters", onClick: clearAllFilters, children: [
2791
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2483
2792
  "path",
2484
2793
  {
2485
2794
  strokeLinecap: "round",
@@ -2490,13 +2799,13 @@ function DataGrid({
2490
2799
  ) }),
2491
2800
  "Clear Filters"
2492
2801
  ] }),
2493
- enableClipboard && selectionBounds && viewMode === "grid" && /* @__PURE__ */ jsx4(
2802
+ enableClipboard && selectionBounds && viewMode === "grid" && /* @__PURE__ */ jsx5(
2494
2803
  "button",
2495
2804
  {
2496
2805
  className: "vpg-icon-btn",
2497
2806
  title: "Copy selection (Ctrl+C)",
2498
2807
  onClick: copySelectionToClipboard,
2499
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2808
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2500
2809
  "path",
2501
2810
  {
2502
2811
  strokeLinecap: "round",
@@ -2507,14 +2816,14 @@ function DataGrid({
2507
2816
  ) })
2508
2817
  }
2509
2818
  ),
2510
- enableExport && (viewMode === "grid" || viewMode === "pivot" && pivotIsConfigured) && /* @__PURE__ */ jsxs4(
2819
+ enableExport && (viewMode === "grid" || viewMode === "pivot" && pivotIsConfigured) && /* @__PURE__ */ jsxs5(
2511
2820
  "button",
2512
2821
  {
2513
2822
  className: "vpg-export-btn",
2514
2823
  title: viewMode === "pivot" ? "Export Pivot to CSV" : "Export to CSV",
2515
2824
  onClick: handleExport,
2516
2825
  children: [
2517
- /* @__PURE__ */ jsx4("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2826
+ /* @__PURE__ */ jsx5("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2518
2827
  "path",
2519
2828
  {
2520
2829
  strokeLinecap: "round",
@@ -2530,13 +2839,13 @@ function DataGrid({
2530
2839
  )
2531
2840
  ] })
2532
2841
  ] }),
2533
- viewMode === "grid" && /* @__PURE__ */ jsxs4("div", { ref: tableContainerRef, className: "vpg-grid-container", tabIndex: 0, children: [
2534
- loading && /* @__PURE__ */ jsxs4("div", { className: "vpg-loading", children: [
2535
- /* @__PURE__ */ jsx4("div", { className: "vpg-spinner" }),
2536
- /* @__PURE__ */ jsx4("span", { children: "Loading data..." })
2842
+ viewMode === "grid" && /* @__PURE__ */ jsxs5("div", { ref: tableContainerRef, className: "vpg-grid-container", tabIndex: 0, children: [
2843
+ loading && /* @__PURE__ */ jsxs5("div", { className: "vpg-loading", children: [
2844
+ /* @__PURE__ */ jsx5("div", { className: "vpg-spinner" }),
2845
+ /* @__PURE__ */ jsx5("span", { children: "Loading data..." })
2537
2846
  ] }),
2538
- !loading && data.length === 0 && /* @__PURE__ */ jsxs4("div", { className: "vpg-empty", children: [
2539
- /* @__PURE__ */ jsx4("div", { className: "vpg-empty-icon", children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2847
+ !loading && data.length === 0 && /* @__PURE__ */ jsxs5("div", { className: "vpg-empty", children: [
2848
+ /* @__PURE__ */ jsx5("div", { className: "vpg-empty-icon", children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2540
2849
  "path",
2541
2850
  {
2542
2851
  strokeLinecap: "round",
@@ -2545,10 +2854,10 @@ function DataGrid({
2545
2854
  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"
2546
2855
  }
2547
2856
  ) }) }),
2548
- /* @__PURE__ */ jsx4("span", { children: "No data available" })
2857
+ /* @__PURE__ */ jsx5("span", { children: "No data available" })
2549
2858
  ] }),
2550
- !loading && data.length > 0 && filteredRowCount === 0 && /* @__PURE__ */ jsxs4("div", { className: "vpg-empty", children: [
2551
- /* @__PURE__ */ jsx4("div", { className: "vpg-empty-icon vpg-warning", children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
2859
+ !loading && data.length > 0 && filteredRowCount === 0 && /* @__PURE__ */ jsxs5("div", { className: "vpg-empty", children: [
2860
+ /* @__PURE__ */ jsx5("div", { className: "vpg-empty-icon vpg-warning", children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-lg", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2552
2861
  "path",
2553
2862
  {
2554
2863
  strokeLinecap: "round",
@@ -2557,11 +2866,11 @@ function DataGrid({
2557
2866
  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"
2558
2867
  }
2559
2868
  ) }) }),
2560
- /* @__PURE__ */ jsx4("span", { children: "No matching records" }),
2561
- /* @__PURE__ */ jsx4("button", { className: "vpg-clear-link", onClick: clearAllFilters, children: "Clear all filters" })
2869
+ /* @__PURE__ */ jsx5("span", { children: "No matching records" }),
2870
+ /* @__PURE__ */ jsx5("button", { className: "vpg-clear-link", onClick: clearAllFilters, children: "Clear all filters" })
2562
2871
  ] }),
2563
- !loading && filteredRowCount > 0 && /* @__PURE__ */ jsx4("div", { className: "vpg-table-wrapper", children: /* @__PURE__ */ jsxs4("table", { className: "vpg-table", style: { minWidth: `${totalTableWidth}px` }, children: [
2564
- /* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsx4("tr", { children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ jsxs4(
2872
+ !loading && filteredRowCount > 0 && /* @__PURE__ */ jsx5("div", { className: "vpg-table-wrapper", children: /* @__PURE__ */ jsxs5("table", { className: "vpg-table", style: { minWidth: `${totalTableWidth}px` }, children: [
2873
+ /* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsx5("tr", { children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ jsxs5(
2565
2874
  "th",
2566
2875
  {
2567
2876
  className: `vpg-header-cell ${hasActiveFilter(colId) ? "vpg-has-filter" : ""} ${getSortDirection(colId) !== null ? "vpg-is-sorted" : ""} ${activeFilterColumn === colId ? "vpg-is-active" : ""}`,
@@ -2576,16 +2885,16 @@ function DataGrid({
2576
2885
  }
2577
2886
  },
2578
2887
  children: [
2579
- /* @__PURE__ */ jsxs4("div", { className: "vpg-header-content", children: [
2580
- /* @__PURE__ */ jsx4("span", { className: "vpg-header-text", children: colId }),
2581
- /* @__PURE__ */ jsxs4("div", { className: "vpg-header-icons", children: [
2582
- getSortDirection(colId) && /* @__PURE__ */ jsx4("span", { className: "vpg-sort-indicator", children: getSortDirection(colId) === "asc" ? /* @__PURE__ */ jsx4(
2888
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-header-content", children: [
2889
+ /* @__PURE__ */ jsx5("span", { className: "vpg-header-text", children: colId }),
2890
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-header-icons", children: [
2891
+ getSortDirection(colId) && /* @__PURE__ */ jsx5("span", { className: "vpg-sort-indicator", children: getSortDirection(colId) === "asc" ? /* @__PURE__ */ jsx5(
2583
2892
  "svg",
2584
2893
  {
2585
2894
  className: "vpg-icon-sm",
2586
2895
  fill: "currentColor",
2587
2896
  viewBox: "0 0 20 20",
2588
- children: /* @__PURE__ */ jsx4(
2897
+ children: /* @__PURE__ */ jsx5(
2589
2898
  "path",
2590
2899
  {
2591
2900
  fillRule: "evenodd",
@@ -2594,13 +2903,13 @@ function DataGrid({
2594
2903
  }
2595
2904
  )
2596
2905
  }
2597
- ) : /* @__PURE__ */ jsx4(
2906
+ ) : /* @__PURE__ */ jsx5(
2598
2907
  "svg",
2599
2908
  {
2600
2909
  className: "vpg-icon-sm",
2601
2910
  fill: "currentColor",
2602
2911
  viewBox: "0 0 20 20",
2603
- children: /* @__PURE__ */ jsx4(
2912
+ children: /* @__PURE__ */ jsx5(
2604
2913
  "path",
2605
2914
  {
2606
2915
  fillRule: "evenodd",
@@ -2610,13 +2919,13 @@ function DataGrid({
2610
2919
  )
2611
2920
  }
2612
2921
  ) }),
2613
- hasActiveFilter(colId) && /* @__PURE__ */ jsx4("span", { className: "vpg-filter-indicator", children: /* @__PURE__ */ jsx4(
2922
+ hasActiveFilter(colId) && /* @__PURE__ */ jsx5("span", { className: "vpg-filter-indicator", children: /* @__PURE__ */ jsx5(
2614
2923
  "svg",
2615
2924
  {
2616
2925
  className: "vpg-icon-xs",
2617
2926
  fill: "currentColor",
2618
2927
  viewBox: "0 0 20 20",
2619
- children: /* @__PURE__ */ jsx4(
2928
+ children: /* @__PURE__ */ jsx5(
2620
2929
  "path",
2621
2930
  {
2622
2931
  fillRule: "evenodd",
@@ -2626,14 +2935,14 @@ function DataGrid({
2626
2935
  )
2627
2936
  }
2628
2937
  ) }),
2629
- /* @__PURE__ */ jsx4("span", { className: "vpg-dropdown-arrow", title: "Filter & Sort", children: /* @__PURE__ */ jsx4(
2938
+ /* @__PURE__ */ jsx5("span", { className: "vpg-dropdown-arrow", title: "Filter & Sort", children: /* @__PURE__ */ jsx5(
2630
2939
  "svg",
2631
2940
  {
2632
2941
  className: "vpg-icon-sm",
2633
2942
  fill: "none",
2634
2943
  stroke: "currentColor",
2635
2944
  viewBox: "0 0 24 24",
2636
- children: /* @__PURE__ */ jsx4(
2945
+ children: /* @__PURE__ */ jsx5(
2637
2946
  "path",
2638
2947
  {
2639
2948
  strokeLinecap: "round",
@@ -2646,7 +2955,7 @@ function DataGrid({
2646
2955
  ) })
2647
2956
  ] })
2648
2957
  ] }),
2649
- enableColumnResize && /* @__PURE__ */ jsx4(
2958
+ enableColumnResize && /* @__PURE__ */ jsx5(
2650
2959
  "div",
2651
2960
  {
2652
2961
  className: "vpg-resize-handle",
@@ -2657,7 +2966,7 @@ function DataGrid({
2657
2966
  },
2658
2967
  colId
2659
2968
  )) }) }),
2660
- /* @__PURE__ */ jsx4("tbody", { ref: tableBodyRef, children: paginatedRows.map((row, rowIndex) => /* @__PURE__ */ jsx4("tr", { className: "vpg-row", children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ jsx4(
2969
+ /* @__PURE__ */ jsx5("tbody", { ref: tableBodyRef, children: paginatedRows.map((row, rowIndex) => /* @__PURE__ */ jsx5("tr", { className: "vpg-row", children: columnKeys.map((colId, colIndex) => /* @__PURE__ */ jsx5(
2661
2970
  "td",
2662
2971
  {
2663
2972
  className: `vpg-cell ${isCellSelected(rowIndex, colIndex) ? "vpg-selected" : ""} ${getColumnStats(colId).type === "number" ? "vpg-is-number" : ""}`,
@@ -2675,8 +2984,8 @@ function DataGrid({
2675
2984
  )) }, row.id)) })
2676
2985
  ] }) })
2677
2986
  ] }),
2678
- viewMode === "pivot" && /* @__PURE__ */ jsxs4("div", { className: "vpg-pivot-container", children: [
2679
- showPivotConfig && canUsePivot && /* @__PURE__ */ jsx4("div", { className: "vpg-pivot-config-panel", children: /* @__PURE__ */ jsx4(
2987
+ viewMode === "pivot" && /* @__PURE__ */ jsxs5("div", { className: "vpg-pivot-container", children: [
2988
+ showPivotConfig && canUsePivot && /* @__PURE__ */ jsx5("div", { className: "vpg-pivot-config-panel", children: /* @__PURE__ */ jsx5(
2680
2989
  PivotConfig,
2681
2990
  {
2682
2991
  availableFields: pivotAvailableFields,
@@ -2685,6 +2994,7 @@ function DataGrid({
2685
2994
  valueFields: pivotValueFields,
2686
2995
  showRowTotals: pivotShowRowTotals,
2687
2996
  showColumnTotals: pivotShowColumnTotals,
2997
+ calculatedFields: pivotCalculatedFields,
2688
2998
  onShowRowTotalsChange: setPivotShowRowTotals,
2689
2999
  onShowColumnTotalsChange: setPivotShowColumnTotals,
2690
3000
  onClearConfig: clearPivotConfig,
@@ -2697,10 +3007,13 @@ function DataGrid({
2697
3007
  onAddColumnField: addColumnField,
2698
3008
  onRemoveColumnField: removeColumnField,
2699
3009
  onAddValueField: addValueField,
2700
- onRemoveValueField: removeValueField
3010
+ onRemoveValueField: removeValueField,
3011
+ onAddCalculatedField: addCalculatedField,
3012
+ onRemoveCalculatedField: removeCalculatedField,
3013
+ onUpdateCalculatedField: addCalculatedField
2701
3014
  }
2702
3015
  ) }),
2703
- /* @__PURE__ */ jsx4("div", { className: `vpg-pivot-main ${!showPivotConfig ? "vpg-full-width" : ""}`, children: /* @__PURE__ */ jsx4(
3016
+ /* @__PURE__ */ jsx5("div", { className: `vpg-pivot-main ${!showPivotConfig ? "vpg-full-width" : ""}`, children: /* @__PURE__ */ jsx5(
2704
3017
  PivotSkeleton,
2705
3018
  {
2706
3019
  rowFields: pivotRowFields,
@@ -2725,44 +3038,44 @@ function DataGrid({
2725
3038
  }
2726
3039
  ) })
2727
3040
  ] }),
2728
- /* @__PURE__ */ jsxs4("div", { className: "vpg-footer", children: [
2729
- /* @__PURE__ */ jsx4("div", { className: "vpg-footer-left", children: viewMode === "grid" ? enablePagination ? /* @__PURE__ */ jsxs4(Fragment2, { children: [
2730
- /* @__PURE__ */ jsxs4("span", { children: [
3041
+ /* @__PURE__ */ jsxs5("div", { className: "vpg-footer", children: [
3042
+ /* @__PURE__ */ jsx5("div", { className: "vpg-footer-left", children: viewMode === "grid" ? enablePagination ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3043
+ /* @__PURE__ */ jsxs5("span", { children: [
2731
3044
  ((currentPage - 1) * pageSize + 1).toLocaleString(),
2732
3045
  "-",
2733
3046
  Math.min(currentPage * pageSize, totalSearchedRows).toLocaleString()
2734
3047
  ] }),
2735
- /* @__PURE__ */ jsx4("span", { className: "vpg-separator", children: "of" }),
2736
- /* @__PURE__ */ jsx4("span", { children: totalSearchedRows.toLocaleString() }),
2737
- totalSearchedRows !== totalRowCount && /* @__PURE__ */ jsxs4("span", { className: "vpg-filtered-note", children: [
3048
+ /* @__PURE__ */ jsx5("span", { className: "vpg-separator", children: "of" }),
3049
+ /* @__PURE__ */ jsx5("span", { children: totalSearchedRows.toLocaleString() }),
3050
+ totalSearchedRows !== totalRowCount && /* @__PURE__ */ jsxs5("span", { className: "vpg-filtered-note", children: [
2738
3051
  "(",
2739
3052
  totalRowCount.toLocaleString(),
2740
3053
  " total)"
2741
3054
  ] })
2742
- ] }) : filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount ? /* @__PURE__ */ jsxs4("span", { children: [
3055
+ ] }) : filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount ? /* @__PURE__ */ jsxs5("span", { children: [
2743
3056
  totalRowCount.toLocaleString(),
2744
3057
  " records"
2745
- ] }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
2746
- /* @__PURE__ */ jsx4("span", { className: "vpg-filtered-count", children: totalSearchedRows.toLocaleString() }),
2747
- /* @__PURE__ */ jsx4("span", { className: "vpg-separator", children: "of" }),
2748
- /* @__PURE__ */ jsx4("span", { children: totalRowCount.toLocaleString() }),
2749
- /* @__PURE__ */ jsx4("span", { className: "vpg-separator", children: "records" })
2750
- ] }) : /* @__PURE__ */ jsxs4(Fragment2, { children: [
2751
- /* @__PURE__ */ jsx4("span", { className: "vpg-pivot-label", children: "Pivot Table" }),
2752
- /* @__PURE__ */ jsx4("span", { className: "vpg-separator", children: "\u2022" }),
2753
- /* @__PURE__ */ jsxs4("span", { children: [
3058
+ ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3059
+ /* @__PURE__ */ jsx5("span", { className: "vpg-filtered-count", children: totalSearchedRows.toLocaleString() }),
3060
+ /* @__PURE__ */ jsx5("span", { className: "vpg-separator", children: "of" }),
3061
+ /* @__PURE__ */ jsx5("span", { children: totalRowCount.toLocaleString() }),
3062
+ /* @__PURE__ */ jsx5("span", { className: "vpg-separator", children: "records" })
3063
+ ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3064
+ /* @__PURE__ */ jsx5("span", { className: "vpg-pivot-label", children: "Pivot Table" }),
3065
+ /* @__PURE__ */ jsx5("span", { className: "vpg-separator", children: "\u2022" }),
3066
+ /* @__PURE__ */ jsxs5("span", { children: [
2754
3067
  totalRowCount.toLocaleString(),
2755
3068
  " source records"
2756
3069
  ] })
2757
3070
  ] }) }),
2758
- enablePagination && viewMode === "grid" && totalPages > 1 && /* @__PURE__ */ jsxs4("div", { className: "vpg-pagination", children: [
2759
- /* @__PURE__ */ jsx4(
3071
+ enablePagination && viewMode === "grid" && totalPages > 1 && /* @__PURE__ */ jsxs5("div", { className: "vpg-pagination", children: [
3072
+ /* @__PURE__ */ jsx5(
2760
3073
  "button",
2761
3074
  {
2762
3075
  className: "vpg-page-btn",
2763
3076
  disabled: currentPage === 1,
2764
3077
  onClick: () => setCurrentPage(1),
2765
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
3078
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2766
3079
  "path",
2767
3080
  {
2768
3081
  strokeLinecap: "round",
@@ -2773,13 +3086,13 @@ function DataGrid({
2773
3086
  ) })
2774
3087
  }
2775
3088
  ),
2776
- /* @__PURE__ */ jsx4(
3089
+ /* @__PURE__ */ jsx5(
2777
3090
  "button",
2778
3091
  {
2779
3092
  className: "vpg-page-btn",
2780
3093
  disabled: currentPage === 1,
2781
3094
  onClick: () => setCurrentPage((p) => Math.max(1, p - 1)),
2782
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
3095
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2783
3096
  "path",
2784
3097
  {
2785
3098
  strokeLinecap: "round",
@@ -2790,19 +3103,19 @@ function DataGrid({
2790
3103
  ) })
2791
3104
  }
2792
3105
  ),
2793
- /* @__PURE__ */ jsxs4("span", { className: "vpg-page-info", children: [
3106
+ /* @__PURE__ */ jsxs5("span", { className: "vpg-page-info", children: [
2794
3107
  "Page ",
2795
3108
  currentPage,
2796
3109
  " of ",
2797
3110
  totalPages
2798
3111
  ] }),
2799
- /* @__PURE__ */ jsx4(
3112
+ /* @__PURE__ */ jsx5(
2800
3113
  "button",
2801
3114
  {
2802
3115
  className: "vpg-page-btn",
2803
3116
  disabled: currentPage === totalPages,
2804
3117
  onClick: () => setCurrentPage((p) => Math.min(totalPages, p + 1)),
2805
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
3118
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2806
3119
  "path",
2807
3120
  {
2808
3121
  strokeLinecap: "round",
@@ -2813,13 +3126,13 @@ function DataGrid({
2813
3126
  ) })
2814
3127
  }
2815
3128
  ),
2816
- /* @__PURE__ */ jsx4(
3129
+ /* @__PURE__ */ jsx5(
2817
3130
  "button",
2818
3131
  {
2819
3132
  className: "vpg-page-btn",
2820
3133
  disabled: currentPage === totalPages,
2821
3134
  onClick: () => setCurrentPage(totalPages),
2822
- children: /* @__PURE__ */ jsx4("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx4(
3135
+ children: /* @__PURE__ */ jsx5("svg", { className: "vpg-icon-sm", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx5(
2823
3136
  "path",
2824
3137
  {
2825
3138
  strokeLinecap: "round",
@@ -2831,45 +3144,45 @@ function DataGrid({
2831
3144
  }
2832
3145
  )
2833
3146
  ] }),
2834
- viewMode === "grid" && selectionStats && selectionStats.count > 1 && /* @__PURE__ */ jsxs4("div", { className: "vpg-selection-stats", children: [
2835
- /* @__PURE__ */ jsxs4("span", { className: "vpg-stat", children: [
2836
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-label", children: "Count:" }),
2837
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-value", children: selectionStats.count })
3147
+ viewMode === "grid" && selectionStats && selectionStats.count > 1 && /* @__PURE__ */ jsxs5("div", { className: "vpg-selection-stats", children: [
3148
+ /* @__PURE__ */ jsxs5("span", { className: "vpg-stat", children: [
3149
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-label", children: "Count:" }),
3150
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-value", children: selectionStats.count })
2838
3151
  ] }),
2839
- selectionStats.numericCount > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
2840
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-divider", children: "|" }),
2841
- /* @__PURE__ */ jsxs4("span", { className: "vpg-stat", children: [
2842
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-label", children: "Sum:" }),
2843
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.sum) })
3152
+ selectionStats.numericCount > 0 && /* @__PURE__ */ jsxs5(Fragment3, { children: [
3153
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-divider", children: "|" }),
3154
+ /* @__PURE__ */ jsxs5("span", { className: "vpg-stat", children: [
3155
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-label", children: "Sum:" }),
3156
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.sum) })
2844
3157
  ] }),
2845
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-divider", children: "|" }),
2846
- /* @__PURE__ */ jsxs4("span", { className: "vpg-stat", children: [
2847
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-label", children: "Avg:" }),
2848
- /* @__PURE__ */ jsx4("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.avg) })
3158
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-divider", children: "|" }),
3159
+ /* @__PURE__ */ jsxs5("span", { className: "vpg-stat", children: [
3160
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-label", children: "Avg:" }),
3161
+ /* @__PURE__ */ jsx5("span", { className: "vpg-stat-value", children: formatStatValue(selectionStats.avg) })
2849
3162
  ] })
2850
3163
  ] })
2851
3164
  ] }),
2852
- /* @__PURE__ */ jsx4("div", { className: "vpg-footer-right", children: isDemo ? /* @__PURE__ */ jsxs4("div", { className: "vpg-demo-banner", children: [
2853
- /* @__PURE__ */ jsx4("span", { className: "vpg-demo-badge", children: "DEMO" }),
2854
- /* @__PURE__ */ jsx4("span", { children: "Pro features enabled" }),
2855
- /* @__PURE__ */ jsx4("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", children: "Get License \u2192" })
2856
- ] }) : showWatermark ? /* @__PURE__ */ jsx4("span", { className: "vpg-watermark-inline", children: /* @__PURE__ */ jsxs4("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: [
2857
- /* @__PURE__ */ jsxs4("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: [
2858
- /* @__PURE__ */ jsx4("rect", { x: "3", y: "3", width: "7", height: "7" }),
2859
- /* @__PURE__ */ jsx4("rect", { x: "14", y: "3", width: "7", height: "7" }),
2860
- /* @__PURE__ */ jsx4("rect", { x: "14", y: "14", width: "7", height: "7" }),
2861
- /* @__PURE__ */ jsx4("rect", { x: "3", y: "14", width: "7", height: "7" })
3165
+ /* @__PURE__ */ jsx5("div", { className: "vpg-footer-right", children: isDemo ? /* @__PURE__ */ jsxs5("div", { className: "vpg-demo-banner", children: [
3166
+ /* @__PURE__ */ jsx5("span", { className: "vpg-demo-badge", children: "DEMO" }),
3167
+ /* @__PURE__ */ jsx5("span", { children: "Pro features enabled" }),
3168
+ /* @__PURE__ */ jsx5("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", children: "Get License \u2192" })
3169
+ ] }) : showWatermark ? /* @__PURE__ */ jsx5("span", { className: "vpg-watermark-inline", children: /* @__PURE__ */ jsxs5("a", { href: "https://tiny-pivot.com", target: "_blank", rel: "noopener noreferrer", children: [
3170
+ /* @__PURE__ */ jsxs5("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: [
3171
+ /* @__PURE__ */ jsx5("rect", { x: "3", y: "3", width: "7", height: "7" }),
3172
+ /* @__PURE__ */ jsx5("rect", { x: "14", y: "3", width: "7", height: "7" }),
3173
+ /* @__PURE__ */ jsx5("rect", { x: "14", y: "14", width: "7", height: "7" }),
3174
+ /* @__PURE__ */ jsx5("rect", { x: "3", y: "14", width: "7", height: "7" })
2862
3175
  ] }),
2863
3176
  "Powered by TinyPivot"
2864
3177
  ] }) }) : null })
2865
3178
  ] }),
2866
- enableVerticalResize && /* @__PURE__ */ jsx4("div", { className: "vpg-vertical-resize-handle", onMouseDown: startVerticalResize, children: /* @__PURE__ */ jsxs4("div", { className: "vpg-resize-grip", children: [
2867
- /* @__PURE__ */ jsx4("span", {}),
2868
- /* @__PURE__ */ jsx4("span", {}),
2869
- /* @__PURE__ */ jsx4("span", {})
3179
+ enableVerticalResize && /* @__PURE__ */ jsx5("div", { className: "vpg-vertical-resize-handle", onMouseDown: startVerticalResize, children: /* @__PURE__ */ jsxs5("div", { className: "vpg-resize-grip", children: [
3180
+ /* @__PURE__ */ jsx5("span", {}),
3181
+ /* @__PURE__ */ jsx5("span", {}),
3182
+ /* @__PURE__ */ jsx5("span", {})
2870
3183
  ] }) }),
2871
- activeFilterColumn && createPortal(
2872
- /* @__PURE__ */ jsx4(
3184
+ activeFilterColumn && createPortal2(
3185
+ /* @__PURE__ */ jsx5(
2873
3186
  "div",
2874
3187
  {
2875
3188
  className: "vpg-filter-portal",
@@ -2880,7 +3193,7 @@ function DataGrid({
2880
3193
  maxHeight: `${filterDropdownPosition.maxHeight}px`,
2881
3194
  zIndex: 9999
2882
3195
  },
2883
- children: /* @__PURE__ */ jsx4(
3196
+ children: /* @__PURE__ */ jsx5(
2884
3197
  ColumnFilter,
2885
3198
  {
2886
3199
  columnId: activeFilterColumn,