@smallwebco/tinypivot-react 1.0.74 → 1.0.80

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/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # @smallwebco/tinypivot-react
2
2
 
3
- A lightweight data grid with pivot tables, charts, and optional AI-powered data exploration for React. **Under 40KB gzipped** — 10x smaller than AG Grid.
3
+ A lightweight data grid with free pivot tables, Pro charts, and optional AI-powered data exploration for React. **Under 40KB gzipped** — 10x smaller than AG Grid.
4
4
 
5
5
  **[Live Demo](https://tiny-pivot.com)** · **[Buy License](https://tiny-pivot.com/#pricing)**
6
6
 
7
7
  ## Why TinyPivot?
8
8
 
9
9
  - **Lightweight**: Under 40KB gzipped vs 500KB+ for AG Grid
10
- - **Batteries Included**: Pivot tables, 6 chart types, Excel-like features out of the box
10
+ - **Free Pivot Tables**: Sum aggregations, totals, and calculated fields included
11
+ - **Pro Upgrade**: Advanced aggregations, charts, AI Data Analyst, and no watermark
11
12
  - **AI Data Analyst** (Pro): Natural language queries with BYOK — use your own OpenAI/Anthropic key
12
- - **One-Time License**: No subscriptions — pay once, use forever
13
+ - **Lifetime License**: No subscriptions — buy once, use forever
13
14
 
14
15
  ## Installation
15
16
 
@@ -44,6 +45,96 @@ export default function App() {
44
45
  }
45
46
  ```
46
47
 
48
+ ## Theming
49
+
50
+ TinyPivot ships 22 themes — 2 neutral (`light`, `dark`) plus 10 brand themes each with a light and dark variant. Themes are applied via the `theme` prop on `DataGrid`.
51
+
52
+ ### Quick start
53
+
54
+ ```tsx
55
+ <DataGrid data={data} theme="slate-dark" />
56
+ ```
57
+
58
+ `theme="auto"` resolves to `'light'` or `'dark'` based on the user's system preference (`prefers-color-scheme`).
59
+
60
+ ### Available themes
61
+
62
+ | Theme | Accent | Vibe |
63
+ |---|---|---|
64
+ | `light` / `dark` / `auto` | indigo / violet | TinyPivot defaults — neutral cool grays |
65
+ | `slate` / `slate-dark` | `#4f46e5` indigo | Linear / Stripe — cool neutral |
66
+ | `zinc` / `zinc-dark` | near-mono | Vercel / Anthropic — minimalist |
67
+ | `indigo` / `indigo-dark` | `#6366f1` vivid indigo | Premium SaaS |
68
+ | `violet` / `violet-dark` | `#8b5cf6` purple | Data viz / AI tools |
69
+ | `emerald` / `emerald-dark` | `#10b981` green | Fintech / finance |
70
+ | `sky` / `sky-dark` | `#0ea5e9` light blue | Productivity / airy |
71
+ | `rose` / `rose-dark` | `#f43f5e` warm pink | Friendly / creator |
72
+ | `amber` / `amber-dark` | `#f59e0b` warm orange | Energy / wellness |
73
+ | `solar` / `solar-dark` | `#b58900` mustard | Solarized-inspired warm cream + dark teal |
74
+ | `mono` / `mono-dark` | `#000` / `#fff` | Editorial — pure grayscale, high contrast |
75
+
76
+ ### Custom themes
77
+
78
+ Brand themes redefine ~25 CSS custom property tokens at the grid root. You can override these in your own CSS to create a custom theme:
79
+
80
+ ```tsx
81
+ import './my-brand.css'
82
+
83
+ <DataGrid data={data} theme="light" className="my-brand" />
84
+ ```
85
+
86
+ ```css
87
+ /* my-brand.css */
88
+ .vpg-data-grid.my-brand {
89
+ --vpg-accent: #ff6b35;
90
+ --vpg-accent-hover: #e55426;
91
+ --vpg-surface-bg: #fafaf7;
92
+ --vpg-surface-panel: #f0eee7;
93
+ /* …override any of the tokens below */
94
+ }
95
+ ```
96
+
97
+ **Token reference** — these are the variables you can override:
98
+
99
+ - **Surfaces**: `--vpg-surface-bg`, `--vpg-surface-panel`, `--vpg-surface-elevated`, `--vpg-surface-hover`, `--vpg-surface-selected`, `--vpg-surface-striped`
100
+ - **Text**: `--vpg-text-primary`, `--vpg-text-secondary`, `--vpg-text-muted`, `--vpg-text-inverse`
101
+ - **Borders**: `--vpg-border-default`, `--vpg-border-strong`, `--vpg-border-subtle`
102
+ - **Accent**: `--vpg-accent`, `--vpg-accent-hover`, `--vpg-accent-soft-bg`, `--vpg-accent-soft-text`, `--vpg-focus-ring`
103
+ - **States**: `--vpg-state-error`, `--vpg-state-warning`, `--vpg-state-success`, `--vpg-state-info`
104
+ - **Scrollbar**: `--vpg-scrollbar-thumb`, `--vpg-scrollbar-track`
105
+
106
+ Custom theme classes layer on top of any preset, so you can start from `theme="dark"` and tweak just the accent, for example.
107
+
108
+ ### Adding a theme switcher
109
+
110
+ Let users pick their own theme — bind a state value to a `<select>`:
111
+
112
+ ```tsx
113
+ import { DataGrid } from '@smallwebco/tinypivot-react'
114
+ import '@smallwebco/tinypivot-react/style.css'
115
+ import { useState } from 'react'
116
+
117
+ type Theme = 'light' | 'dark' | 'slate' | 'slate-dark' | 'emerald' | 'emerald-dark'
118
+
119
+ export function MyGrid({ data }) {
120
+ const [theme, setTheme] = useState<Theme>('dark')
121
+
122
+ return (
123
+ <>
124
+ <select value={theme} onChange={e => setTheme(e.target.value as Theme)}>
125
+ <option value="light">Light</option>
126
+ <option value="dark">Dark</option>
127
+ <option value="slate-dark">Slate (dark)</option>
128
+ <option value="emerald-dark">Emerald (dark)</option>
129
+ {/* …add more themes */}
130
+ </select>
131
+
132
+ <DataGrid data={data} theme={theme} />
133
+ </>
134
+ )
135
+ }
136
+ ```
137
+
47
138
  ## Features
48
139
 
49
140
  | Feature | Free | Pro |
@@ -56,11 +147,12 @@ export default function App() {
56
147
  | Column resizing | ✅ | ✅ |
57
148
  | Clipboard (Ctrl+C) | ✅ | ✅ |
58
149
  | Dark mode | ✅ | ✅ |
150
+ | Pivot table with Sum aggregation | ✅ | ✅ |
151
+ | Row/column totals | ✅ | ✅ |
152
+ | Calculated fields with formulas | ✅ | ✅ |
59
153
  | **AI Data Analyst** (natural language, BYOK) | ❌ | ✅ |
60
154
  | **Chart Builder** (6 chart types) | ❌ | ✅ |
61
- | Pivot table | ❌ | ✅ |
62
- | Aggregations (Sum, Avg, etc.) | ❌ | ✅ |
63
- | Row/column totals | ❌ | ✅ |
155
+ | Advanced aggregations (Count, Avg, Min, Max, Unique, Median, Std Dev, %) | ❌ | ✅ |
64
156
  | No watermark | ❌ | ✅ |
65
157
 
66
158
  ## Props
@@ -70,14 +162,14 @@ export default function App() {
70
162
  | `data` | `Record<string, unknown>[]` | **required** | Array of data objects |
71
163
  | `loading` | `boolean` | `false` | Show loading spinner |
72
164
  | `fontSize` | `'xs' \| 'sm' \| 'base'` | `'xs'` | Font size preset |
73
- | `showPivot` | `boolean` | `true` | Show pivot toggle (Pro) |
165
+ | `showPivot` | `boolean` | `true` | Show pivot toggle |
74
166
  | `enableExport` | `boolean` | `true` | Show CSV export button |
75
167
  | `enableSearch` | `boolean` | `true` | Show global search |
76
168
  | `enablePagination` | `boolean` | `false` | Enable pagination |
77
169
  | `pageSize` | `number` | `50` | Rows per page |
78
170
  | `enableColumnResize` | `boolean` | `true` | Drag to resize columns |
79
171
  | `enableClipboard` | `boolean` | `true` | Ctrl+C to copy cells |
80
- | `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | Color theme |
172
+ | `theme` | `string` | `'light'` | Color theme — see [Theming](#theming) for the full list (22 presets) |
81
173
  | `numberFormat` | `'us' \| 'eu' \| 'plain'` | `'us'` | Number display format: US (1,234.56), EU (1.234,56), plain (1234.56) |
82
174
  | `dateFormat` | `'us' \| 'eu' \| 'iso'` | `'iso'` | Date display format: US (MM/DD/YYYY), EU (DD/MM/YYYY), ISO (YYYY-MM-DD) |
83
175
  | `fieldRoleOverrides` | `Record<string, FieldRole>` | `undefined` | Override auto-detected chart field roles per column (`'dimension'` \| `'measure'` \| `'temporal'`) |
@@ -180,7 +272,7 @@ See the [full documentation](https://github.com/Small-Web-Co/tinypivot) for comp
180
272
 
181
273
  ## License
182
274
 
183
- - **Free Tier**: MIT License for basic grid features
275
+ - **Free Tier**: MIT License for core grid and pivot features
184
276
  - **Pro Features**: Commercial license required
185
277
 
186
278
  **[Purchase at tiny-pivot.com/#pricing](https://tiny-pivot.com/#pricing)**
package/dist/index.cjs CHANGED
@@ -99,14 +99,22 @@ function useAIAnalyst(options) {
99
99
  }
100
100
  }
101
101
  }, [storageKey]);
102
- const [conversation, setConversation] = (0, import_react.useState)(() => loadFromStorage());
102
+ const initialConversationRef = (0, import_react.useRef)(null);
103
+ if (!initialConversationRef.current) {
104
+ initialConversationRef.current = loadFromStorage();
105
+ }
106
+ const [conversation, setConversation] = (0, import_react.useState)(initialConversationRef.current);
103
107
  const [schemas, setSchemas] = (0, import_react.useState)(/* @__PURE__ */ new Map());
104
108
  const [allSchemas, setAllSchemas] = (0, import_react.useState)([]);
105
109
  const [isLoading, setIsLoading] = (0, import_react.useState)(false);
106
110
  const [error, setError] = (0, import_react.useState)(null);
107
- const [lastLoadedData, setLastLoadedData] = (0, import_react.useState)(null);
111
+ const [lastLoadedData, setLastLoadedData] = (0, import_react.useState)(
112
+ () => (0, import_tinypivot_core.getLatestConversationData)(initialConversationRef.current)
113
+ );
108
114
  const [discoveredDataSources, setDiscoveredDataSources] = (0, import_react.useState)([]);
109
115
  const [isLoadingTables, setIsLoadingTables] = (0, import_react.useState)(false);
116
+ const dataSourceLoadPromisesRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
117
+ const hydratedPersistedSelectionRef = (0, import_react.useRef)(false);
110
118
  const effectiveDataSources = (0, import_react.useMemo)(() => {
111
119
  if (config.dataSources && config.dataSources.length > 0) {
112
120
  return config.dataSources;
@@ -251,6 +259,59 @@ function useAIAnalyst(options) {
251
259
  console.warn("Failed to fetch sample data:", err);
252
260
  }
253
261
  }, [onDataLoaded]);
262
+ const loadDataSourceState = (0, import_react.useCallback)(async (dataSource) => {
263
+ const currentConfig = configRef.current;
264
+ if (currentConfig.dataSourceLoader) {
265
+ const { data, schema } = await currentConfig.dataSourceLoader(dataSource.id);
266
+ if (schema) {
267
+ setSchemas((prev) => new Map(prev).set(dataSource.id, schema));
268
+ }
269
+ if (data && data.length > 0) {
270
+ setLastLoadedData(data);
271
+ onDataLoaded?.({
272
+ data,
273
+ query: `SELECT * FROM ${dataSource.table} LIMIT 100`,
274
+ dataSourceId: dataSource.id,
275
+ rowCount: data.length
276
+ });
277
+ }
278
+ return;
279
+ }
280
+ if (currentConfig.demoMode) {
281
+ const demoSchema = (0, import_tinypivot_core.getDemoSchema)(dataSource.id);
282
+ if (demoSchema) {
283
+ setSchemas((prev) => new Map(prev).set(dataSource.id, demoSchema));
284
+ }
285
+ const initialData = (0, import_tinypivot_core.getInitialDemoData)(dataSource.id);
286
+ if (initialData) {
287
+ setLastLoadedData(initialData);
288
+ onDataLoaded?.({
289
+ data: initialData,
290
+ query: `SELECT * FROM ${dataSource.table} LIMIT 10`,
291
+ dataSourceId: dataSource.id,
292
+ rowCount: initialData.length
293
+ });
294
+ }
295
+ return;
296
+ }
297
+ if (currentConfig.endpoint) {
298
+ await fetchSchema(dataSource);
299
+ await fetchSampleData(dataSource);
300
+ }
301
+ }, [fetchSchema, fetchSampleData, onDataLoaded]);
302
+ const ensureDataSourceState = (0, import_react.useCallback)(async (dataSource) => {
303
+ const existingLoad = dataSourceLoadPromisesRef.current.get(dataSource.id);
304
+ if (existingLoad) {
305
+ return existingLoad;
306
+ }
307
+ const loadPromise = loadDataSourceState(dataSource).catch((err) => {
308
+ console.warn("Failed to load data source:", err);
309
+ }).finally(() => {
310
+ dataSourceLoadPromisesRef.current.delete(dataSource.id);
311
+ });
312
+ dataSourceLoadPromisesRef.current.set(dataSource.id, loadPromise);
313
+ return loadPromise;
314
+ }, [loadDataSourceState]);
254
315
  const selectDataSource = (0, import_react.useCallback)(async (dataSourceId) => {
255
316
  const dataSource = effectiveDataSources.find((ds) => ds.id === dataSourceId);
256
317
  if (!dataSource) {
@@ -270,44 +331,30 @@ What would you like to know about this data?`
270
331
  onConversationUpdate?.({ conversation: withMessage });
271
332
  return withMessage;
272
333
  });
273
- if (configRef.current.dataSourceLoader) {
274
- try {
275
- const { data, schema } = await configRef.current.dataSourceLoader(dataSourceId);
276
- if (schema) {
277
- setSchemas((prev) => new Map(prev).set(dataSourceId, schema));
278
- }
279
- if (data && data.length > 0) {
280
- setLastLoadedData(data);
281
- onDataLoaded?.({
282
- data,
283
- query: `SELECT * FROM ${dataSource.table} LIMIT 100`,
284
- dataSourceId,
285
- rowCount: data.length
286
- });
287
- }
288
- } catch (err) {
289
- console.warn("Failed to load data source:", err);
290
- }
291
- } else if (configRef.current.demoMode) {
292
- const demoSchema = (0, import_tinypivot_core.getDemoSchema)(dataSourceId);
293
- if (demoSchema) {
294
- setSchemas((prev) => new Map(prev).set(dataSourceId, demoSchema));
295
- }
296
- const initialData = (0, import_tinypivot_core.getInitialDemoData)(dataSourceId);
297
- if (initialData) {
298
- setLastLoadedData(initialData);
299
- onDataLoaded?.({
300
- data: initialData,
301
- query: `SELECT * FROM ${dataSource.table} LIMIT 10`,
302
- dataSourceId,
303
- rowCount: initialData.length
304
- });
305
- }
306
- } else if (configRef.current.endpoint) {
307
- await fetchSchema(dataSource);
308
- await fetchSampleData(dataSource);
334
+ await ensureDataSourceState(dataSource);
335
+ }, [effectiveDataSources, ensureDataSourceState, onConversationUpdate]);
336
+ (0, import_react.useEffect)(() => {
337
+ if (hydratedPersistedSelectionRef.current) {
338
+ return;
339
+ }
340
+ const initialConversation = initialConversationRef.current;
341
+ const initialDataSourceId = initialConversation?.dataSourceId;
342
+ if (!initialDataSourceId) {
343
+ hydratedPersistedSelectionRef.current = true;
344
+ return;
345
+ }
346
+ const dataSource = effectiveDataSources.find((ds) => ds.id === initialDataSourceId);
347
+ if (!dataSource) {
348
+ return;
349
+ }
350
+ const hasPersistedPreviewData = !!(0, import_tinypivot_core.getLatestConversationData)(initialConversation);
351
+ const hasSchema = schemas.has(initialDataSourceId);
352
+ const hasPreviewData = !!lastLoadedData?.length || hasPersistedPreviewData;
353
+ hydratedPersistedSelectionRef.current = true;
354
+ if (!hasSchema || !hasPreviewData) {
355
+ void ensureDataSourceState(dataSource);
309
356
  }
310
- }, [effectiveDataSources, fetchSchema, fetchSampleData, onConversationUpdate, onDataLoaded]);
357
+ }, [effectiveDataSources, ensureDataSourceState, lastLoadedData, schemas]);
311
358
  const callAIEndpoint = (0, import_react.useCallback)(async (userInput, currentConversation, currentSchemas, currentDataSources, currentAllSchemas) => {
312
359
  if (!configRef.current.endpoint) {
313
360
  throw new Error("No endpoint configured. Set `endpoint` in AI analyst config.");
@@ -710,6 +757,7 @@ What would you like to know about this data?`
710
757
  return null;
711
758
  }, [conversation.dataSourceId, effectiveDataSources, onError]);
712
759
  const clearConversation = (0, import_react.useCallback)(() => {
760
+ hydratedPersistedSelectionRef.current = true;
713
761
  const newConv = (0, import_tinypivot_core.createConversation)(configRef.current.sessionId);
714
762
  setConversation(newConv);
715
763
  setError(null);
@@ -720,7 +768,9 @@ What would you like to know about this data?`
720
768
  return { ...conversation };
721
769
  }, [conversation]);
722
770
  const importConversation = (0, import_react.useCallback)((conv) => {
771
+ hydratedPersistedSelectionRef.current = true;
723
772
  setConversation(conv);
773
+ setLastLoadedData((0, import_tinypivot_core.getLatestConversationData)(conv));
724
774
  onConversationUpdate?.({ conversation: conv });
725
775
  }, [onConversationUpdate]);
726
776
  return {
@@ -782,6 +832,7 @@ var AIAnalyst = (0, import_react2.forwardRef)(({
782
832
  onQueryExecuted,
783
833
  onError
784
834
  });
835
+ const isDarkTheme = theme === "dark" || typeof theme === "string" && theme.endsWith("-dark");
785
836
  (0, import_react2.useImperativeHandle)(ref, () => ({
786
837
  loadFullData,
787
838
  selectedDataSource
@@ -943,7 +994,7 @@ var AIAnalyst = (0, import_react2.forwardRef)(({
943
994
  return !!message.metadata?.data && message.metadata.data.length > 0;
944
995
  };
945
996
  if (!selectedDataSource) {
946
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `vpg-ai-analyst ${theme === "dark" ? "vpg-theme-dark" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "vpg-ai-picker-fullscreen", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-picker-content", children: [
997
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `vpg-ai-analyst ${isDarkTheme ? "vpg-theme-dark" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "vpg-ai-picker-fullscreen", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-picker-content", children: [
947
998
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-picker-header", children: [
948
999
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "vpg-ai-icon-lg", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
949
1000
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 2a2 2 0 0 1 2 2c0 .74-.4 1.39-1 1.73V7h1a7 7 0 0 1 7 7h1a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v1a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-1H2a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h1a7 7 0 0 1 7-7h1V5.73c-.6-.34-1-.99-1-1.73a2 2 0 0 1 2-2z" }),
@@ -1015,7 +1066,7 @@ var AIAnalyst = (0, import_react2.forwardRef)(({
1015
1066
  ] })
1016
1067
  ] }) }) });
1017
1068
  }
1018
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `vpg-ai-analyst ${theme === "dark" ? "vpg-theme-dark" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-split-layout", children: [
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: `vpg-ai-analyst ${isDarkTheme ? "vpg-theme-dark" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-split-layout", children: [
1019
1070
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-chat-panel", children: [
1020
1071
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "vpg-ai-chat-header", children: [
1021
1072
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1745,7 +1796,7 @@ function ChartBuilder({
1745
1796
  return val.toFixed(dec);
1746
1797
  }, []);
1747
1798
  const chartOptions = (0, import_react4.useMemo)(() => {
1748
- const isDark = theme === "dark";
1799
+ const isDark = theme === "dark" || typeof theme === "string" && theme.endsWith("-dark");
1749
1800
  const config = chartConfig;
1750
1801
  const options = config.options || {};
1751
1802
  const baseOptions = {
@@ -3834,7 +3885,8 @@ function PivotConfig({
3834
3885
  onAddColumnField,
3835
3886
  onAddCalculatedField,
3836
3887
  onRemoveCalculatedField,
3837
- onUpdateCalculatedField
3888
+ onUpdateCalculatedField,
3889
+ theme
3838
3890
  }) {
3839
3891
  const [fieldSearch, setFieldSearch] = (0, import_react12.useState)("");
3840
3892
  const [showCalcModal, setShowCalcModal] = (0, import_react12.useState)(false);
@@ -3960,7 +4012,7 @@ function PivotConfig({
3960
4012
  setShowCalcModal(false);
3961
4013
  setEditingCalcField(null);
3962
4014
  }, []);
3963
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "vpg-pivot-config", children: [
4015
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `vpg-pivot-config ${theme ? `vpg-theme-${theme}` : ""}`, children: [
3964
4016
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "vpg-config-header", children: [
3965
4017
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h3", { className: "vpg-config-title", children: [
3966
4018
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -4228,7 +4280,8 @@ function PivotSkeleton({
4228
4280
  onAddValueField,
4229
4281
  onRemoveValueField,
4230
4282
  onReorderRowFields,
4231
- onReorderColumnFields
4283
+ onReorderColumnFields,
4284
+ theme
4232
4285
  }) {
4233
4286
  const { showWatermark, canUsePivot, isDemo } = useLicense();
4234
4287
  const getValueFieldDisplayName = (0, import_react13.useCallback)((field) => {
@@ -4594,7 +4647,7 @@ function PivotSkeleton({
4594
4647
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
4595
4648
  "div",
4596
4649
  {
4597
- className: `vpg-pivot-skeleton vpg-font-${currentFontSize} ${draggingField ? "vpg-is-dragging" : ""}`,
4650
+ className: `vpg-pivot-skeleton vpg-font-${currentFontSize} ${theme ? `vpg-theme-${theme}` : ""} ${draggingField ? "vpg-is-dragging" : ""}`,
4598
4651
  children: [
4599
4652
  showCopyToast && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "vpg-toast", children: [
4600
4653
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { className: "vpg-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 13l4 4L19 7" }) }),
@@ -4715,9 +4768,8 @@ function PivotSkeleton({
4715
4768
  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"
4716
4769
  }
4717
4770
  ) }),
4718
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Pro Feature" }),
4719
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "Pivot Table functionality requires a Pro license." }),
4720
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("a", { href: "https://tiny-pivot.com/#pricing", target: "_blank", rel: "noopener noreferrer", className: "vpg-pro-link", children: "Get Pro License \u2192" })
4771
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: "Pivot Unavailable" }),
4772
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "Pivot mode could not be enabled in this session. Try reloading the page." })
4721
4773
  ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
4722
4774
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "vpg-config-bar", children: [
4723
4775
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
@@ -6146,7 +6198,8 @@ function DataGrid({
6146
6198
  onRemoveValueField: removeValueField,
6147
6199
  onAddCalculatedField: addCalculatedField,
6148
6200
  onRemoveCalculatedField: removeCalculatedField,
6149
- onUpdateCalculatedField: addCalculatedField
6201
+ onUpdateCalculatedField: addCalculatedField,
6202
+ theme: currentTheme
6150
6203
  }
6151
6204
  ) }),
6152
6205
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `vpg-pivot-main ${!showPivotConfig ? "vpg-full-width" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -6171,7 +6224,8 @@ function DataGrid({
6171
6224
  onRemoveValueField: removeValueField,
6172
6225
  onUpdateAggregation: updateValueFieldAggregation,
6173
6226
  onReorderRowFields: setRowFields,
6174
- onReorderColumnFields: setColumnFields
6227
+ onReorderColumnFields: setColumnFields,
6228
+ theme: currentTheme
6175
6229
  }
6176
6230
  ) })
6177
6231
  ] }),