@smallwebco/tinypivot-react 1.0.47 → 1.0.49

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
@@ -425,12 +425,11 @@ function usePivotTable(data) {
425
425
  }, [currentStorageKey, rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields]);
426
426
  const addRowField = useCallback3(
427
427
  (field) => {
428
- if (!requirePro("Pivot Table - Row Fields")) return;
429
428
  if (!rowFields.includes(field)) {
430
429
  setRowFieldsState((prev) => [...prev, field]);
431
430
  }
432
431
  },
433
- [rowFields, requirePro]
432
+ [rowFields]
434
433
  );
435
434
  const removeRowField = useCallback3((field) => {
436
435
  setRowFieldsState((prev) => prev.filter((f) => f !== field));
@@ -440,12 +439,11 @@ function usePivotTable(data) {
440
439
  }, []);
441
440
  const addColumnField = useCallback3(
442
441
  (field) => {
443
- if (!requirePro("Pivot Table - Column Fields")) return;
444
442
  if (!columnFields.includes(field)) {
445
443
  setColumnFieldsState((prev) => [...prev, field]);
446
444
  }
447
445
  },
448
- [columnFields, requirePro]
446
+ [columnFields]
449
447
  );
450
448
  const removeColumnField = useCallback3((field) => {
451
449
  setColumnFieldsState((prev) => prev.filter((f) => f !== field));
@@ -455,7 +453,9 @@ function usePivotTable(data) {
455
453
  }, []);
456
454
  const addValueField = useCallback3(
457
455
  (field, aggregation = "sum") => {
458
- if (!requirePro("Pivot Table - Value Fields")) return;
456
+ if (aggregation !== "sum" && !requirePro(`${aggregation} aggregation`)) {
457
+ return;
458
+ }
459
459
  setValueFields((prev) => {
460
460
  if (prev.some((v) => v.field === field && v.aggregation === aggregation)) {
461
461
  return prev;
@@ -1538,6 +1538,9 @@ function CalculatedFieldModal({
1538
1538
 
1539
1539
  // src/components/PivotConfig.tsx
1540
1540
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1541
+ function aggregationRequiresPro(agg) {
1542
+ return agg !== "sum";
1543
+ }
1541
1544
  function getFieldIcon(type, isCalculated) {
1542
1545
  if (isCalculated) return "\u0192";
1543
1546
  switch (type) {
@@ -1577,6 +1580,10 @@ function PivotConfig({
1577
1580
  const [fieldSearch, setFieldSearch] = useState8("");
1578
1581
  const [showCalcModal, setShowCalcModal] = useState8(false);
1579
1582
  const [editingCalcField, setEditingCalcField] = useState8(null);
1583
+ const { canUseAdvancedAggregations } = useLicense();
1584
+ const isAggregationAvailable = useCallback8((agg) => {
1585
+ return !aggregationRequiresPro(agg) || canUseAdvancedAggregations;
1586
+ }, [canUseAdvancedAggregations]);
1580
1587
  const numericFieldNames = useMemo8(
1581
1588
  () => availableFields.filter((f) => f.isNumeric).map((f) => f.field),
1582
1589
  [availableFields]
@@ -1642,9 +1649,13 @@ function PivotConfig({
1642
1649
  );
1643
1650
  const handleAggregationChange = useCallback8(
1644
1651
  (field, currentAgg, newAgg) => {
1652
+ if (!isAggregationAvailable(newAgg)) {
1653
+ console.warn(`[TinyPivot] "${newAgg}" aggregation requires a Pro license. Visit https://tiny-pivot.com/#pricing to upgrade.`);
1654
+ return;
1655
+ }
1645
1656
  onUpdateAggregation(field, currentAgg, newAgg);
1646
1657
  },
1647
- [onUpdateAggregation]
1658
+ [onUpdateAggregation, isAggregationAvailable]
1648
1659
  );
1649
1660
  const toggleRowColumn = useCallback8(
1650
1661
  (field, currentAssignment) => {
@@ -1782,11 +1793,20 @@ function PivotConfig({
1782
1793
  );
1783
1794
  },
1784
1795
  onClick: (e) => e.stopPropagation(),
1785
- children: AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ jsxs4("option", { value: agg.value, children: [
1786
- agg.symbol,
1787
- " ",
1788
- agg.label
1789
- ] }, agg.value))
1796
+ children: AGGREGATION_OPTIONS.map((agg) => /* @__PURE__ */ jsxs4(
1797
+ "option",
1798
+ {
1799
+ value: agg.value,
1800
+ disabled: aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations,
1801
+ children: [
1802
+ agg.symbol,
1803
+ " ",
1804
+ agg.label,
1805
+ aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations ? " (Pro)" : ""
1806
+ ]
1807
+ },
1808
+ agg.value
1809
+ ))
1790
1810
  }
1791
1811
  ),
1792
1812
  /* @__PURE__ */ jsx4(
@@ -2285,6 +2305,14 @@ function PivotSkeleton({
2285
2305
  [reorderDropTarget]
2286
2306
  );
2287
2307
  const currentFontSize = fontSize;
2308
+ const rowHeaderWidth = 180;
2309
+ const rowHeaderColWidth = useMemo9(() => {
2310
+ const numCols = Math.max(rowFields.length, 1);
2311
+ return Math.max(rowHeaderWidth / numCols, 80);
2312
+ }, [rowFields.length]);
2313
+ const getRowHeaderLeftOffset = useCallback9((fieldIdx) => {
2314
+ return fieldIdx * rowHeaderColWidth;
2315
+ }, [rowHeaderColWidth]);
2288
2316
  return /* @__PURE__ */ jsxs5(
2289
2317
  "div",
2290
2318
  {
@@ -2565,18 +2593,20 @@ function PivotSkeleton({
2565
2593
  ] }) }),
2566
2594
  isConfigured && pivotResult && /* @__PURE__ */ jsx5("div", { className: "vpg-table-container", children: /* @__PURE__ */ jsxs5("table", { className: "vpg-pivot-table", children: [
2567
2595
  /* @__PURE__ */ jsx5("thead", { children: columnHeaderCells.map((headerRow, levelIdx) => /* @__PURE__ */ jsxs5("tr", { className: "vpg-column-header-row", children: [
2568
- levelIdx === 0 && /* @__PURE__ */ jsx5(
2596
+ levelIdx === 0 && (rowFields.length > 0 ? rowFields : ["Rows"]).map((field, fieldIdx) => /* @__PURE__ */ jsx5(
2569
2597
  "th",
2570
2598
  {
2571
2599
  className: "vpg-row-header-label",
2572
2600
  rowSpan: columnHeaderCells.length,
2601
+ style: { width: `${rowHeaderColWidth}px`, minWidth: "80px", left: `${getRowHeaderLeftOffset(fieldIdx)}px` },
2573
2602
  onClick: () => toggleSort("row"),
2574
2603
  children: /* @__PURE__ */ jsxs5("div", { className: "vpg-header-content", children: [
2575
- /* @__PURE__ */ jsx5("span", { children: rowFields.join(" / ") || "Rows" }),
2576
- /* @__PURE__ */ jsx5("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2604
+ /* @__PURE__ */ jsx5("span", { children: field }),
2605
+ (fieldIdx === rowFields.length - 1 || rowFields.length === 0) && /* @__PURE__ */ jsx5("span", { className: `vpg-sort-indicator ${sortTarget === "row" ? "active" : ""}`, children: sortTarget === "row" ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
2577
2606
  ] })
2578
- }
2579
- ),
2607
+ },
2608
+ `row-header-${fieldIdx}`
2609
+ )),
2580
2610
  headerRow.map((cell, idx) => /* @__PURE__ */ jsx5(
2581
2611
  "th",
2582
2612
  {
@@ -2594,7 +2624,15 @@ function PivotSkeleton({
2594
2624
  ] }, `header-${levelIdx}`)) }),
2595
2625
  /* @__PURE__ */ jsxs5("tbody", { children: [
2596
2626
  sortedRowIndices.map((sortedIdx) => /* @__PURE__ */ jsxs5("tr", { className: "vpg-data-row", children: [
2597
- /* @__PURE__ */ jsx5("th", { className: "vpg-row-header-cell", children: pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ jsx5("span", { className: "vpg-row-value", children: val }, idx)) }),
2627
+ pivotResult.rowHeaders[sortedIdx].map((val, idx) => /* @__PURE__ */ jsx5(
2628
+ "th",
2629
+ {
2630
+ className: "vpg-row-header-cell",
2631
+ style: { width: `${rowHeaderColWidth}px`, minWidth: "80px", left: `${getRowHeaderLeftOffset(idx)}px` },
2632
+ children: val
2633
+ },
2634
+ `row-${sortedIdx}-${idx}`
2635
+ )),
2598
2636
  pivotResult.data[sortedIdx].map((cell, colIdx) => {
2599
2637
  const displayRowIdx = sortedRowIndices.indexOf(sortedIdx);
2600
2638
  return /* @__PURE__ */ jsx5(
@@ -2611,7 +2649,15 @@ function PivotSkeleton({
2611
2649
  pivotResult.rowTotals[sortedIdx] && /* @__PURE__ */ jsx5("td", { className: "vpg-data-cell vpg-total-cell", children: pivotResult.rowTotals[sortedIdx].formattedValue })
2612
2650
  ] }, sortedIdx)),
2613
2651
  pivotResult.columnTotals.length > 0 && /* @__PURE__ */ jsxs5("tr", { className: "vpg-totals-row", children: [
2614
- /* @__PURE__ */ jsx5("th", { className: "vpg-row-header-cell vpg-total-label", children: "Total" }),
2652
+ /* @__PURE__ */ jsx5(
2653
+ "th",
2654
+ {
2655
+ className: "vpg-row-header-cell vpg-total-label",
2656
+ colSpan: Math.max(rowFields.length, 1),
2657
+ style: { width: `${rowHeaderWidth}px` },
2658
+ children: "Total"
2659
+ }
2660
+ ),
2615
2661
  pivotResult.columnTotals.map((cell, colIdx) => /* @__PURE__ */ jsx5("td", { className: "vpg-data-cell vpg-total-cell", children: cell.formattedValue }, colIdx)),
2616
2662
  pivotResult.rowTotals.length > 0 && /* @__PURE__ */ jsx5("td", { className: "vpg-data-cell vpg-grand-total-cell", children: pivotResult.grandTotal.formattedValue })
2617
2663
  ] })
@@ -2689,7 +2735,7 @@ function DataGrid({
2689
2735
  onExport,
2690
2736
  onCopy
2691
2737
  }) {
2692
- const { showWatermark, canUsePivot, isDemo } = useLicense();
2738
+ const { showWatermark, canUsePivot, isDemo, isPro } = useLicense();
2693
2739
  const currentTheme = useMemo10(() => {
2694
2740
  if (theme === "auto") {
2695
2741
  return window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -3396,11 +3442,11 @@ function DataGrid({
3396
3442
  ) })
3397
3443
  }
3398
3444
  ),
3399
- enableExport && (viewMode === "grid" || viewMode === "pivot" && pivotIsConfigured) && /* @__PURE__ */ jsxs6(
3445
+ enableExport && viewMode === "grid" && /* @__PURE__ */ jsxs6(
3400
3446
  "button",
3401
3447
  {
3402
3448
  className: "vpg-export-btn",
3403
- title: viewMode === "pivot" ? "Export Pivot to CSV" : "Export to CSV",
3449
+ title: "Export to CSV",
3404
3450
  onClick: handleExport,
3405
3451
  children: [
3406
3452
  /* @__PURE__ */ jsx6("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6(
@@ -3412,8 +3458,29 @@ function DataGrid({
3412
3458
  d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
3413
3459
  }
3414
3460
  ) }),
3415
- "Export",
3416
- viewMode === "pivot" ? " Pivot" : ""
3461
+ "Export"
3462
+ ]
3463
+ }
3464
+ ),
3465
+ enableExport && viewMode === "pivot" && pivotIsConfigured && /* @__PURE__ */ jsxs6(
3466
+ "button",
3467
+ {
3468
+ className: `vpg-export-btn ${!isPro ? "vpg-export-btn-disabled" : ""}`,
3469
+ disabled: !isPro,
3470
+ title: isPro ? "Export Pivot to CSV" : "Export Pivot to CSV (Pro feature)",
3471
+ onClick: () => isPro && handleExport(),
3472
+ children: [
3473
+ /* @__PURE__ */ jsx6("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx6(
3474
+ "path",
3475
+ {
3476
+ strokeLinecap: "round",
3477
+ strokeLinejoin: "round",
3478
+ strokeWidth: 2,
3479
+ d: "M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
3480
+ }
3481
+ ) }),
3482
+ "Export Pivot",
3483
+ !isPro ? " (Pro)" : ""
3417
3484
  ]
3418
3485
  }
3419
3486
  )