@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 +101 -9
- package/dist/index.cjs +105 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +106 -51
- package/dist/index.js.map +1 -1
- package/dist/style.css +727 -900
- package/package.json +3 -3
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
|
-
- **
|
|
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
|
-
- **
|
|
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
|
-
|
|
|
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
|
|
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` | `
|
|
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
|
|
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
|
|
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)(
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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,
|
|
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 ${
|
|
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 ${
|
|
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:
|
|
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: "
|
|
4719
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "Pivot
|
|
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
|
] }),
|