react-auto-smart-table 1.0.0

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 ADDED
@@ -0,0 +1,1259 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ FilterPanel: () => FilterPanel,
34
+ InsightsPanel: () => InsightsPanel,
35
+ PluginRegistry: () => PluginRegistry,
36
+ SmartTable: () => SmartTable,
37
+ aggregateData: () => aggregateData,
38
+ aggregateDataByCount: () => aggregateDataByCount,
39
+ buildSchema: () => buildSchema,
40
+ computeColumnStats: () => computeColumnStats,
41
+ currencyPlugin: () => currencyPlugin,
42
+ detectChartFields: () => detectChartFields,
43
+ detectValueType: () => detectValueType,
44
+ generateInsights: () => generateInsights,
45
+ getCellRenderer: () => getCellRenderer,
46
+ globalPluginRegistry: () => globalPluginRegistry,
47
+ percentagePlugin: () => percentagePlugin,
48
+ sampleDataset: () => sampleDataset,
49
+ useFilters: () => useFilters,
50
+ usePagination: () => usePagination,
51
+ useSorting: () => useSorting
52
+ });
53
+ module.exports = __toCommonJS(index_exports);
54
+
55
+ // src/analyzer/detectTypes.ts
56
+ var EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
57
+ var URL_REGEX = /^(https?:\/\/)?([\w.-]+)\.([a-z]{2,6}\.?)(\/[\w.-]*)*\/?$/i;
58
+ var IMAGE_REGEX = /\.(jpeg|jpg|gif|png|webp|svg|bmp)(\?.*)?$/i;
59
+ var isEmail = (value) => EMAIL_REGEX.test(value);
60
+ var isImage = (value) => {
61
+ return URL_REGEX.test(value) && IMAGE_REGEX.test(value);
62
+ };
63
+ var isUrl = (value) => {
64
+ if (isImage(value)) return false;
65
+ return URL_REGEX.test(value);
66
+ };
67
+ var isDate = (value) => {
68
+ if (value instanceof Date) return !isNaN(value.getTime());
69
+ if (typeof value === "string" || typeof value === "number") {
70
+ if (typeof value === "number") return false;
71
+ if (typeof value === "string" && value.trim() !== "" && !isNaN(Number(value))) return false;
72
+ const datePattern = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z?)?$|^\d{1,2}[-/]\d{1,2}[-/]\d{2,4}$/;
73
+ if (typeof value === "string" && !datePattern.test(value.trim())) {
74
+ return false;
75
+ }
76
+ const d = new Date(value);
77
+ return !isNaN(d.getTime()) && String(d) !== "Invalid Date";
78
+ }
79
+ return false;
80
+ };
81
+ var isCurrency = (value) => {
82
+ return typeof value === "string" && /^[£$€¥]?\s*-?\d+(?:,\d{3})*(?:\.\d+)?\s*[£$€¥]?$/.test(value) && /[£$€¥]/.test(value);
83
+ };
84
+ var isPercentage = (value) => {
85
+ return typeof value === "string" && /^-?\d+(?:\.\d+)?%$/.test(value);
86
+ };
87
+ var isNumber = (value) => {
88
+ if (typeof value === "number") return true;
89
+ if (typeof value === "string") {
90
+ return value.trim() !== "" && !isNaN(Number(value));
91
+ }
92
+ return false;
93
+ };
94
+ var isBoolean = (value) => {
95
+ if (typeof value === "boolean") return true;
96
+ if (typeof value === "string") {
97
+ const lower = value.toLowerCase();
98
+ return lower === "true" || lower === "false" || lower === "yes" || lower === "no";
99
+ }
100
+ return false;
101
+ };
102
+ var detectValueType = (value) => {
103
+ if (value === null || value === void 0 || value === "") return "string";
104
+ const strVal = String(value);
105
+ if (isEmail(strVal)) return "email";
106
+ if (isUrl(strVal)) return "url";
107
+ if (isImage(strVal)) return "image";
108
+ if (isDate(value)) return "date";
109
+ if (isCurrency(strVal)) return "currency";
110
+ if (isPercentage(strVal)) return "percentage";
111
+ if (isNumber(value)) return "number";
112
+ if (isBoolean(value)) return "boolean";
113
+ return "string";
114
+ };
115
+
116
+ // src/analyzer/sampleDataset.ts
117
+ function sampleDataset(dataset, maxSampleSize = 200) {
118
+ if (!dataset || !dataset.length) return [];
119
+ if (dataset.length <= maxSampleSize) return [...dataset];
120
+ const sample = [];
121
+ const indices = /* @__PURE__ */ new Set();
122
+ while (sample.length < maxSampleSize) {
123
+ const idx = Math.floor(Math.random() * dataset.length);
124
+ if (!indices.has(idx)) {
125
+ indices.add(idx);
126
+ sample.push(dataset[idx]);
127
+ }
128
+ }
129
+ return sample;
130
+ }
131
+
132
+ // src/analyzer/computeStats.ts
133
+ var computeColumnStats = (columnKey, dataset, type) => {
134
+ const stats = {};
135
+ const uniqueVals = /* @__PURE__ */ new Set();
136
+ let min = void 0;
137
+ let max = void 0;
138
+ for (const row of dataset) {
139
+ const val = row[columnKey];
140
+ if (val !== null && val !== void 0 && val !== "") {
141
+ uniqueVals.add(val);
142
+ if (type === "number" || type === "currency" || type === "percentage") {
143
+ let numVal = NaN;
144
+ if (type === "number") numVal = Number(val);
145
+ else if (type === "currency" || type === "percentage") {
146
+ const clean = String(val).replace(/[^0-9.-]/g, "");
147
+ numVal = Number(clean);
148
+ }
149
+ if (!isNaN(numVal)) {
150
+ if (min === void 0 || numVal < min) min = numVal;
151
+ if (max === void 0 || numVal > max) max = numVal;
152
+ }
153
+ } else if (type === "date") {
154
+ const d = new Date(val).getTime();
155
+ if (!isNaN(d)) {
156
+ if (min === void 0 || d < min) min = d;
157
+ if (max === void 0 || d > max) max = d;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ stats.uniqueValues = uniqueVals.size;
163
+ if (min !== void 0) stats.min = min;
164
+ if (max !== void 0) stats.max = max;
165
+ return stats;
166
+ };
167
+
168
+ // src/schema/buildSchema.ts
169
+ var buildSchema = (dataset, registry) => {
170
+ if (!dataset || dataset.length === 0) return {};
171
+ const sample = sampleDataset(dataset, 200);
172
+ const sampleSize = sample.length;
173
+ const keys = /* @__PURE__ */ new Set();
174
+ for (const row of sample) {
175
+ for (const key of Object.keys(row)) {
176
+ keys.add(key);
177
+ }
178
+ }
179
+ const schema = {};
180
+ for (const key of keys) {
181
+ const values = sample.map((row) => row[key]);
182
+ let detectedTypeStr = null;
183
+ if (registry) {
184
+ detectedTypeStr = registry.runDetectors(key, values);
185
+ }
186
+ if (detectedTypeStr) {
187
+ const isNull = values.some((v) => v === null || v === void 0);
188
+ schema[key] = {
189
+ key,
190
+ type: detectedTypeStr,
191
+ nullable: isNull
192
+ };
193
+ const stats2 = computeColumnStats(key, sample, detectedTypeStr);
194
+ schema[key].uniqueValues = stats2.uniqueValues;
195
+ if (stats2.min !== void 0) schema[key].min = stats2.min;
196
+ if (stats2.max !== void 0) schema[key].max = stats2.max;
197
+ continue;
198
+ }
199
+ let nullCount = 0;
200
+ const typeCounts = {};
201
+ for (const row of sample) {
202
+ const val = row[key];
203
+ if (val === null || val === void 0 || val === "") {
204
+ nullCount++;
205
+ } else {
206
+ const detectedType = detectValueType(val);
207
+ typeCounts[detectedType] = (typeCounts[detectedType] || 0) + 1;
208
+ }
209
+ }
210
+ const validValuesCount = sampleSize - nullCount;
211
+ let dominantType = "string";
212
+ if (validValuesCount > 0) {
213
+ let maxCount = 0;
214
+ let topType = "string";
215
+ for (const [type, count] of Object.entries(typeCounts)) {
216
+ if (count > maxCount) {
217
+ maxCount = count;
218
+ topType = type;
219
+ }
220
+ }
221
+ const confidence = maxCount / validValuesCount;
222
+ dominantType = confidence > 0.7 ? topType : "string";
223
+ }
224
+ const stats = computeColumnStats(key, sample, dominantType);
225
+ const columnSchema = {
226
+ key,
227
+ type: dominantType,
228
+ nullable: nullCount > 0,
229
+ uniqueValues: stats.uniqueValues
230
+ };
231
+ if (stats.min !== void 0) columnSchema.min = stats.min;
232
+ if (stats.max !== void 0) columnSchema.max = stats.max;
233
+ schema[key] = columnSchema;
234
+ }
235
+ return schema;
236
+ };
237
+
238
+ // src/hooks/useSorting.ts
239
+ var import_react = require("react");
240
+ var useSorting = (data, schema, initialSortColumn = null, initialSortDirection = "asc") => {
241
+ const [sortColumn, setSortColumn] = (0, import_react.useState)(initialSortColumn);
242
+ const [sortDirection, setSortDirection] = (0, import_react.useState)(initialSortDirection);
243
+ const handleSort = (columnKey) => {
244
+ if (sortColumn === columnKey) {
245
+ if (sortDirection === "asc") {
246
+ setSortDirection("desc");
247
+ } else {
248
+ setSortColumn(null);
249
+ setSortDirection("asc");
250
+ }
251
+ } else {
252
+ setSortColumn(columnKey);
253
+ setSortDirection("asc");
254
+ }
255
+ };
256
+ const sortedData = (0, import_react.useMemo)(() => {
257
+ if (!sortColumn || !data || data.length === 0) return data;
258
+ const columnType = schema[sortColumn]?.type || "string";
259
+ return [...data].sort((a, b) => {
260
+ let valA = a[sortColumn];
261
+ let valB = b[sortColumn];
262
+ if (valA === valB) return 0;
263
+ if (valA === null || valA === void 0) return sortDirection === "asc" ? 1 : -1;
264
+ if (valB === null || valB === void 0) return sortDirection === "asc" ? -1 : 1;
265
+ let comparison = 0;
266
+ switch (columnType) {
267
+ case "number":
268
+ case "currency":
269
+ case "percentage":
270
+ const numA = typeof valA === "number" ? valA : Number(String(valA).replace(/[^0-9.-]/g, ""));
271
+ const numB = typeof valB === "number" ? valB : Number(String(valB).replace(/[^0-9.-]/g, ""));
272
+ comparison = (isNaN(numA) ? 0 : numA) - (isNaN(numB) ? 0 : numB);
273
+ break;
274
+ case "date":
275
+ const dateA = new Date(valA).getTime();
276
+ const dateB = new Date(valB).getTime();
277
+ comparison = (isNaN(dateA) ? 0 : dateA) - (isNaN(dateB) ? 0 : dateB);
278
+ break;
279
+ case "boolean":
280
+ const boolA = valA === true || String(valA).toLowerCase() === "true" || String(valA).toLowerCase() === "yes" ? 1 : 0;
281
+ const boolB = valB === true || String(valB).toLowerCase() === "true" || String(valB).toLowerCase() === "yes" ? 1 : 0;
282
+ comparison = boolA - boolB;
283
+ break;
284
+ default:
285
+ comparison = String(valA).localeCompare(String(valB));
286
+ break;
287
+ }
288
+ return sortDirection === "asc" ? comparison : -comparison;
289
+ });
290
+ }, [data, schema, sortColumn, sortDirection]);
291
+ return { sortedData, sortColumn, sortDirection, handleSort };
292
+ };
293
+
294
+ // src/hooks/useFilters.ts
295
+ var import_react2 = require("react");
296
+ var useFilters = (data, schema) => {
297
+ const [filters, setFilters] = (0, import_react2.useState)({});
298
+ const setFilter = (columnKey, value) => {
299
+ setFilters((prev) => {
300
+ const next = { ...prev };
301
+ if (value === null || value === void 0 || value === "") {
302
+ delete next[columnKey];
303
+ } else {
304
+ next[columnKey] = value;
305
+ }
306
+ return next;
307
+ });
308
+ };
309
+ const clearFilters = () => setFilters({});
310
+ const filteredData = (0, import_react2.useMemo)(() => {
311
+ if (!filters || Object.keys(filters).length === 0 || !data || data.length === 0) {
312
+ return data;
313
+ }
314
+ return data.filter((row) => {
315
+ for (const [key, filterValue] of Object.entries(filters)) {
316
+ const rowValue = row[key];
317
+ const type = schema[key]?.type || "string";
318
+ if (rowValue === null || rowValue === void 0) {
319
+ if (filterValue !== null && filterValue !== "") return false;
320
+ continue;
321
+ }
322
+ switch (type) {
323
+ case "string":
324
+ case "email":
325
+ case "url":
326
+ if (typeof filterValue === "string") {
327
+ if (!String(rowValue).toLowerCase().includes(filterValue.toLowerCase())) return false;
328
+ }
329
+ break;
330
+ case "number":
331
+ case "currency":
332
+ case "percentage":
333
+ if (typeof filterValue === "object" && filterValue !== null) {
334
+ const numVal = typeof rowValue === "number" ? rowValue : Number(String(rowValue).replace(/[^0-9.-]/g, ""));
335
+ if (isNaN(numVal)) return false;
336
+ const { min, max } = filterValue;
337
+ if (min !== void 0 && numVal < min) return false;
338
+ if (max !== void 0 && numVal > max) return false;
339
+ }
340
+ break;
341
+ case "date":
342
+ if (typeof filterValue === "object" && filterValue !== null) {
343
+ const dateVal = new Date(rowValue).getTime();
344
+ if (isNaN(dateVal)) return false;
345
+ const { start, end } = filterValue;
346
+ if (start && dateVal < new Date(start).getTime()) return false;
347
+ if (end && dateVal > new Date(end).getTime()) return false;
348
+ }
349
+ break;
350
+ case "boolean":
351
+ if (typeof filterValue === "boolean") {
352
+ const boolVal = rowValue === true || String(rowValue).toLowerCase() === "true" || String(rowValue).toLowerCase() === "yes";
353
+ if (boolVal !== filterValue) return false;
354
+ }
355
+ break;
356
+ }
357
+ }
358
+ return true;
359
+ });
360
+ }, [data, schema, filters]);
361
+ return { filteredData, filters, setFilter, clearFilters };
362
+ };
363
+
364
+ // src/hooks/usePagination.ts
365
+ var import_react3 = require("react");
366
+ var usePagination = (data, initialPageSize = 10) => {
367
+ const [currentPage, setCurrentPage] = (0, import_react3.useState)(1);
368
+ const [pageSize, setPageSize] = (0, import_react3.useState)(initialPageSize);
369
+ const totalPages = Math.max(1, Math.ceil(data.length / pageSize));
370
+ const safeCurrentPage = Math.min(currentPage, totalPages);
371
+ const paginatedData = (0, import_react3.useMemo)(() => {
372
+ const startIndex = (safeCurrentPage - 1) * pageSize;
373
+ return data.slice(startIndex, startIndex + pageSize);
374
+ }, [data, safeCurrentPage, pageSize]);
375
+ return {
376
+ paginatedData,
377
+ currentPage: safeCurrentPage,
378
+ pageSize,
379
+ totalPages,
380
+ setPage: setCurrentPage,
381
+ setPageSize
382
+ };
383
+ };
384
+
385
+ // src/insights/aggregationEngine.ts
386
+ var aggregateData = (dataset, dimension, metrics) => {
387
+ if (!dataset || dataset.length === 0) return [];
388
+ if (!dimension) return [];
389
+ const groups = /* @__PURE__ */ new Map();
390
+ for (const row of dataset) {
391
+ let dimValue = row[dimension];
392
+ if (dimValue === null || dimValue === void 0) {
393
+ dimValue = "Unknown";
394
+ } else if (typeof dimValue === "boolean") {
395
+ dimValue = dimValue ? "Yes" : "No";
396
+ }
397
+ if (!groups.has(dimValue)) {
398
+ const initPoint = { [dimension]: dimValue };
399
+ for (const m of metrics) {
400
+ initPoint[m] = 0;
401
+ }
402
+ groups.set(dimValue, initPoint);
403
+ }
404
+ const group = groups.get(dimValue);
405
+ for (const m of metrics) {
406
+ const val = row[m];
407
+ let numVal = 0;
408
+ if (typeof val === "number") {
409
+ numVal = val;
410
+ } else if (typeof val === "string") {
411
+ numVal = Number(val.replace(/[^0-9.-]/g, ""));
412
+ }
413
+ if (!isNaN(numVal)) {
414
+ group[m] += numVal;
415
+ }
416
+ }
417
+ }
418
+ return Array.from(groups.values());
419
+ };
420
+ var aggregateDataByCount = (dataset, dimension) => {
421
+ if (!dataset || dataset.length === 0) return [];
422
+ const groups = /* @__PURE__ */ new Map();
423
+ for (const row of dataset) {
424
+ let dimValue = row[dimension];
425
+ if (dimValue === null || dimValue === void 0) {
426
+ dimValue = "Unknown";
427
+ } else if (typeof dimValue === "boolean") {
428
+ dimValue = dimValue ? "Yes" : "No";
429
+ }
430
+ groups.set(dimValue, (groups.get(dimValue) || 0) + 1);
431
+ }
432
+ return Array.from(groups.entries()).map(([dim, count]) => ({
433
+ [dimension]: dim,
434
+ count
435
+ }));
436
+ };
437
+
438
+ // src/insights/chartDetector.ts
439
+ var detectChartFields = (schema) => {
440
+ const dimensions = [];
441
+ const metrics = [];
442
+ for (const [key, col] of Object.entries(schema)) {
443
+ const lowerKey = key.toLowerCase();
444
+ const isIdField = lowerKey === "id" || lowerKey === "_id" || lowerKey === "uuid" || lowerKey === "guid" || lowerKey.endsWith("id") || lowerKey.endsWith("_id") || lowerKey.endsWith("uuid");
445
+ if (isIdField) {
446
+ continue;
447
+ }
448
+ const role = determineFieldRole(col.type, col.uniqueValues);
449
+ if (role === "dimension") {
450
+ dimensions.push(key);
451
+ } else if (role === "metric") {
452
+ metrics.push(key);
453
+ }
454
+ }
455
+ return { dimensions, metrics };
456
+ };
457
+ var determineFieldRole = (type, uniqueValues) => {
458
+ switch (type) {
459
+ case "boolean":
460
+ return "dimension";
461
+ case "string":
462
+ if (uniqueValues !== void 0 && uniqueValues > 1 && uniqueValues <= 20) {
463
+ return "dimension";
464
+ }
465
+ return "discard";
466
+ case "date":
467
+ return "dimension";
468
+ case "number":
469
+ case "currency":
470
+ case "percentage":
471
+ return "metric";
472
+ default:
473
+ return "discard";
474
+ }
475
+ };
476
+
477
+ // src/utils/stringUtils.ts
478
+ var ACRONYMS = ["ID", "URL", "API", "JSON", "UUID", "SKU", "IP", "VAT", "GST"];
479
+ var toTitleCase = (str) => {
480
+ if (!str) return "";
481
+ const spaced = str.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").trim();
482
+ return spaced.split(" ").filter(Boolean).map((word) => {
483
+ const upper = word.toUpperCase();
484
+ if (ACRONYMS.includes(upper)) {
485
+ return upper;
486
+ }
487
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
488
+ }).join(" ");
489
+ };
490
+
491
+ // src/insights/insightBuilder.ts
492
+ var generateInsights = (dataset, schema) => {
493
+ if (!dataset || dataset.length === 0 || !schema) return [];
494
+ const { dimensions, metrics } = detectChartFields(schema);
495
+ const widgets = [];
496
+ const maxCharts = 4;
497
+ if (dimensions.length > 0 && metrics.length > 0) {
498
+ for (const dim of dimensions) {
499
+ if (widgets.length >= maxCharts) break;
500
+ const dimInfo = schema[dim];
501
+ const targetMetrics = metrics.slice(0, 2);
502
+ const aggregated = aggregateData(dataset, dim, targetMetrics);
503
+ if (dimInfo.type === "date") {
504
+ aggregated.sort((a, b) => new Date(a[dim]).getTime() - new Date(b[dim]).getTime());
505
+ } else {
506
+ const primaryMetric = targetMetrics[0];
507
+ aggregated.sort((a, b) => (b[primaryMetric] || 0) - (a[primaryMetric] || 0));
508
+ }
509
+ const isLine = dimInfo.type === "date";
510
+ const isPie = !isLine && aggregated.length > 0 && aggregated.length <= 5 && targetMetrics.length === 1;
511
+ widgets.push({
512
+ id: `chart-${dim}-metrics`,
513
+ title: `${targetMetrics.map(toTitleCase).join(" & ")} by ${toTitleCase(dim)}`,
514
+ type: isPie ? "pie" : isLine ? "line" : "bar",
515
+ data: aggregated,
516
+ xAxisKey: dim,
517
+ yAxisKeys: targetMetrics
518
+ });
519
+ }
520
+ }
521
+ if (dimensions.length > 0 && widgets.length < maxCharts) {
522
+ for (const dim of dimensions) {
523
+ if (widgets.length >= maxCharts) break;
524
+ if (widgets.some((w) => w.id.includes(dim))) continue;
525
+ const dimInfo = schema[dim];
526
+ const aggregated = aggregateDataByCount(dataset, dim);
527
+ if (dimInfo.type === "date") {
528
+ aggregated.sort((a, b) => new Date(a[dim]).getTime() - new Date(b[dim]).getTime());
529
+ } else {
530
+ aggregated.sort((a, b) => b.count - a.count);
531
+ }
532
+ const isLine = dimInfo.type === "date";
533
+ widgets.push({
534
+ id: `chart-${dim}-count`,
535
+ title: `Distribution of ${toTitleCase(dim)}`,
536
+ type: isLine ? "line" : aggregated.length <= 6 ? "pie" : "bar",
537
+ data: aggregated,
538
+ xAxisKey: dim,
539
+ yAxisKeys: ["count"]
540
+ });
541
+ }
542
+ }
543
+ return widgets;
544
+ };
545
+
546
+ // src/components/SmartTable.tsx
547
+ var import_react6 = __toESM(require("react"));
548
+
549
+ // src/components/TableHeader.tsx
550
+ var import_jsx_runtime = require("react/jsx-runtime");
551
+ var getColumnWidthClass = (key, type) => {
552
+ const lowerKey = key.toLowerCase();
553
+ if (lowerKey === "id" || lowerKey === "_id" || type === "boolean") return "rst-col-xs";
554
+ if (type === "date" || type === "number" || lowerKey.includes("status")) return "rst-col-sm";
555
+ if (lowerKey.includes("role") || lowerKey.includes("country") || lowerKey.includes("category")) return "rst-col-md";
556
+ if (lowerKey.includes("name") || lowerKey.includes("email") || lowerKey.includes("url") || lowerKey.includes("description")) return "rst-col-flex";
557
+ return "rst-col-md";
558
+ };
559
+ var TableHeader = ({
560
+ schema,
561
+ sortable = false,
562
+ sortColumn = null,
563
+ sortDirection = "asc",
564
+ onSort
565
+ }) => {
566
+ const columns = Object.keys(schema);
567
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { className: "rst-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { className: "rst-header-row", children: columns.map((colKey) => {
568
+ const colInfo = schema[colKey];
569
+ const widthClass = getColumnWidthClass(colKey, colInfo.type);
570
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
571
+ "th",
572
+ {
573
+ className: `rst-th rst-th-col-${colKey} rst-th-type-${colInfo.type} ${widthClass} ${sortable && onSort ? "rst-sortable" : ""} ${sortColumn === colKey ? "rst-sort-active" : ""}`,
574
+ onClick: () => {
575
+ if (sortable && onSort) onSort(colKey);
576
+ },
577
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rst-header-content", children: [
578
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: toTitleCase(colKey) }),
579
+ sortable && onSort && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rst-sort-icon", children: sortColumn === colKey ? sortDirection === "asc" ? "\u2191" : "\u2193" : "\u21C5" })
580
+ ] })
581
+ },
582
+ colKey
583
+ );
584
+ }) }) });
585
+ };
586
+
587
+ // src/components/TableBody.tsx
588
+ var import_react4 = __toESM(require("react"));
589
+
590
+ // src/renderers/numberRenderer.tsx
591
+ var import_jsx_runtime2 = require("react/jsx-runtime");
592
+ var NumberRenderer = ({ value }) => {
593
+ if (value === null || value === void 0) return null;
594
+ const num = Number(value);
595
+ if (!isNaN(num)) {
596
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rst-cell-number", children: new Intl.NumberFormat().format(num) });
597
+ }
598
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "rst-cell-number", children: String(value) });
599
+ };
600
+
601
+ // src/renderers/emailRenderer.tsx
602
+ var import_jsx_runtime3 = require("react/jsx-runtime");
603
+ var EmailRenderer = ({ value }) => {
604
+ if (!value) return null;
605
+ const email = String(value);
606
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: `mailto:${email}`, className: "rst-cell-email", onClick: (e) => e.stopPropagation(), children: email });
607
+ };
608
+
609
+ // src/renderers/urlRenderer.tsx
610
+ var import_jsx_runtime4 = require("react/jsx-runtime");
611
+ var UrlRenderer = ({ value }) => {
612
+ if (!value) return null;
613
+ const url = String(value);
614
+ const href = /^https?:\/\//i.test(url) ? url : `https://${url}`;
615
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
616
+ "a",
617
+ {
618
+ href,
619
+ target: "_blank",
620
+ rel: "noopener noreferrer",
621
+ className: "rst-cell-url",
622
+ onClick: (e) => e.stopPropagation(),
623
+ children: url
624
+ }
625
+ );
626
+ };
627
+
628
+ // src/renderers/imageRenderer.tsx
629
+ var import_jsx_runtime5 = require("react/jsx-runtime");
630
+ var ImageRenderer = ({ value }) => {
631
+ if (!value) return null;
632
+ const src = String(value);
633
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
634
+ "img",
635
+ {
636
+ src,
637
+ alt: "cell content",
638
+ className: "rst-cell-image",
639
+ style: { maxWidth: "50px", maxHeight: "50px", objectFit: "contain", borderRadius: "4px" },
640
+ loading: "lazy"
641
+ }
642
+ );
643
+ };
644
+
645
+ // src/renderers/percentageRenderer.tsx
646
+ var import_jsx_runtime6 = require("react/jsx-runtime");
647
+ var PercentageRenderer = ({ value }) => {
648
+ if (value === null || value === void 0) return null;
649
+ const str = String(value);
650
+ if (str.includes("%")) {
651
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rst-cell-percentage", children: str });
652
+ }
653
+ const num = Number(value);
654
+ if (!isNaN(num)) {
655
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "rst-cell-percentage", children: [
656
+ (num * 100).toFixed(2),
657
+ "%"
658
+ ] });
659
+ }
660
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "rst-cell-percentage", children: str });
661
+ };
662
+
663
+ // src/renderers/dateRenderer.tsx
664
+ var import_jsx_runtime7 = require("react/jsx-runtime");
665
+ var DateRenderer = ({ value }) => {
666
+ if (!value) return null;
667
+ const d = new Date(value);
668
+ if (isNaN(d.getTime())) {
669
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rst-cell-date", children: String(value) });
670
+ }
671
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rst-cell-date", title: d.toISOString(), children: d.toLocaleDateString(void 0, {
672
+ year: "numeric",
673
+ month: "short",
674
+ day: "numeric"
675
+ }) });
676
+ };
677
+
678
+ // src/renderers/booleanRenderer.tsx
679
+ var import_jsx_runtime8 = require("react/jsx-runtime");
680
+ var BooleanRenderer = ({ value }) => {
681
+ if (value === null || value === void 0) return null;
682
+ let isTrue = false;
683
+ if (typeof value === "boolean") {
684
+ isTrue = value;
685
+ } else if (typeof value === "string") {
686
+ const lower = value.toLowerCase();
687
+ isTrue = lower === "true" || lower === "yes";
688
+ } else if (typeof value === "number") {
689
+ isTrue = value > 0;
690
+ }
691
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
692
+ "span",
693
+ {
694
+ className: `rst-cell-boolean rst-cell-boolean-${isTrue ? "true" : "false"}`,
695
+ style: {
696
+ display: "inline-block",
697
+ padding: "2px 8px",
698
+ borderRadius: "12px",
699
+ fontSize: "0.85em",
700
+ fontWeight: "bold",
701
+ backgroundColor: isTrue ? "#e6f4ea" : "#fce8e6",
702
+ color: isTrue ? "#137333" : "#c5221f"
703
+ },
704
+ children: isTrue ? "Yes" : "No"
705
+ }
706
+ );
707
+ };
708
+
709
+ // src/renderers/defaultRenderer.tsx
710
+ var import_jsx_runtime9 = require("react/jsx-runtime");
711
+ var DefaultRenderer = ({ value }) => {
712
+ if (value === null || value === void 0) return null;
713
+ if (typeof value === "object") {
714
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rst-cell-default", children: JSON.stringify(value) });
715
+ }
716
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "rst-cell-default", children: String(value) });
717
+ };
718
+
719
+ // src/plugins/currencyPlugin.tsx
720
+ var import_jsx_runtime10 = require("react/jsx-runtime");
721
+ var currencyPlugin = {
722
+ detect: (columnKey, sample) => {
723
+ const lowerKey = columnKey.toLowerCase();
724
+ if (lowerKey.includes("amount") || lowerKey.includes("price") || lowerKey.includes("revenue")) {
725
+ return "currency";
726
+ }
727
+ return null;
728
+ },
729
+ render: ({ value }) => {
730
+ if (value === null || value === void 0) return null;
731
+ let num = NaN;
732
+ if (typeof value === "number") num = value;
733
+ else if (typeof value === "string") num = Number(value.replace(/[^0-9.-]/g, ""));
734
+ if (isNaN(num)) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: String(value) });
735
+ const formatted = new Intl.NumberFormat("en-US", {
736
+ style: "currency",
737
+ currency: "USD"
738
+ }).format(num);
739
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { color: num < 0 ? "#d32f2f" : "#388e3c", fontWeight: "bold" }, children: formatted });
740
+ }
741
+ };
742
+
743
+ // src/plugins/percentagePlugin.tsx
744
+ var import_jsx_runtime11 = require("react/jsx-runtime");
745
+ var percentagePlugin = {
746
+ detect: (columnKey, sample) => {
747
+ const lowerKey = columnKey.toLowerCase();
748
+ if (lowerKey.includes("percent") || lowerKey.includes("rate")) {
749
+ return "percentage";
750
+ }
751
+ return null;
752
+ },
753
+ render: ({ value }) => {
754
+ if (value === null || value === void 0) return null;
755
+ let str = String(value);
756
+ let num = Number(value);
757
+ if (!str.includes("%") && !isNaN(num)) {
758
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: {
759
+ backgroundColor: "#e3f2fd",
760
+ padding: "2px 6px",
761
+ borderRadius: "4px",
762
+ color: "#1565c0",
763
+ fontSize: "0.9em",
764
+ fontWeight: 600
765
+ }, children: [
766
+ (num * 100).toFixed(1),
767
+ "%"
768
+ ] });
769
+ }
770
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: {
771
+ backgroundColor: "#e3f2fd",
772
+ padding: "2px 6px",
773
+ borderRadius: "4px",
774
+ color: "#1565c0",
775
+ fontSize: "0.9em",
776
+ fontWeight: 600
777
+ }, children: str });
778
+ }
779
+ };
780
+
781
+ // src/renderers/cellRendererFactory.ts
782
+ var getCellRenderer = (type, registry) => {
783
+ if (registry) {
784
+ for (const plugin of registry.getPlugins()) {
785
+ if (type === "currency" && plugin.render && (plugin === currencyPlugin || plugin.detect?.("amount", []) === "currency")) {
786
+ return plugin.render;
787
+ }
788
+ if (type === "percentage" && plugin.render && (plugin === percentagePlugin || plugin.detect?.("percentage", []) === "percentage")) {
789
+ return plugin.render;
790
+ }
791
+ }
792
+ }
793
+ switch (type) {
794
+ case "number":
795
+ case "currency":
796
+ return NumberRenderer;
797
+ case "email":
798
+ return EmailRenderer;
799
+ case "url":
800
+ return UrlRenderer;
801
+ case "image":
802
+ return ImageRenderer;
803
+ case "percentage":
804
+ return PercentageRenderer;
805
+ case "date":
806
+ return DateRenderer;
807
+ case "boolean":
808
+ return BooleanRenderer;
809
+ case "string":
810
+ default:
811
+ return DefaultRenderer;
812
+ }
813
+ };
814
+
815
+ // src/components/TableBody.tsx
816
+ var import_react_virtual = require("react-virtual");
817
+ var import_jsx_runtime12 = require("react/jsx-runtime");
818
+ var TableBody = ({ data, schema, registry }) => {
819
+ const columns = Object.keys(schema);
820
+ const parentRef = (0, import_react4.useRef)(null);
821
+ const rowVirtualizer = (0, import_react_virtual.useVirtual)({
822
+ size: data.length,
823
+ parentRef,
824
+ estimateSize: import_react4.default.useCallback(() => 45, []),
825
+ overscan: 5
826
+ });
827
+ const isVirtualized = data.length > 20;
828
+ if (!isVirtualized) {
829
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { className: "rst-body", children: data.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tr", { className: "rst-row", children: columns.map((colKey) => {
830
+ const colInfo = schema[colKey];
831
+ const Renderer = getCellRenderer(colInfo.type, registry);
832
+ const widthClass = getColumnWidthClass(colKey, colInfo.type);
833
+ const val = row[colKey];
834
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
835
+ "td",
836
+ {
837
+ className: `rst-td rst-td-col-${colKey} rst-td-type-${colInfo.type} ${widthClass}`,
838
+ children: colInfo.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rst-badge ${val ? "rst-badge-yes" : "rst-badge-no"}`, children: val ? "Yes" : "No" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Renderer, { value: val })
839
+ },
840
+ colKey
841
+ );
842
+ }) }, index)) });
843
+ }
844
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
845
+ "tbody",
846
+ {
847
+ className: "rst-body",
848
+ ref: parentRef,
849
+ style: {
850
+ height: `${rowVirtualizer.totalSize}px`,
851
+ width: "100%",
852
+ position: "relative"
853
+ },
854
+ children: rowVirtualizer.virtualItems.map((virtualRow) => {
855
+ const row = data[virtualRow.index];
856
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
857
+ "tr",
858
+ {
859
+ className: "rst-row",
860
+ style: {
861
+ position: "absolute",
862
+ top: 0,
863
+ left: 0,
864
+ width: "100%",
865
+ height: `${virtualRow.size}px`,
866
+ transform: `translateY(${virtualRow.start}px)`
867
+ },
868
+ children: columns.map((colKey) => {
869
+ const val = row[colKey];
870
+ const colInfo = schema[colKey];
871
+ const Renderer = getCellRenderer(colInfo.type, registry);
872
+ const widthClass = getColumnWidthClass(colKey, colInfo.type);
873
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
874
+ "td",
875
+ {
876
+ className: `rst-td rst-td-col-${colKey} rst-td-type-${colInfo.type} ${widthClass}`,
877
+ children: colInfo.type === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: `rst-badge ${val ? "rst-badge-yes" : "rst-badge-no"}`, children: val ? "Yes" : "No" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Renderer, { value: val })
878
+ },
879
+ colKey
880
+ );
881
+ })
882
+ },
883
+ virtualRow.index
884
+ );
885
+ })
886
+ }
887
+ );
888
+ };
889
+
890
+ // src/components/FilterPanel.tsx
891
+ var import_jsx_runtime13 = require("react/jsx-runtime");
892
+ var FilterPanel = ({ schema, filters, onFilterChange, onClear }) => {
893
+ const handleStringChange = (key, e) => {
894
+ onFilterChange(key, e.target.value || null);
895
+ };
896
+ const handleNumberChange = (key, field, value) => {
897
+ const current = filters[key] || {};
898
+ const num = parseFloat(value);
899
+ const next = { ...current };
900
+ if (isNaN(num)) {
901
+ delete next[field];
902
+ } else {
903
+ next[field] = num;
904
+ }
905
+ if (Object.keys(next).length === 0) {
906
+ onFilterChange(key, null);
907
+ } else {
908
+ onFilterChange(key, next);
909
+ }
910
+ };
911
+ const handleDateChange = (key, field, value) => {
912
+ const current = filters[key] || {};
913
+ const next = { ...current };
914
+ if (!value) {
915
+ delete next[field];
916
+ } else {
917
+ next[field] = value;
918
+ }
919
+ if (Object.keys(next).length === 0) {
920
+ onFilterChange(key, null);
921
+ } else {
922
+ onFilterChange(key, next);
923
+ }
924
+ };
925
+ const handleBooleanToggle = (key) => {
926
+ const current = filters[key];
927
+ if (current === true) {
928
+ onFilterChange(key, false);
929
+ } else if (current === false) {
930
+ onFilterChange(key, null);
931
+ } else {
932
+ onFilterChange(key, true);
933
+ }
934
+ };
935
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rst-filter-panel", children: [
936
+ Object.entries(schema).map(([key, colInfo]) => {
937
+ const type = colInfo.type;
938
+ const currentFilter = filters[key];
939
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `rst-filter-group rst-filter-type-${type}`, children: [
940
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { children: [
941
+ toTitleCase(key),
942
+ " Filter"
943
+ ] }),
944
+ (type === "string" || type === "email" || type === "url") && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
945
+ "input",
946
+ {
947
+ type: "text",
948
+ placeholder: `Search ${toTitleCase(key)}...`,
949
+ value: currentFilter || "",
950
+ onChange: (e) => handleStringChange(key, e)
951
+ }
952
+ ),
953
+ (type === "number" || type === "currency" || type === "percentage") && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rst-filter-range", children: [
954
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
955
+ "input",
956
+ {
957
+ type: "number",
958
+ placeholder: "Min",
959
+ value: currentFilter?.min ?? "",
960
+ onChange: (e) => handleNumberChange(key, "min", e.target.value)
961
+ }
962
+ ),
963
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
964
+ "input",
965
+ {
966
+ type: "number",
967
+ placeholder: "Max",
968
+ value: currentFilter?.max ?? "",
969
+ onChange: (e) => handleNumberChange(key, "max", e.target.value)
970
+ }
971
+ )
972
+ ] }),
973
+ type === "date" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rst-filter-range", children: [
974
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
975
+ "input",
976
+ {
977
+ type: "date",
978
+ title: "Start Date",
979
+ value: currentFilter?.start || "",
980
+ onChange: (e) => handleDateChange(key, "start", e.target.value)
981
+ }
982
+ ),
983
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
984
+ "input",
985
+ {
986
+ type: "date",
987
+ title: "End Date",
988
+ value: currentFilter?.end || "",
989
+ onChange: (e) => handleDateChange(key, "end", e.target.value)
990
+ }
991
+ )
992
+ ] }),
993
+ type === "boolean" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
994
+ "button",
995
+ {
996
+ className: "rst-filter-toggle",
997
+ onClick: () => handleBooleanToggle(key),
998
+ style: {
999
+ backgroundColor: currentFilter === true ? "#e6f4ea" : currentFilter === false ? "#fce8e6" : "#fff"
1000
+ },
1001
+ children: currentFilter === true ? "Only Yes" : currentFilter === false ? "Only No" : "All"
1002
+ }
1003
+ )
1004
+ ] }, key);
1005
+ }),
1006
+ Object.keys(filters).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1007
+ "button",
1008
+ {
1009
+ className: "rst-filter-clear-btn",
1010
+ onClick: onClear,
1011
+ children: "Clear All Filters"
1012
+ }
1013
+ )
1014
+ ] });
1015
+ };
1016
+
1017
+ // src/components/InsightsPanel.tsx
1018
+ var import_react5 = require("react");
1019
+ var import_recharts = require("recharts");
1020
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1021
+ var COLORS = ["#8884d8", "#82ca9d", "#ffc658", "#ff8042", "#a4de6c", "#d0ed57"];
1022
+ var InsightsPanel = ({ data, schema }) => {
1023
+ const insights = (0, import_react5.useMemo)(() => {
1024
+ return generateInsights(data, schema);
1025
+ }, [data, schema]);
1026
+ if (!insights || insights.length === 0) {
1027
+ return null;
1028
+ }
1029
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rst-insights-panel", children: [
1030
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { children: "AI Generated Insights" }),
1031
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "rst-insights-grid", children: insights.map((widget) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "rst-insight-card", children: [
1032
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h4", { className: "rst-insight-title", children: widget.title }),
1033
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "rst-insight-chart-wrapper", style: { height: "240px" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.ResponsiveContainer, { width: "100%", height: "100%", children: widget.type === "bar" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_recharts.BarChart, { data: widget.data, margin: { top: 5, right: 10, left: 0, bottom: 5 }, children: [
1034
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
1035
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.XAxis, { dataKey: widget.xAxisKey, tick: { fontSize: 11, fill: "#64748b" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false }),
1036
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false }),
1037
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1038
+ import_recharts.Tooltip,
1039
+ {
1040
+ contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
1041
+ cursor: { fill: "#f1f5f9" }
1042
+ }
1043
+ ),
1044
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: "11px", paddingTop: "10px" }, iconType: "circle" }),
1045
+ widget.yAxisKeys.map((yKey, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Bar, { dataKey: yKey, fill: COLORS[index % COLORS.length], radius: [4, 4, 0, 0], barSize: 32 }, yKey))
1046
+ ] }) : widget.type === "line" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_recharts.LineChart, { data: widget.data, margin: { top: 5, right: 10, left: 0, bottom: 5 }, children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
1048
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.XAxis, { dataKey: widget.xAxisKey, tick: { fontSize: 11, fill: "#64748b" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false }),
1049
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, axisLine: { stroke: "#e2e8f0" }, tickLine: false }),
1050
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Tooltip, { contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" } }),
1051
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: "11px", paddingTop: "10px" }, iconType: "circle" }),
1052
+ widget.yAxisKeys.map((yKey, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Line, { type: "monotone", dataKey: yKey, stroke: COLORS[index % COLORS.length], strokeWidth: 2.5, dot: { r: 4, strokeWidth: 2, fill: "#fff" }, activeDot: { r: 6, strokeWidth: 0 } }, yKey))
1053
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_recharts.PieChart, { children: [
1054
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Tooltip, { contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" } }),
1055
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Legend, { wrapperStyle: { fontSize: "11px" }, iconType: "circle" }),
1056
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1057
+ import_recharts.Pie,
1058
+ {
1059
+ data: widget.data,
1060
+ cx: "50%",
1061
+ cy: "45%",
1062
+ innerRadius: 60,
1063
+ outerRadius: 80,
1064
+ fill: "#8884d8",
1065
+ paddingAngle: 5,
1066
+ dataKey: widget.yAxisKeys[0],
1067
+ nameKey: widget.xAxisKey,
1068
+ label: false,
1069
+ children: widget.data.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_recharts.Cell, { fill: COLORS[index % COLORS.length] }, `cell-${index}`))
1070
+ }
1071
+ )
1072
+ ] }) }) })
1073
+ ] }, widget.id)) })
1074
+ ] });
1075
+ };
1076
+
1077
+ // src/plugins/pluginRegistry.ts
1078
+ var PluginRegistry = class {
1079
+ constructor() {
1080
+ this.plugins = [];
1081
+ }
1082
+ register(pluginOrPlugins) {
1083
+ if (Array.isArray(pluginOrPlugins)) {
1084
+ this.plugins.push(...pluginOrPlugins);
1085
+ } else {
1086
+ this.plugins.push(pluginOrPlugins);
1087
+ }
1088
+ }
1089
+ clear() {
1090
+ this.plugins = [];
1091
+ }
1092
+ runDetectors(columnKey, sample) {
1093
+ for (const plugin of this.plugins) {
1094
+ if (plugin.detect) {
1095
+ const detectedType = plugin.detect(columnKey, sample);
1096
+ if (detectedType) {
1097
+ return detectedType;
1098
+ }
1099
+ }
1100
+ }
1101
+ return null;
1102
+ }
1103
+ getRenderers() {
1104
+ const renderers = {};
1105
+ for (const plugin of this.plugins) {
1106
+ }
1107
+ return renderers;
1108
+ }
1109
+ getPlugins() {
1110
+ return this.plugins;
1111
+ }
1112
+ };
1113
+ var globalPluginRegistry = new PluginRegistry();
1114
+
1115
+ // src/components/SmartTable.tsx
1116
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1117
+ var SmartTable = ({
1118
+ data,
1119
+ sortable = false,
1120
+ filterable = false,
1121
+ pagination = false,
1122
+ insights = false,
1123
+ plugins = []
1124
+ }) => {
1125
+ const registry = (0, import_react6.useMemo)(() => {
1126
+ const reg = new PluginRegistry();
1127
+ if (plugins && plugins.length > 0) {
1128
+ reg.register(plugins);
1129
+ }
1130
+ return reg;
1131
+ }, [plugins]);
1132
+ const schema = (0, import_react6.useMemo)(() => {
1133
+ return buildSchema(data, registry);
1134
+ }, [data, registry]);
1135
+ const { filteredData, filters, setFilter, clearFilters } = useFilters(data, schema);
1136
+ const dataToFilter = filterable ? filteredData : data;
1137
+ const { sortedData, sortColumn, sortDirection, handleSort } = useSorting(dataToFilter, schema);
1138
+ const dataToRenderOrPaginate = sortable ? sortedData : dataToFilter;
1139
+ const { paginatedData, currentPage, totalPages, setPage } = usePagination(dataToRenderOrPaginate, 10);
1140
+ const finalData = pagination ? paginatedData : dataToRenderOrPaginate;
1141
+ const [showFilters, setShowFilters] = import_react6.default.useState(true);
1142
+ if (!data || data.length === 0) {
1143
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rst-container", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rst-empty", children: "No data to display." }) });
1144
+ }
1145
+ const summaryStats = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rst-summary-strip", children: [
1146
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
1147
+ data.length,
1148
+ " Records"
1149
+ ] }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rst-dot", children: "\u2022" }),
1151
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
1152
+ Object.keys(schema).length,
1153
+ " Columns"
1154
+ ] }),
1155
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "rst-dot", children: "\u2022" }),
1156
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
1157
+ "Types: ",
1158
+ Array.from(new Set(Object.values(schema).map((c) => c.type))).join(", ")
1159
+ ] })
1160
+ ] });
1161
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rst-container", children: [
1162
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("header", { className: "rst-main-header", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-end" }, children: [
1163
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
1164
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { children: "Smart Table" }),
1165
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: "Auto-generated insights, filters, and records" })
1166
+ ] }),
1167
+ filterable && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1168
+ "button",
1169
+ {
1170
+ className: "rst-toggle-filters-btn",
1171
+ onClick: () => setShowFilters(!showFilters),
1172
+ children: [
1173
+ "Filters ",
1174
+ showFilters ? "\u25B2" : "\u25BC"
1175
+ ]
1176
+ }
1177
+ )
1178
+ ] }) }),
1179
+ insights && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(InsightsPanel, { data: dataToRenderOrPaginate, schema }),
1180
+ summaryStats,
1181
+ filterable && showFilters && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("section", { className: "rst-card", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1182
+ FilterPanel,
1183
+ {
1184
+ schema,
1185
+ filters,
1186
+ onFilterChange: setFilter,
1187
+ onClear: clearFilters
1188
+ }
1189
+ ) }),
1190
+ data.length > 0 && finalData.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rst-empty-results-card", children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rst-empty-icon", children: "\u{1F50D}" }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { children: "No results found" }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { children: "Try adjusting your filters to find what you're looking for." }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { className: "btn btn-primary", onClick: clearFilters, children: "Clear All Filters" })
1195
+ ] }),
1196
+ data.length > 0 && finalData.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { className: "rst-card", children: [
1197
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rst-table-container", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("table", { className: "rst-table", children: [
1198
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1199
+ TableHeader,
1200
+ {
1201
+ schema,
1202
+ sortable,
1203
+ sortColumn,
1204
+ sortDirection,
1205
+ onSort: handleSort
1206
+ }
1207
+ ),
1208
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TableBody, { data: finalData, schema, registry })
1209
+ ] }) }),
1210
+ pagination && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "rst-pagination", children: [
1211
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1212
+ "button",
1213
+ {
1214
+ disabled: currentPage === 1,
1215
+ onClick: () => setPage(currentPage - 1),
1216
+ children: "Previous"
1217
+ }
1218
+ ),
1219
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { children: [
1220
+ "Page ",
1221
+ currentPage,
1222
+ " of ",
1223
+ totalPages
1224
+ ] }),
1225
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1226
+ "button",
1227
+ {
1228
+ disabled: currentPage === totalPages,
1229
+ onClick: () => setPage(currentPage + 1),
1230
+ children: "Next"
1231
+ }
1232
+ )
1233
+ ] })
1234
+ ] })
1235
+ ] });
1236
+ };
1237
+ // Annotate the CommonJS export names for ESM import in node:
1238
+ 0 && (module.exports = {
1239
+ FilterPanel,
1240
+ InsightsPanel,
1241
+ PluginRegistry,
1242
+ SmartTable,
1243
+ aggregateData,
1244
+ aggregateDataByCount,
1245
+ buildSchema,
1246
+ computeColumnStats,
1247
+ currencyPlugin,
1248
+ detectChartFields,
1249
+ detectValueType,
1250
+ generateInsights,
1251
+ getCellRenderer,
1252
+ globalPluginRegistry,
1253
+ percentagePlugin,
1254
+ sampleDataset,
1255
+ useFilters,
1256
+ usePagination,
1257
+ useSorting
1258
+ });
1259
+ //# sourceMappingURL=index.js.map