@smallwebco/tinypivot-vue 1.0.71 → 1.0.73

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.
@@ -1 +1 @@
1
- {"version":3,"file":"tinypivot-vue.js","sources":["../../core/dist/ai/demo.js","../../core/dist/ai/prompts.js","../../core/dist/ai/session.js","../../core/dist/chart/index.js","../../core/dist/export/index.js","../../core/dist/license/index.js","../../core/dist/utils/index.js","../../core/dist/pivot/index.js","../../core/dist/types/index.js","../src/composables/useAIAnalyst.ts","../src/components/AIAnalyst.vue","../src/components/CalculatedFieldModal.vue","../src/components/ChartBuilder.vue","../src/components/DateRangeFilter.vue","../src/components/NumericRangeFilter.vue","../src/components/ColumnFilter.vue","../src/composables/useExcelGrid.ts","../src/composables/useGridFeatures.ts","../src/composables/useLicense.ts","../src/composables/usePivotTable.ts","../src/components/PivotConfig.vue","../src/components/PivotSkeleton.vue","../src/components/DataGrid.vue"],"sourcesContent":["/**\n * Demo data sources for the public demo\n */\nexport const DEMO_DATA_SOURCES = [\n {\n id: 'sales',\n table: 'sales_transactions',\n name: 'Sales Transactions',\n description: 'E-commerce sales data from 2022-2024 including orders, revenue, and customer information',\n },\n {\n id: 'customers',\n table: 'customers',\n name: 'Customer Data',\n description: 'Customer profiles including demographics, segments, and lifetime value',\n },\n {\n id: 'products',\n table: 'products',\n name: 'Product Catalog',\n description: 'Product information including categories, pricing, and inventory',\n },\n];\n/**\n * Demo schemas for the data sources\n */\nexport const DEMO_SCHEMAS = new Map([\n ['sales', {\n table: 'sales_transactions',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Transaction ID' },\n { name: 'date', type: 'date', nullable: false, description: 'Transaction date' },\n { name: 'customer_id', type: 'number', nullable: false, description: 'Customer reference' },\n { name: 'product_id', type: 'number', nullable: false, description: 'Product reference' },\n { name: 'quantity', type: 'number', nullable: false, description: 'Units sold' },\n { name: 'revenue', type: 'number', nullable: false, description: 'Total sale amount in USD' },\n { name: 'region', type: 'string', nullable: false, description: 'Sales region (North, South, East, West)' },\n { name: 'channel', type: 'string', nullable: false, description: 'Sales channel (Online, Retail, Wholesale)' },\n ],\n }],\n ['customers', {\n table: 'customers',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Customer ID' },\n { name: 'name', type: 'string', nullable: false, description: 'Customer name' },\n { name: 'email', type: 'string', nullable: false, description: 'Email address' },\n { name: 'segment', type: 'string', nullable: false, description: 'Customer segment (Enterprise, SMB, Consumer)' },\n { name: 'country', type: 'string', nullable: false, description: 'Country' },\n { name: 'created_at', type: 'date', nullable: false, description: 'Account creation date' },\n { name: 'lifetime_value', type: 'number', nullable: true, description: 'Total lifetime spend in USD' },\n ],\n }],\n ['products', {\n table: 'products',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Product ID' },\n { name: 'name', type: 'string', nullable: false, description: 'Product name' },\n { name: 'category', type: 'string', nullable: false, description: 'Product category' },\n { name: 'price', type: 'number', nullable: false, description: 'Unit price in USD' },\n { name: 'cost', type: 'number', nullable: false, description: 'Unit cost in USD' },\n { name: 'stock', type: 'number', nullable: false, description: 'Current inventory' },\n ],\n }],\n]);\n/**\n * Demo scenarios with canned responses\n */\nexport const DEMO_SCENARIOS = [\n {\n dataSourceId: 'sales',\n initialData: [\n { id: 1, date: '2024-12-01', customer_id: 1001, product_id: 101, quantity: 2, revenue: 599.98, region: 'West', channel: 'Online' },\n { id: 2, date: '2024-12-01', customer_id: 1042, product_id: 203, quantity: 1, revenue: 849.99, region: 'North', channel: 'Retail' },\n { id: 3, date: '2024-12-02', customer_id: 1015, product_id: 105, quantity: 5, revenue: 149.95, region: 'East', channel: 'Online' },\n { id: 4, date: '2024-12-02', customer_id: 1088, product_id: 302, quantity: 1, revenue: 1299.00, region: 'West', channel: 'Wholesale' },\n { id: 5, date: '2024-12-03', customer_id: 1023, product_id: 118, quantity: 3, revenue: 89.97, region: 'South', channel: 'Online' },\n { id: 6, date: '2024-12-03', customer_id: 1056, product_id: 209, quantity: 2, revenue: 459.98, region: 'North', channel: 'Retail' },\n { id: 7, date: '2024-12-04', customer_id: 1077, product_id: 115, quantity: 1, revenue: 199.99, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-04', customer_id: 1034, product_id: 301, quantity: 4, revenue: 2199.96, region: 'West', channel: 'Wholesale' },\n { id: 9, date: '2024-12-05', customer_id: 1091, product_id: 122, quantity: 2, revenue: 339.98, region: 'South', channel: 'Retail' },\n { id: 10, date: '2024-12-05', customer_id: 1012, product_id: 207, quantity: 1, revenue: 749.99, region: 'North', channel: 'Online' },\n ],\n defaultResponse: `I can help you explore the sales transactions data. Here are some things you can ask me:\n\n- \"Show me total revenue by region\"\n- \"What are the top selling products?\"\n- \"Show me sales trends over time\"\n- \"Which sales channel performs best?\"\n- \"Show me sales with customer names\" (JOIN example)\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['revenue', 'region'],\n response: `I'll query the sales table to show total revenue broken down by region.\n\nHere's my approach:\n1. **regional_summary**: Group all transactions by region and calculate totals\n\n\\`\\`\\`sql\n-- Calculate revenue and transaction counts for each region\nWITH regional_summary AS (\n SELECT \n region,\n SUM(revenue) as total_revenue,\n COUNT(*) as transaction_count\n FROM sales_transactions\n GROUP BY region\n)\n-- Return regions sorted by revenue (highest first)\nSELECT * FROM regional_summary\nORDER BY total_revenue DESC\n\\`\\`\\`\n\nThe results show revenue performance across all four regions. The data is now loaded in the grid - you can use the Pivot or Chart views to visualize it further.`,\n query: 'WITH regional_summary AS (SELECT region, SUM(revenue) as total_revenue, COUNT(*) as transaction_count FROM sales_transactions GROUP BY region) SELECT * FROM regional_summary ORDER BY total_revenue DESC',\n mockData: [\n { region: 'West', total_revenue: 1250000, transaction_count: 3420 },\n { region: 'North', total_revenue: 980000, transaction_count: 2890 },\n { region: 'East', total_revenue: 875000, transaction_count: 2650 },\n { region: 'South', total_revenue: 720000, transaction_count: 2140 },\n ],\n },\n {\n keywords: ['top', 'product', 'best', 'selling'],\n response: `I'll find the top selling products by revenue.\n\nHere's my approach:\n1. **product_totals**: Sum up revenue and units for each product\n2. **ranked_products**: Take only the top 10 performers\n\n\\`\\`\\`sql\n-- Aggregate sales by product\nWITH product_totals AS (\n SELECT \n product_id,\n SUM(revenue) as total_revenue,\n SUM(quantity) as units_sold\n FROM sales_transactions\n GROUP BY product_id\n),\n-- Rank and limit to top performers\nranked_products AS (\n SELECT * FROM product_totals\n ORDER BY total_revenue DESC\n LIMIT 10\n)\nSELECT * FROM ranked_products\n\\`\\`\\`\n\nHere are the top 10 products by revenue. You might want to join this with the Products table to see product names.`,\n query: 'WITH product_totals AS (SELECT product_id, SUM(revenue) as total_revenue, SUM(quantity) as units_sold FROM sales_transactions GROUP BY product_id), ranked_products AS (SELECT * FROM product_totals ORDER BY total_revenue DESC LIMIT 10) SELECT * FROM ranked_products',\n mockData: [\n { product_id: 101, total_revenue: 425000, units_sold: 1250 },\n { product_id: 203, total_revenue: 380000, units_sold: 890 },\n { product_id: 105, total_revenue: 315000, units_sold: 2100 },\n { product_id: 302, total_revenue: 290000, units_sold: 560 },\n { product_id: 118, total_revenue: 245000, units_sold: 1800 },\n { product_id: 209, total_revenue: 220000, units_sold: 750 },\n { product_id: 115, total_revenue: 195000, units_sold: 1400 },\n { product_id: 301, total_revenue: 180000, units_sold: 320 },\n { product_id: 122, total_revenue: 165000, units_sold: 980 },\n { product_id: 207, total_revenue: 155000, units_sold: 620 },\n ],\n },\n {\n keywords: ['trend', 'time', 'month', 'over time'],\n response: `I'll show you the sales trends over time, grouped by month.\n\nHere's my approach:\n1. **monthly_metrics**: Truncate dates to month and aggregate revenue/transactions\n\n\\`\\`\\`sql\n-- Group transactions by month and calculate totals\nWITH monthly_metrics AS (\n SELECT \n DATE_TRUNC('month', date) as month,\n SUM(revenue) as monthly_revenue,\n COUNT(*) as transactions\n FROM sales_transactions\n GROUP BY DATE_TRUNC('month', date)\n)\n-- Return in chronological order\nSELECT * FROM monthly_metrics\nORDER BY month\n\\`\\`\\`\n\nThe data shows monthly revenue trends. Try using the Chart view with a Line chart to visualize this trend!`,\n query: 'WITH monthly_metrics AS (SELECT DATE_TRUNC(\\'month\\', date) as month, SUM(revenue) as monthly_revenue, COUNT(*) as transactions FROM sales_transactions GROUP BY DATE_TRUNC(\\'month\\', date)) SELECT * FROM monthly_metrics ORDER BY month',\n mockData: [\n { month: '2024-01-01', monthly_revenue: 285000, transactions: 820 },\n { month: '2024-02-01', monthly_revenue: 310000, transactions: 890 },\n { month: '2024-03-01', monthly_revenue: 345000, transactions: 950 },\n { month: '2024-04-01', monthly_revenue: 320000, transactions: 910 },\n { month: '2024-05-01', monthly_revenue: 380000, transactions: 1050 },\n { month: '2024-06-01', monthly_revenue: 410000, transactions: 1120 },\n { month: '2024-07-01', monthly_revenue: 395000, transactions: 1080 },\n { month: '2024-08-01', monthly_revenue: 425000, transactions: 1150 },\n { month: '2024-09-01', monthly_revenue: 390000, transactions: 1060 },\n { month: '2024-10-01', monthly_revenue: 445000, transactions: 1200 },\n { month: '2024-11-01', monthly_revenue: 520000, transactions: 1380 },\n { month: '2024-12-01', monthly_revenue: 480000, transactions: 1290 },\n ],\n },\n {\n keywords: ['channel', 'online', 'retail', 'wholesale'],\n response: `I'll compare performance across sales channels.\n\nHere's my approach:\n1. **channel_metrics**: Calculate total revenue, transaction count, and average order value per channel\n\n\\`\\`\\`sql\n-- Aggregate key metrics by sales channel\nWITH channel_metrics AS (\n SELECT \n channel,\n SUM(revenue) as total_revenue,\n COUNT(*) as transactions,\n AVG(revenue) as avg_order_value\n FROM sales_transactions\n GROUP BY channel\n)\n-- Return sorted by total revenue\nSELECT * FROM channel_metrics\nORDER BY total_revenue DESC\n\\`\\`\\`\n\nThis shows revenue and average order value by channel. Online has the highest volume while Wholesale has the highest average order value.`,\n query: 'WITH channel_metrics AS (SELECT channel, SUM(revenue) as total_revenue, COUNT(*) as transactions, AVG(revenue) as avg_order_value FROM sales_transactions GROUP BY channel) SELECT * FROM channel_metrics ORDER BY total_revenue DESC',\n mockData: [\n { channel: 'Online', total_revenue: 1850000, transactions: 6500, avg_order_value: 284.62 },\n { channel: 'Retail', total_revenue: 1200000, transactions: 3800, avg_order_value: 315.79 },\n { channel: 'Wholesale', total_revenue: 775000, transactions: 800, avg_order_value: 968.75 },\n ],\n },\n {\n keywords: ['customer name', 'with customer', 'join customer', 'customer info'],\n response: `I'll join the sales data with customers to show you sales with customer names.\n\nHere's my approach:\n1. **JOIN**: Link sales_transactions with customers table on customer_id\n\n\\`\\`\\`sql\n-- Join sales with customer information\nSELECT \n s.id,\n s.date,\n c.name as customer_name,\n c.segment,\n s.revenue,\n s.quantity,\n s.region,\n s.channel\nFROM sales_transactions s\nJOIN customers c ON s.customer_id = c.id\nORDER BY s.date DESC\n\\`\\`\\`\n\nHere are the sales records enriched with customer names and segments. You can now filter or pivot by customer segment!`,\n query: 'SELECT s.id, s.date, c.name as customer_name, c.segment, s.revenue, s.quantity, s.region, s.channel FROM sales_transactions s JOIN customers c ON s.customer_id = c.id ORDER BY s.date DESC',\n mockData: [\n { id: 1, date: '2024-12-05', customer_name: 'Acme Corporation', segment: 'Enterprise', revenue: 2499.99, quantity: 5, region: 'West', channel: 'Wholesale' },\n { id: 2, date: '2024-12-05', customer_name: 'Jane Smith', segment: 'Consumer', revenue: 149.99, quantity: 2, region: 'North', channel: 'Online' },\n { id: 3, date: '2024-12-04', customer_name: 'TechStart Inc', segment: 'SMB', revenue: 899.97, quantity: 3, region: 'East', channel: 'Retail' },\n { id: 4, date: '2024-12-04', customer_name: 'Global Industries', segment: 'Enterprise', revenue: 4599.99, quantity: 10, region: 'West', channel: 'Wholesale' },\n { id: 5, date: '2024-12-03', customer_name: 'John Doe', segment: 'Consumer', revenue: 79.99, quantity: 1, region: 'South', channel: 'Online' },\n { id: 6, date: '2024-12-03', customer_name: 'Nordic Solutions', segment: 'Enterprise', revenue: 1899.99, quantity: 4, region: 'North', channel: 'Retail' },\n { id: 7, date: '2024-12-02', customer_name: 'Boutique Shop', segment: 'SMB', revenue: 449.97, quantity: 3, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-02', customer_name: 'Maria Garcia', segment: 'Consumer', revenue: 129.99, quantity: 1, region: 'South', channel: 'Online' },\n { id: 9, date: '2024-12-01', customer_name: 'Local Crafts Co', segment: 'SMB', revenue: 679.98, quantity: 2, region: 'West', channel: 'Retail' },\n { id: 10, date: '2024-12-01', customer_name: 'Alex Johnson', segment: 'Consumer', revenue: 59.99, quantity: 1, region: 'North', channel: 'Online' },\n ],\n },\n {\n keywords: ['product name', 'with product', 'join product', 'product info', 'product detail'],\n response: `I'll join the sales data with products to show you sales with product details.\n\nHere's my approach:\n1. **JOIN**: Link sales_transactions with products table on product_id\n\n\\`\\`\\`sql\n-- Join sales with product information\nSELECT \n s.id,\n s.date,\n p.name as product_name,\n p.category,\n s.quantity,\n s.revenue,\n s.region,\n s.channel\nFROM sales_transactions s\nJOIN products p ON s.product_id = p.id\nORDER BY s.revenue DESC\n\\`\\`\\`\n\nHere are the sales records enriched with product names and categories. Try pivoting by category to see which product types sell best!`,\n query: 'SELECT s.id, s.date, p.name as product_name, p.category, s.quantity, s.revenue, s.region, s.channel FROM sales_transactions s JOIN products p ON s.product_id = p.id ORDER BY s.revenue DESC',\n mockData: [\n { id: 1, date: '2024-12-04', product_name: 'Standing Desk Frame', category: 'Home & Garden', quantity: 3, revenue: 1049.97, region: 'West', channel: 'Wholesale' },\n { id: 2, date: '2024-12-05', product_name: 'Bluetooth Headphones', category: 'Electronics', quantity: 4, revenue: 599.96, region: 'North', channel: 'Retail' },\n { id: 3, date: '2024-12-03', product_name: 'Running Shoes Elite', category: 'Sports', quantity: 3, revenue: 389.97, region: 'East', channel: 'Online' },\n { id: 4, date: '2024-12-02', product_name: 'Wireless Mouse Pro', category: 'Electronics', quantity: 4, revenue: 319.96, region: 'South', channel: 'Online' },\n { id: 5, date: '2024-12-05', product_name: 'Denim Jeans Classic', category: 'Clothing', quantity: 3, revenue: 209.97, region: 'West', channel: 'Retail' },\n { id: 6, date: '2024-12-01', product_name: 'Garden Tool Set', category: 'Home & Garden', quantity: 2, revenue: 179.98, region: 'North', channel: 'Online' },\n { id: 7, date: '2024-12-04', product_name: 'Yoga Mat Premium', category: 'Sports', quantity: 3, revenue: 137.97, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-03', product_name: 'Cotton T-Shirt Basic', category: 'Clothing', quantity: 5, revenue: 124.95, region: 'South', channel: 'Online' },\n { id: 9, date: '2024-12-02', product_name: 'Clean Code', category: 'Books', quantity: 2, revenue: 69.98, region: 'West', channel: 'Online' },\n { id: 10, date: '2024-12-01', product_name: 'JavaScript: The Good Parts', category: 'Books', quantity: 2, revenue: 59.98, region: 'North', channel: 'Online' },\n ],\n },\n ],\n },\n {\n dataSourceId: 'customers',\n initialData: [\n { id: 1001, name: 'Acme Corporation', email: 'contact@acme.com', segment: 'Enterprise', country: 'United States', created_at: '2022-03-15', lifetime_value: 45000 },\n { id: 1002, name: 'Jane Smith', email: 'jane.smith@email.com', segment: 'Consumer', country: 'United Kingdom', created_at: '2023-06-22', lifetime_value: 850 },\n { id: 1003, name: 'TechStart Inc', email: 'info@techstart.io', segment: 'SMB', country: 'Germany', created_at: '2023-01-10', lifetime_value: 3200 },\n { id: 1004, name: 'Global Industries', email: 'sales@globalind.com', segment: 'Enterprise', country: 'United States', created_at: '2021-11-08', lifetime_value: 78500 },\n { id: 1005, name: 'John Doe', email: 'johndoe@gmail.com', segment: 'Consumer', country: 'Canada', created_at: '2024-02-14', lifetime_value: 320 },\n { id: 1006, name: 'Boutique Shop', email: 'hello@boutique.fr', segment: 'SMB', country: 'France', created_at: '2023-08-30', lifetime_value: 1800 },\n { id: 1007, name: 'Maria Garcia', email: 'maria.g@outlook.com', segment: 'Consumer', country: 'Spain', created_at: '2024-05-19', lifetime_value: 450 },\n { id: 1008, name: 'Nordic Solutions', email: 'contact@nordic.se', segment: 'Enterprise', country: 'Sweden', created_at: '2022-07-03', lifetime_value: 32000 },\n { id: 1009, name: 'Local Crafts Co', email: 'orders@localcrafts.au', segment: 'SMB', country: 'Australia', created_at: '2023-11-25', lifetime_value: 2100 },\n { id: 1010, name: 'Alex Johnson', email: 'alex.j@proton.me', segment: 'Consumer', country: 'United States', created_at: '2024-09-02', lifetime_value: 180 },\n ],\n defaultResponse: `I can help you explore the customer data. Here are some things you can ask me:\n\n- \"Show me customers by segment\"\n- \"What's the average lifetime value?\"\n- \"Which countries have the most customers?\"\n- \"Show me recent signups\"\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['segment', 'breakdown'],\n response: `I'll show you the customer breakdown by segment.\n\n\\`\\`\\`sql\nSELECT segment, COUNT(*) as customer_count, AVG(lifetime_value) as avg_ltv\nFROM customers\nGROUP BY segment\nORDER BY customer_count DESC\n\\`\\`\\`\n\nHere's the distribution across segments. Enterprise customers have the highest average lifetime value.`,\n query: 'SELECT segment, COUNT(*) as customer_count, AVG(lifetime_value) as avg_ltv FROM customers GROUP BY segment ORDER BY customer_count DESC',\n mockData: [\n { segment: 'Consumer', customer_count: 8500, avg_ltv: 450 },\n { segment: 'SMB', customer_count: 2800, avg_ltv: 2200 },\n { segment: 'Enterprise', customer_count: 450, avg_ltv: 18500 },\n ],\n },\n {\n keywords: ['lifetime', 'value', 'ltv'],\n response: `I'll calculate lifetime value statistics across the customer base.\n\n\\`\\`\\`sql\nSELECT \n COUNT(*) as total_customers,\n AVG(lifetime_value) as avg_ltv,\n MAX(lifetime_value) as max_ltv,\n MIN(lifetime_value) as min_ltv,\n SUM(lifetime_value) as total_ltv\nFROM customers\n\\`\\`\\`\n\nThe average customer lifetime value is $1,250 with significant variation between segments.`,\n query: 'SELECT COUNT(*) as total_customers, AVG(lifetime_value) as avg_ltv, MAX(lifetime_value) as max_ltv, MIN(lifetime_value) as min_ltv, SUM(lifetime_value) as total_ltv FROM customers',\n mockData: [\n { total_customers: 11750, avg_ltv: 1250, max_ltv: 85000, min_ltv: 25, total_ltv: 14687500 },\n ],\n },\n {\n keywords: ['country', 'countries', 'location'],\n response: `I'll show you the customer distribution by country.\n\n\\`\\`\\`sql\nSELECT country, COUNT(*) as customer_count, SUM(lifetime_value) as total_ltv\nFROM customers\nGROUP BY country\nORDER BY customer_count DESC\nLIMIT 10\n\\`\\`\\`\n\nHere are the top 10 countries by customer count.`,\n query: 'SELECT country, COUNT(*) as customer_count, SUM(lifetime_value) as total_ltv FROM customers GROUP BY country ORDER BY customer_count DESC LIMIT 10',\n mockData: [\n { country: 'United States', customer_count: 4200, total_ltv: 5800000 },\n { country: 'United Kingdom', customer_count: 1850, total_ltv: 2100000 },\n { country: 'Germany', customer_count: 1200, total_ltv: 1450000 },\n { country: 'Canada', customer_count: 980, total_ltv: 1100000 },\n { country: 'France', customer_count: 750, total_ltv: 890000 },\n { country: 'Australia', customer_count: 620, total_ltv: 720000 },\n { country: 'Japan', customer_count: 480, total_ltv: 650000 },\n { country: 'Netherlands', customer_count: 350, total_ltv: 420000 },\n { country: 'Spain', customer_count: 290, total_ltv: 340000 },\n { country: 'Italy', customer_count: 250, total_ltv: 280000 },\n ],\n },\n ],\n },\n {\n dataSourceId: 'products',\n initialData: [\n { id: 101, name: 'Wireless Mouse Pro', category: 'Electronics', price: 79.99, cost: 35.00, stock: 450 },\n { id: 102, name: 'Cotton T-Shirt Basic', category: 'Clothing', price: 24.99, cost: 8.50, stock: 1200 },\n { id: 103, name: 'Standing Desk Frame', category: 'Home & Garden', price: 349.99, cost: 180.00, stock: 85 },\n { id: 104, name: 'Running Shoes Elite', category: 'Sports', price: 129.99, cost: 55.00, stock: 320 },\n { id: 105, name: 'JavaScript: The Good Parts', category: 'Books', price: 29.99, cost: 10.00, stock: 580 },\n { id: 106, name: 'Bluetooth Headphones', category: 'Electronics', price: 149.99, cost: 65.00, stock: 280 },\n { id: 107, name: 'Denim Jeans Classic', category: 'Clothing', price: 69.99, cost: 28.00, stock: 890 },\n { id: 108, name: 'Garden Tool Set', category: 'Home & Garden', price: 89.99, cost: 38.00, stock: 150 },\n { id: 109, name: 'Yoga Mat Premium', category: 'Sports', price: 45.99, cost: 18.00, stock: 420 },\n { id: 110, name: 'Clean Code', category: 'Books', price: 34.99, cost: 12.00, stock: 340 },\n ],\n defaultResponse: `I can help you explore the product catalog. Here are some things you can ask me:\n\n- \"Show me products by category\"\n- \"What are the profit margins?\"\n- \"Which products are low on stock?\"\n- \"Show me the price distribution\"\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['category', 'categories'],\n response: `I'll show you the product breakdown by category.\n\n\\`\\`\\`sql\nSELECT category, COUNT(*) as product_count, AVG(price) as avg_price, SUM(stock) as total_stock\nFROM products\nGROUP BY category\nORDER BY product_count DESC\n\\`\\`\\`\n\nHere's the distribution of products across categories.`,\n query: 'SELECT category, COUNT(*) as product_count, AVG(price) as avg_price, SUM(stock) as total_stock FROM products GROUP BY category ORDER BY product_count DESC',\n mockData: [\n { category: 'Electronics', product_count: 450, avg_price: 299.99, total_stock: 12500 },\n { category: 'Clothing', product_count: 380, avg_price: 59.99, total_stock: 28000 },\n { category: 'Home & Garden', product_count: 290, avg_price: 89.99, total_stock: 15000 },\n { category: 'Sports', product_count: 220, avg_price: 79.99, total_stock: 9500 },\n { category: 'Books', product_count: 180, avg_price: 24.99, total_stock: 22000 },\n ],\n },\n {\n keywords: ['margin', 'profit', 'cost'],\n response: `I'll calculate the profit margins by category.\n\n\\`\\`\\`sql\nSELECT category, AVG(price) as avg_price, AVG(cost) as avg_cost, AVG(price - cost) as avg_margin, AVG((price - cost) / price * 100) as margin_percent\nFROM products\nGROUP BY category\nORDER BY margin_percent DESC\n\\`\\`\\`\n\nHere are the profit margins. Electronics has the highest absolute margin while Books has the best percentage margin.`,\n query: 'SELECT category, AVG(price) as avg_price, AVG(cost) as avg_cost, AVG(price - cost) as avg_margin, AVG((price - cost) / price * 100) as margin_percent FROM products GROUP BY category ORDER BY margin_percent DESC',\n mockData: [\n { category: 'Books', avg_price: 24.99, avg_cost: 8.50, avg_margin: 16.49, margin_percent: 65.99 },\n { category: 'Clothing', avg_price: 59.99, avg_cost: 22.00, avg_margin: 37.99, margin_percent: 63.33 },\n { category: 'Home & Garden', avg_price: 89.99, avg_cost: 38.00, avg_margin: 51.99, margin_percent: 57.77 },\n { category: 'Sports', avg_price: 79.99, avg_cost: 35.00, avg_margin: 44.99, margin_percent: 56.24 },\n { category: 'Electronics', avg_price: 299.99, avg_cost: 180.00, avg_margin: 119.99, margin_percent: 40.00 },\n ],\n },\n {\n keywords: ['stock', 'inventory', 'low'],\n response: `I'll find products with low stock levels.\n\n\\`\\`\\`sql\nSELECT name, category, stock, price\nFROM products\nWHERE stock < 50\nORDER BY stock ASC\nLIMIT 20\n\\`\\`\\`\n\nThese products are running low on inventory and may need restocking soon.`,\n query: 'SELECT name, category, stock, price FROM products WHERE stock < 50 ORDER BY stock ASC LIMIT 20',\n mockData: [\n { name: 'Premium Headphones Pro', category: 'Electronics', stock: 5, price: 349.99 },\n { name: 'Vintage Leather Jacket', category: 'Clothing', stock: 8, price: 299.99 },\n { name: 'Smart Home Hub', category: 'Electronics', stock: 12, price: 199.99 },\n { name: 'Designer Sunglasses', category: 'Clothing', stock: 15, price: 189.99 },\n { name: 'Ergonomic Office Chair', category: 'Home & Garden', stock: 18, price: 449.99 },\n { name: 'Wireless Earbuds Elite', category: 'Electronics', stock: 22, price: 179.99 },\n { name: 'Cashmere Sweater', category: 'Clothing', stock: 25, price: 249.99 },\n { name: 'Smart Watch Series X', category: 'Electronics', stock: 28, price: 399.99 },\n { name: 'Premium Yoga Mat', category: 'Sports', stock: 32, price: 89.99 },\n { name: 'Espresso Machine Pro', category: 'Home & Garden', stock: 35, price: 599.99 },\n ],\n },\n ],\n },\n];\n/**\n * Find a matching demo response for a user message\n */\nexport function findDemoResponse(dataSourceId, userMessage) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n if (!scenario) {\n return null;\n }\n const lowerMessage = userMessage.toLowerCase();\n for (const trigger of scenario.triggers) {\n const hasMatch = trigger.keywords.some(keyword => lowerMessage.includes(keyword.toLowerCase()));\n if (hasMatch) {\n return trigger;\n }\n }\n return null;\n}\n/**\n * Get the default response for a data source when no trigger matches\n */\nexport function getDefaultDemoResponse(dataSourceId) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n return scenario?.defaultResponse || 'Please select a data source to get started.';\n}\n/**\n * Get demo schema for a data source\n */\nexport function getDemoSchema(dataSourceId) {\n return DEMO_SCHEMAS.get(dataSourceId);\n}\n/**\n * Get initial sample data for a data source (shown when first selected)\n */\nexport function getInitialDemoData(dataSourceId) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n return scenario?.initialData;\n}\n//# sourceMappingURL=demo.js.map","/**\n * Build the system prompt for the AI Data Analyst\n * @param dataSources - List of available data sources\n * @param schemas - Map of table schemas (selected table schema)\n * @param selectedSourceId - Currently selected data source ID\n * @param allSchemas - Optional: ALL table schemas for enabling JOINs\n */\nexport function buildSystemPrompt(dataSources, schemas, selectedSourceId, allSchemas) {\n const selectedSchema = selectedSourceId ? schemas.get(selectedSourceId) : undefined;\n const selectedSource = selectedSourceId\n ? dataSources.find(ds => ds.id === selectedSourceId)\n : undefined;\n // Filter out the selected table from allSchemas to get \"other tables\"\n const otherTables = allSchemas?.filter(s => s.table !== selectedSchema?.table) || [];\n return `You are a data analyst assistant. Your job is to translate user questions into SQL queries and return data results.\n\n## CRITICAL: ALWAYS GENERATE A SQL QUERY\n**Every response MUST include a SQL query.** The user is here to explore data - they expect to see results.\n- If the user asks a question → Generate a query to answer it\n- If the user says \"show me\" or \"what are\" → Generate a query\n- If the user asks for trends/patterns → Generate an aggregation query\n- If the question is vague → Make reasonable assumptions and generate a query anyway\n- If you're unsure what they want → Generate a sensible default query (like top 10 rows with key columns)\n\n**NEVER respond with only text. ALWAYS include a SQL query in your response.**\n\n## Available Data Sources\n${formatDataSourcesList(dataSources)}\n\n${selectedSource && selectedSchema ? formatSelectedSchemaContext(selectedSource, selectedSchema) : '## No Data Source Selected\\nPlease ask the user to select a data source first.'}\n\n${otherTables.length > 0 ? formatRelatedTablesContext(otherTables) : ''}\n\n## Query Rules\n1. **READ-ONLY**: ONLY use SELECT. NEVER use INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, or any write operations.\n2. **NO LIMIT**: Do NOT add LIMIT clauses unless the user explicitly asks for a limited number of results. Return all matching rows by default.\n3. **PRIMARY TABLE**: The main table is \\`${selectedSchema?.table || 'table_name'}\\`\n4. **JOINs ALLOWED**: You CAN JOIN with other tables listed in \"Related Tables\" when the user needs data from multiple tables.\n5. **BE SPECIFIC**: Select relevant columns, not SELECT * (unless showing sample data)\n\n## Query Format\nOutput queries in this EXACT format (the system auto-executes SQL blocks):\n\n\\`\\`\\`sql\nSELECT column1, column2 FROM ${selectedSchema?.table || 'table_name'} WHERE condition\n\\`\\`\\`\n\nFor JOINs (when user needs data from related tables):\n\\`\\`\\`sql\nSELECT p.column1, r.column2 \nFROM ${selectedSchema?.table || 'primary_table'} p\nJOIN related_table r ON p.foreign_key = r.id\nWHERE condition\n\\`\\`\\`\n\nFor complex analysis, use CTEs:\n\\`\\`\\`sql\nWITH summary AS (\n SELECT category, COUNT(*) as count\n FROM ${selectedSchema?.table || 'table_name'}\n GROUP BY category\n)\nSELECT * FROM summary ORDER BY count DESC\n\\`\\`\\`\n\n## Response Format\nKeep responses concise and insight-focused:\n1. **Start with the SQL query** in a code block (REQUIRED) - this will be extracted and hidden from the user\n2. **Then provide your insight/analysis** (2-3 sentences) explaining what the data shows\n3. **Optional**: Suggest 1-2 follow-up questions\n\n**IMPORTANT**: The SQL block is automatically extracted and shown separately. Your text response should focus on INSIGHTS about the data, not describing the query itself. Don't say \"I'm querying...\" or \"This query shows...\". Instead, provide the analytical insight directly.\n\nExample response:\n\"\\`\\`\\`sql\nSELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department ORDER BY avg_salary DESC\n\\`\\`\\`\n\nEngineering and Product teams have the highest average salaries at $145K and $138K respectively, while Support and Operations are at the lower end around $75K. This 2x salary gap may indicate market-driven compensation or role complexity differences.\n\nWant to see how this breaks down by job level?\"\n\n## If Query Fails\n- Acknowledge the error briefly\n- Provide a corrected query immediately\n- Don't apologize excessively, just fix it`;\n}\n/**\n * Format the list of available data sources for the prompt\n */\nfunction formatDataSourcesList(dataSources) {\n if (dataSources.length === 0) {\n return 'No data sources configured.';\n }\n return dataSources\n .map((ds) => {\n const desc = ds.description ? `: ${ds.description}` : '';\n return `- **${ds.name}** (${ds.table})${desc}`;\n })\n .join('\\n');\n}\n/**\n * Format the schema context for the currently selected data source\n */\nfunction formatSelectedSchemaContext(source, schema) {\n // Filter out hidden columns\n const visibleColumns = schema.columns.filter((col) => {\n const override = source.columns?.find(c => c.name === col.name);\n return !override?.hidden;\n });\n // Merge descriptions from overrides\n const columnsWithDescriptions = visibleColumns.map((col) => {\n const override = source.columns?.find(c => c.name === col.name);\n return {\n ...col,\n description: override?.description || col.description,\n };\n });\n return `## Currently Selected: ${source.name}\nTable: \\`${schema.table}\\`\n${source.description ? `Description: ${source.description}` : ''}\n\n### Columns\n${formatColumnsTable(columnsWithDescriptions)}\n\n### Query Tips\n- Use column names exactly as shown above\n- The table name is \\`${schema.table}\\`\n- For text searches, use ILIKE for case-insensitive matching\n- For date columns, use standard SQL date functions`;\n}\n/**\n * Format the context for related tables that can be JOINed\n */\nfunction formatRelatedTablesContext(tables) {\n if (tables.length === 0)\n return '';\n const tablesSummary = tables.map((table) => {\n // Show table name and key columns (likely join keys)\n const keyColumns = table.columns\n .filter(col => col.name === 'id'\n || col.name.endsWith('_id')\n || col.name.startsWith('id_')\n || col.name === 'uuid')\n .map(col => `\\`${col.name}\\``)\n .join(', ');\n const otherColumns = table.columns\n .filter(col => col.name !== 'id'\n && !col.name.endsWith('_id')\n && !col.name.startsWith('id_')\n && col.name !== 'uuid')\n .slice(0, 5) // Show up to 5 other columns\n .map(col => `\\`${col.name}\\` (${col.type})`)\n .join(', ');\n const moreCount = table.columns.length - (keyColumns ? keyColumns.split(',').length : 0) - 5;\n const moreText = moreCount > 0 ? `, +${moreCount} more` : '';\n return `- **\\`${table.table}\\`**\n - Keys: ${keyColumns || 'none'}\n - Columns: ${otherColumns}${moreText}`;\n }).join('\\n');\n return `## Related Tables (Available for JOINs)\nYou can JOIN with these tables when the user needs additional data.\nLook for foreign key relationships (columns ending in \\`_id\\`).\n\n${tablesSummary}\n`;\n}\n/**\n * Format columns as a readable table for the prompt\n */\nfunction formatColumnsTable(columns) {\n return columns\n .map((col) => {\n const nullable = col.nullable ? 'nullable' : 'required';\n const desc = col.description ? ` - ${col.description}` : '';\n return `- \\`${col.name}\\` (${col.type}, ${nullable})${desc}`;\n })\n .join('\\n');\n}\n/**\n * Build a user message with additional context\n */\nexport function buildUserMessage(userInput, context) {\n let message = userInput;\n if (context?.previousQueryFailed && context.errorMessage) {\n message = `[Previous query failed: ${context.errorMessage}]\\n\\n${userInput}`;\n }\n return message;\n}\n/**\n * Extract SQL query from AI response\n * Returns the SQL if found, null otherwise\n */\nexport function extractSQLFromResponse(response) {\n // Match SQL code blocks\n const sqlBlockRegex = /```sql\\s*([\\s\\S]*?)```/i;\n const match = response.match(sqlBlockRegex);\n if (match && match[1]) {\n const sql = match[1].trim();\n // Validate it's a SELECT statement\n if (!sql.toUpperCase().startsWith('SELECT')) {\n return null;\n }\n return sql;\n }\n return null;\n}\n/**\n * Validate that a SQL query is safe (read-only)\n */\nexport function validateSQLSafety(sql) {\n const upperSQL = sql.toUpperCase().trim();\n // Must start with SELECT or WITH (for CTEs)\n if (!upperSQL.startsWith('SELECT') && !upperSQL.startsWith('WITH')) {\n return { valid: false, error: 'Only SELECT queries (including CTEs with WITH) are allowed' };\n }\n // If it starts with WITH, ensure it ends with a SELECT\n if (upperSQL.startsWith('WITH') && !upperSQL.includes('SELECT')) {\n return { valid: false, error: 'CTE queries must include a final SELECT statement' };\n }\n // Check for dangerous keywords\n const dangerousKeywords = [\n 'INSERT',\n 'UPDATE',\n 'DELETE',\n 'DROP',\n 'ALTER',\n 'TRUNCATE',\n 'CREATE',\n 'GRANT',\n 'REVOKE',\n 'EXEC',\n 'EXECUTE',\n 'INTO', // SELECT INTO\n ];\n for (const keyword of dangerousKeywords) {\n // Check for keyword as a whole word (not part of column name)\n const regex = new RegExp(`\\\\b${keyword}\\\\b`, 'i');\n if (regex.test(sql)) {\n return { valid: false, error: `Query contains forbidden keyword: ${keyword}` };\n }\n }\n // Check for multiple statements\n if (sql.includes(';')) {\n const statements = sql.split(';').filter(s => s.trim().length > 0);\n if (statements.length > 1) {\n return { valid: false, error: 'Multiple statements are not allowed' };\n }\n }\n return { valid: true };\n}\n/**\n * Build a summary message after query results are returned\n */\nexport function buildResultsSummary(rowCount, truncated, maxRows) {\n if (rowCount === 0) {\n return 'The query returned no results. You may want to adjust your filters or try a different approach.';\n }\n if (truncated) {\n return `Retrieved ${rowCount} rows (limited to ${maxRows}). There may be more data matching your query. Consider adding filters to narrow down the results.`;\n }\n return `Retrieved ${rowCount} row${rowCount === 1 ? '' : 's'}.`;\n}\n/**\n * Strip SQL code blocks from message content for display\n * The SQL is stored in metadata and shown via a button instead\n */\nexport function stripSQLFromContent(content) {\n // Remove SQL code blocks and any surrounding whitespace\n return content\n .replace(/```sql\\s*[\\s\\S]*?```\\s*/gi, '')\n .trim();\n}\n//# sourceMappingURL=prompts.js.map","/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `tp-ai-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId() {\n return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n/**\n * Create a new empty conversation\n */\nexport function createConversation(sessionId) {\n const now = Date.now();\n return {\n id: sessionId || generateSessionId(),\n messages: [],\n dataSourceId: undefined,\n createdAt: now,\n updatedAt: now,\n };\n}\n/**\n * Create a user message\n */\nexport function createUserMessage(content) {\n return {\n id: generateMessageId(),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n}\n/**\n * Create an assistant message\n */\nexport function createAssistantMessage(content, metadata) {\n return {\n id: generateMessageId(),\n role: 'assistant',\n content,\n timestamp: Date.now(),\n metadata,\n };\n}\n/**\n * Create a system message\n */\nexport function createSystemMessage(content) {\n return {\n id: generateMessageId(),\n role: 'system',\n content,\n timestamp: Date.now(),\n };\n}\n/**\n * Add a message to a conversation (immutably)\n */\nexport function addMessageToConversation(conversation, message) {\n return {\n ...conversation,\n messages: [...conversation.messages, message],\n updatedAt: Date.now(),\n };\n}\n/**\n * Update the data source for a conversation\n */\nexport function setConversationDataSource(conversation, dataSourceId) {\n return {\n ...conversation,\n dataSourceId,\n updatedAt: Date.now(),\n };\n}\n/**\n * Serialize a conversation to JSON string for storage\n */\nexport function serializeConversation(conversation) {\n return JSON.stringify(conversation);\n}\n/**\n * Deserialize a conversation from JSON string\n */\nexport function deserializeConversation(json) {\n try {\n const parsed = JSON.parse(json);\n // Basic validation\n if (typeof parsed !== 'object'\n || !parsed.id\n || !Array.isArray(parsed.messages)) {\n return null;\n }\n return parsed;\n }\n catch {\n return null;\n }\n}\n/**\n * Get the messages formatted for the AI API\n * Excludes system messages and metadata\n */\nexport function getMessagesForAPI(conversation) {\n return conversation.messages\n .filter(m => m.role !== 'system')\n .map(m => ({\n role: m.role,\n content: m.content,\n }));\n}\n/**\n * Trim conversation to last N messages to manage context window\n */\nexport function trimConversation(conversation, maxMessages) {\n if (conversation.messages.length <= maxMessages) {\n return conversation;\n }\n return {\n ...conversation,\n messages: conversation.messages.slice(-maxMessages),\n updatedAt: Date.now(),\n };\n}\n/**\n * Get conversation statistics\n */\nexport function getConversationStats(conversation) {\n const messages = conversation.messages;\n const queriesExecuted = messages.filter(m => m.metadata?.query).length;\n const failedQueries = messages.filter(m => m.metadata?.error).length;\n return {\n messageCount: messages.length,\n userMessageCount: messages.filter(m => m.role === 'user').length,\n assistantMessageCount: messages.filter(m => m.role === 'assistant').length,\n queriesExecuted,\n successfulQueries: queriesExecuted - failedQueries,\n failedQueries,\n };\n}\n//# sourceMappingURL=session.js.map","/**\n * Chart type definitions with metadata\n */\nexport const CHART_TYPES = [\n {\n type: 'bar',\n label: 'Bar Chart',\n icon: 'bar',\n description: 'Compare values across categories',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a category to X-axis and a number to Y-axis',\n bestFor: ['Comparing categories', 'Ranking', 'Part-to-whole'],\n },\n {\n type: 'stackedBar',\n label: 'Stacked Bar',\n icon: 'stackedBar',\n description: 'Compare composition across categories',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a category to X-axis, a number to Y-axis, and a grouping field to Series',\n bestFor: ['Part-to-whole comparison', 'Composition over categories', 'Cumulative totals'],\n },\n {\n type: 'line',\n label: 'Line Chart',\n icon: 'line',\n description: 'Show trends over time or sequence',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Best with time/date on X-axis and numbers on Y-axis',\n bestFor: ['Trends over time', 'Continuous data', 'Multiple series'],\n },\n {\n type: 'area',\n label: 'Area Chart',\n icon: 'area',\n description: 'Show magnitude and trends',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Like line charts but emphasizes volume. Great for stacked comparisons.',\n bestFor: ['Cumulative totals', 'Part-to-whole over time', 'Volume trends'],\n },\n {\n type: 'pie',\n label: 'Pie Chart',\n icon: 'pie',\n description: 'Show proportions of a whole',\n requiredFields: ['dimension', 'measure'],\n optionalFields: [],\n guidance: 'Drag a category and a number. Best with 2-6 categories.',\n bestFor: ['Part-to-whole', 'Proportions', 'Simple distributions'],\n },\n {\n type: 'donut',\n label: 'Donut Chart',\n icon: 'donut',\n description: 'Proportions with center space for metrics',\n requiredFields: ['dimension', 'measure'],\n optionalFields: [],\n guidance: 'Like pie but allows showing a total in the center',\n bestFor: ['Part-to-whole', 'Showing total', 'Dashboard KPIs'],\n },\n {\n type: 'scatter',\n label: 'Scatter Plot',\n icon: 'scatter',\n description: 'Show relationships between two variables',\n requiredFields: ['measure', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a number to X-axis and another number to Y-axis',\n bestFor: ['Correlation', 'Outlier detection', 'Distribution'],\n },\n {\n type: 'bubble',\n label: 'Bubble Chart',\n icon: 'bubble',\n description: 'Three-dimensional comparison',\n requiredFields: ['measure', 'measure'],\n optionalFields: ['measure', 'dimension'],\n guidance: 'Like scatter, plus drag a third number to Size for bubble size',\n bestFor: ['Multi-variable comparison', 'Weighted relationships'],\n },\n {\n type: 'heatmap',\n label: 'Heatmap',\n icon: 'heatmap',\n description: 'Visualize density or intensity',\n requiredFields: ['dimension', 'dimension', 'measure'],\n optionalFields: [],\n guidance: 'Drag two categories (X and Y) and a number to Color',\n bestFor: ['Patterns', 'Density', 'Cross-tabulation'],\n },\n {\n type: 'radar',\n label: 'Radar Chart',\n icon: 'radar',\n description: 'Compare multiple variables',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Best for comparing items across multiple metrics',\n bestFor: ['Multi-metric comparison', 'Performance profiles', 'Balanced scorecards'],\n },\n];\n/**\n * Aggregation options for measures\n */\nexport const CHART_AGGREGATIONS = [\n { value: 'sum', label: 'Sum', symbol: 'SUM' },\n { value: 'count', label: 'Count', symbol: 'COUNT' },\n { value: 'avg', label: 'Average', symbol: 'AVG' },\n { value: 'min', label: 'Minimum', symbol: 'MIN' },\n { value: 'max', label: 'Maximum', symbol: 'MAX' },\n { value: 'countDistinct', label: 'Count Distinct', symbol: 'DISTINCT' },\n];\n/**\n * Default color palette for charts (works in light and dark mode)\n */\nexport const CHART_COLORS = [\n '#6366f1', // indigo\n '#22c55e', // green\n '#f59e0b', // amber\n '#ef4444', // red\n '#8b5cf6', // violet\n '#06b6d4', // cyan\n '#ec4899', // pink\n '#14b8a6', // teal\n '#f97316', // orange\n '#3b82f6', // blue\n];\n/**\n * Detect the role of a field based on its data\n */\nexport function detectFieldRole(data, field) {\n if (data.length === 0)\n return 'dimension';\n const sample = data.slice(0, 100);\n const values = sample.map(row => row[field]).filter(v => v !== null && v !== undefined);\n if (values.length === 0)\n return 'dimension';\n // Check if numeric\n let numericCount = 0;\n let dateCount = 0;\n for (const val of values) {\n if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '' && typeof val !== 'boolean')) {\n numericCount++;\n }\n if (val instanceof Date || (typeof val === 'string' && !Number.isNaN(Date.parse(val)) && val.includes('-'))) {\n dateCount++;\n }\n }\n const threshold = values.length * 0.8;\n // Temporal detection (date fields)\n if (dateCount >= threshold) {\n return 'temporal';\n }\n // Measure detection (numeric with low cardinality ratio)\n if (numericCount >= threshold) {\n const uniqueCount = new Set(values.map(String)).size;\n // If high cardinality relative to count, it's a measure\n // If low cardinality (like \"1, 2, 3\" categories), treat as dimension\n if (uniqueCount > Math.min(values.length * 0.3, 20)) {\n return 'measure';\n }\n }\n return 'dimension';\n}\n/**\n * Analyze all fields in a dataset for chart building\n */\nexport function analyzeFieldsForChart(data) {\n if (data.length === 0)\n return [];\n const fields = Object.keys(data[0]);\n const result = [];\n for (const field of fields) {\n const values = data.map(row => row[field]).filter(v => v !== null && v !== undefined);\n const role = detectFieldRole(data, field);\n const uniqueSet = new Set(values.map(String));\n let dataType = 'string';\n let min;\n let max;\n if (role === 'measure') {\n dataType = 'number';\n const nums = values.map(v => Number(v)).filter(n => !Number.isNaN(n));\n if (nums.length > 0) {\n min = Math.min(...nums);\n max = Math.max(...nums);\n }\n }\n else if (role === 'temporal') {\n dataType = 'date';\n }\n else {\n // Check for boolean\n const boolCount = values.filter(v => typeof v === 'boolean' || v === 'true' || v === 'false').length;\n if (boolCount >= values.length * 0.8) {\n dataType = 'boolean';\n }\n }\n result.push({\n field,\n label: formatFieldLabel(field),\n role,\n dataType,\n uniqueCount: uniqueSet.size,\n sampleValues: Array.from(uniqueSet).slice(0, 5),\n min,\n max,\n });\n }\n return result;\n}\n/**\n * Format field name as label\n */\nexport function formatFieldLabel(field) {\n return field\n .replace(/([A-Z])/g, ' $1')\n .replace(/[_-]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .split(' ')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n}\n/**\n * Get chart type info by type\n */\nexport function getChartTypeInfo(type) {\n return CHART_TYPES.find(ct => ct.type === type);\n}\n/**\n * Check if a chart configuration is valid/complete\n */\nexport function isChartConfigValid(config) {\n const typeInfo = getChartTypeInfo(config.type);\n if (!typeInfo)\n return false;\n // Check required fields based on chart type\n switch (config.type) {\n case 'bar':\n case 'stackedBar':\n case 'line':\n case 'area':\n case 'pie':\n case 'donut':\n case 'radar':\n return !!config.xAxis && !!config.yAxis;\n case 'scatter':\n // Scatter needs two numeric fields (X and Y)\n return !!config.xAxis && !!config.yAxis;\n case 'bubble':\n // Bubble needs two numeric fields (X and Y), size is optional\n return !!config.xAxis && !!config.yAxis;\n case 'heatmap':\n // Heatmap needs two categories (X and Y) plus a measure for color intensity\n return !!config.xAxis && !!config.yAxis && !!config.colorField;\n default:\n return false;\n }\n}\n/**\n * Get guidance message for current chart state\n */\nexport function getChartGuidance(config) {\n const typeInfo = getChartTypeInfo(config.type);\n if (!typeInfo)\n return 'Select a chart type to begin';\n if (!config.xAxis && !config.yAxis) {\n return typeInfo.guidance;\n }\n switch (config.type) {\n case 'bar':\n case 'line':\n case 'area':\n if (!config.xAxis)\n return 'Drag a category field to the X-axis';\n if (!config.yAxis)\n return 'Drag a number field to the Y-axis';\n if (!config.seriesField)\n return 'Optionally add a field to Color for grouped series';\n return 'Chart is ready! Adjust options as needed.';\n case 'stackedBar':\n if (!config.xAxis)\n return 'Drag a category field to the X-axis';\n if (!config.yAxis)\n return 'Drag a number field to the Y-axis';\n if (!config.seriesField)\n return 'Add a field to Series to define stacked segments';\n return 'Chart is ready! Each series is stacked within the bar.';\n case 'pie':\n case 'donut':\n if (!config.xAxis)\n return 'Drag a category field (slices)';\n if (!config.yAxis)\n return 'Drag a number field (values)';\n return 'Chart is ready!';\n case 'radar':\n if (!config.xAxis)\n return 'Drag a category field for axes';\n if (!config.yAxis)\n return 'Drag a number field for values';\n return 'Chart is ready!';\n case 'scatter':\n if (!config.xAxis)\n return 'Drag a number field to X-axis';\n if (!config.yAxis)\n return 'Drag a number field to Y-axis';\n if (!config.seriesField)\n return 'Optionally add a category to color points by group';\n return 'Tip: Filter data first for clearer visualizations';\n case 'bubble':\n if (!config.xAxis)\n return 'Drag a number field to X-axis';\n if (!config.yAxis)\n return 'Drag a number field to Y-axis';\n if (!config.sizeField)\n return 'Drag a number field to Size for bubble size';\n return 'Tip: Filter to fewer records for readable bubbles';\n case 'heatmap':\n if (!config.xAxis)\n return 'Drag a category field to X-axis';\n if (!config.yAxis)\n return 'Drag a category field to Y-axis';\n if (!config.colorField)\n return 'Drag a number field to Value for color intensity';\n return 'Chart is ready!';\n default:\n return typeInfo.guidance;\n }\n}\n/**\n * Apply aggregation to values\n */\nexport function aggregateValues(values, aggregation) {\n if (values.length === 0)\n return 0;\n switch (aggregation) {\n case 'sum':\n return values.reduce((a, b) => a + b, 0);\n case 'count':\n return values.length;\n case 'avg':\n return values.reduce((a, b) => a + b, 0) / values.length;\n case 'min':\n return Math.min(...values);\n case 'max':\n return Math.max(...values);\n case 'countDistinct':\n return new Set(values).size;\n default:\n return values.reduce((a, b) => a + b, 0);\n }\n}\n/**\n * Process raw data into chart-ready format\n */\nexport function processChartData(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { categories: [], series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const yAggregation = config.yAxis.aggregation || 'sum';\n const seriesField = config.seriesField?.field;\n // Group data by x-axis values\n const grouped = new Map();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = Number(row[yField]);\n const seriesValue = seriesField ? String(row[seriesField] ?? '(blank)') : '_default';\n if (Number.isNaN(yValue))\n continue;\n if (!grouped.has(xValue)) {\n grouped.set(xValue, new Map());\n }\n const xGroup = grouped.get(xValue);\n if (!xGroup.has(seriesValue)) {\n xGroup.set(seriesValue, []);\n }\n xGroup.get(seriesValue).push(yValue);\n }\n // Get sorted categories\n const categories = Array.from(grouped.keys()).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Get all series names\n const seriesNames = new Set();\n for (const xGroup of grouped.values()) {\n for (const seriesName of xGroup.keys()) {\n seriesNames.add(seriesName);\n }\n }\n // Build series data\n const series = [];\n for (const seriesName of seriesNames) {\n const seriesData = [];\n for (const category of categories) {\n const xGroup = grouped.get(category);\n const values = xGroup?.get(seriesName) || [];\n seriesData.push(aggregateValues(values, yAggregation));\n }\n series.push({\n name: seriesName === '_default'\n ? formatFieldLabel(yField)\n : seriesName,\n data: seriesData,\n });\n }\n return { categories, series };\n}\n/**\n * Process data for pie/donut charts\n */\nexport function processChartDataForPie(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { categories: [], series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const yAggregation = config.yAxis.aggregation || 'sum';\n // Group by category\n const grouped = new Map();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = Number(row[yField]);\n if (Number.isNaN(yValue))\n continue;\n if (!grouped.has(xValue)) {\n grouped.set(xValue, []);\n }\n grouped.get(xValue).push(yValue);\n }\n // Sort by aggregated value descending\n const entries = Array.from(grouped.entries())\n .map(([category, values]) => ({\n category,\n value: aggregateValues(values, yAggregation),\n }))\n .sort((a, b) => b.value - a.value);\n return {\n categories: entries.map(e => e.category),\n series: [{\n name: formatFieldLabel(yField),\n data: entries.map(e => e.value),\n }],\n };\n}\n/**\n * Process data for scatter/bubble charts\n * Returns grouped series when seriesField is provided for color-coding\n */\nexport function processChartDataForScatter(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const sizeField = config.sizeField?.field;\n const seriesField = config.seriesField?.field;\n // Group by series field if provided\n const grouped = new Map();\n for (const row of data) {\n const x = Number(row[xField]);\n const y = Number(row[yField]);\n if (Number.isNaN(x) || Number.isNaN(y))\n continue;\n const point = { x, y };\n if (sizeField) {\n const z = Number(row[sizeField]);\n if (!Number.isNaN(z)) {\n point.z = z;\n }\n }\n // Group by series field or use default\n const seriesName = seriesField\n ? String(row[seriesField] ?? '(blank)')\n : '_default';\n if (!grouped.has(seriesName)) {\n grouped.set(seriesName, []);\n }\n grouped.get(seriesName).push(point);\n }\n // Convert to series array\n const series = Array.from(grouped.entries()).map(([name, points]) => ({\n name: name === '_default' ? (config.yAxis?.label || 'Data') : name,\n data: points,\n }));\n return { series };\n}\n/**\n * Process data for heatmap charts\n * ApexCharts heatmaps need: series[] where each series is a Y category\n * containing data[] of {x: X category, y: value}\n */\nexport function processChartDataForHeatmap(data, config) {\n if (!config.xAxis || !config.yAxis || !config.colorField || data.length === 0) {\n return { series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const colorField = config.colorField.field;\n const colorAggregation = config.colorField.aggregation || 'sum';\n // Group data by Y category, then by X category\n // Structure: Map<yValue, Map<xValue, number[]>>\n const grouped = new Map();\n const allXCategories = new Set();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = String(row[yField] ?? '(blank)');\n const colorValue = Number(row[colorField]);\n if (Number.isNaN(colorValue))\n continue;\n allXCategories.add(xValue);\n if (!grouped.has(yValue)) {\n grouped.set(yValue, new Map());\n }\n const yGroup = grouped.get(yValue);\n if (!yGroup.has(xValue)) {\n yGroup.set(xValue, []);\n }\n yGroup.get(xValue).push(colorValue);\n }\n // Sort X categories\n const sortedXCategories = Array.from(allXCategories).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Sort Y categories (series names)\n const sortedYCategories = Array.from(grouped.keys()).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Build series - each Y category becomes a series\n const series = sortedYCategories.map((yCategory) => {\n const yGroup = grouped.get(yCategory);\n const seriesData = sortedXCategories.map((xCategory) => {\n const values = yGroup.get(xCategory) || [];\n const aggregatedValue = values.length > 0 ? aggregateValues(values, colorAggregation) : 0;\n return { x: xCategory, y: aggregatedValue };\n });\n return {\n name: yCategory,\n data: seriesData,\n };\n });\n return { series };\n}\n/**\n * Create a default chart config\n */\nexport function createDefaultChartConfig() {\n return {\n type: 'bar',\n options: {\n showDataLabels: false,\n showLegend: true,\n legendPosition: 'top',\n animated: true,\n colors: CHART_COLORS,\n showGrid: true,\n enableZoom: false,\n stacked: false,\n },\n };\n}\n/**\n * Storage key for chart config\n */\nexport function generateChartStorageKey(prefix = 'tinypivot') {\n return `${prefix}_chart_config`;\n}\n/**\n * Save chart config to localStorage\n */\nexport function saveChartConfig(config, key) {\n try {\n localStorage.setItem(key || generateChartStorageKey(), JSON.stringify(config));\n }\n catch {\n // localStorage might be unavailable\n }\n}\n/**\n * Load chart config from localStorage\n */\nexport function loadChartConfig(key) {\n try {\n const stored = localStorage.getItem(key || generateChartStorageKey());\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // localStorage might be unavailable or invalid JSON\n }\n return null;\n}\n//# sourceMappingURL=index.js.map","/**\n * Escape CSV value\n */\nfunction escapeCSV(value, delimiter = ',') {\n if (value === null || value === undefined)\n return '';\n const str = String(value);\n if (str.includes(delimiter) || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n/**\n * CSV Export functionality\n */\nexport function exportToCSV(data, columns, options = {}) {\n const { filename = 'export.csv', includeHeaders = true, delimiter = ',' } = options;\n const rows = [];\n if (includeHeaders) {\n rows.push(columns.map(col => escapeCSV(col, delimiter)).join(delimiter));\n }\n for (const row of data) {\n const values = columns.map(col => escapeCSV(row[col], delimiter));\n rows.push(values.join(delimiter));\n }\n const csvContent = rows.join('\\n');\n downloadFile(csvContent, filename, 'text/csv;charset=utf-8;');\n}\n/**\n * Export pivot table to CSV\n */\nexport function exportPivotToCSV(pivotData, rowFields, _columnFields, valueFields, options = {}) {\n const { filename = 'pivot-export.csv', delimiter = ',' } = options;\n const rows = [];\n const { headers, rowHeaders, data, rowTotals, columnTotals, grandTotal, showRowTotals, showColumnTotals } = pivotData;\n // Calculate number of row header columns\n const rowHeaderColCount = rowFields.length || 1;\n // Build column headers\n if (headers.length > 0) {\n // Multi-level column headers\n for (let level = 0; level < headers.length; level++) {\n const headerRow = [];\n // Empty cells for row field columns\n for (let i = 0; i < rowHeaderColCount; i++) {\n headerRow.push(level === headers.length - 1 ? escapeCSV(rowFields[i] || '', delimiter) : '');\n }\n // Column header values\n for (const val of headers[level]) {\n headerRow.push(escapeCSV(val, delimiter));\n }\n // Row totals header\n if (showRowTotals && rowTotals && rowTotals.length > 0) {\n if (level === headers.length - 1) {\n for (const vf of valueFields) {\n headerRow.push(escapeCSV(`Total (${vf.aggregation})`, delimiter));\n }\n }\n else {\n for (let i = 0; i < valueFields.length; i++) {\n headerRow.push('');\n }\n }\n }\n rows.push(headerRow.join(delimiter));\n }\n }\n else {\n // Simple header with value fields only\n const headerRow = [];\n for (let i = 0; i < rowHeaderColCount; i++) {\n headerRow.push(escapeCSV(rowFields[i] || '', delimiter));\n }\n for (const vf of valueFields) {\n headerRow.push(escapeCSV(`${vf.field} (${vf.aggregation})`, delimiter));\n }\n if (showRowTotals && rowTotals && rowTotals.length > 0) {\n headerRow.push(escapeCSV('Total', delimiter));\n }\n rows.push(headerRow.join(delimiter));\n }\n // Build data rows\n for (let rowIdx = 0; rowIdx < rowHeaders.length; rowIdx++) {\n const csvRow = [];\n // Row headers\n const rowHeader = rowHeaders[rowIdx] || [];\n for (let i = 0; i < rowHeaderColCount; i++) {\n csvRow.push(escapeCSV(rowHeader[i] || '', delimiter));\n }\n // Data cells\n const rowData = data[rowIdx] || [];\n for (const cell of rowData) {\n csvRow.push(escapeCSV(cell?.formattedValue || '', delimiter));\n }\n // Row total\n if (showRowTotals && rowTotals && rowTotals[rowIdx]) {\n csvRow.push(escapeCSV(rowTotals[rowIdx].formattedValue || '', delimiter));\n }\n rows.push(csvRow.join(delimiter));\n }\n // Column totals row\n if (showColumnTotals && columnTotals && columnTotals.length > 0) {\n const totalsRow = [];\n // Label for totals row\n totalsRow.push(escapeCSV('Total', delimiter));\n for (let i = 1; i < rowHeaderColCount; i++) {\n totalsRow.push('');\n }\n // Column total values\n for (const cell of columnTotals) {\n totalsRow.push(escapeCSV(cell?.formattedValue || '', delimiter));\n }\n // Grand total\n if (showRowTotals && grandTotal) {\n totalsRow.push(escapeCSV(grandTotal.formattedValue || '', delimiter));\n }\n rows.push(totalsRow.join(delimiter));\n }\n const csvContent = rows.join('\\n');\n downloadFile(csvContent, filename, 'text/csv;charset=utf-8;');\n}\n/**\n * Download file helper\n */\nfunction downloadFile(content, filename, mimeType) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n/**\n * Copy text to clipboard\n */\nexport function copyToClipboard(text, onSuccess, onError) {\n navigator.clipboard.writeText(text).then(onSuccess).catch(onError);\n}\n/**\n * Format selected cells for clipboard (tab-separated)\n */\nexport function formatSelectionForClipboard(rows, columns, selectionBounds) {\n const { minRow, maxRow, minCol, maxCol } = selectionBounds;\n const lines = [];\n for (let r = minRow; r <= maxRow; r++) {\n const row = rows[r];\n if (!row)\n continue;\n const values = [];\n for (let c = minCol; c <= maxCol; c++) {\n const colId = columns[c];\n if (!colId)\n continue;\n const value = row[colId];\n values.push(value === null || value === undefined ? '' : String(value));\n }\n lines.push(values.join('\\t'));\n }\n return lines.join('\\n');\n}\n//# sourceMappingURL=index.js.map","const FREE_LICENSE = {\n type: 'free',\n isValid: true,\n features: {\n pivot: true, // Free tier includes pivot with sum aggregation\n advancedAggregations: false, // Pro: all aggregations beyond sum\n percentageMode: false,\n sessionPersistence: false,\n noWatermark: false,\n charts: false, // Chart builder is Pro only\n aiAnalyst: false, // AI Data Analyst is Pro only\n },\n};\nconst INVALID_LICENSE = {\n type: 'free',\n isValid: false,\n features: {\n pivot: true, // Free tier includes pivot with sum aggregation\n advancedAggregations: false,\n percentageMode: false,\n sessionPersistence: false,\n noWatermark: false,\n charts: false,\n aiAnalyst: false,\n },\n};\nconst DEMO_LICENSE = {\n type: 'free',\n isValid: true,\n features: {\n pivot: true,\n advancedAggregations: true,\n percentageMode: true,\n sessionPersistence: true,\n noWatermark: false, // Still show watermark in demo\n charts: true, // Demo can use charts\n aiAnalyst: true, // Demo can use AI Analyst\n },\n};\n// Public key for license verification (ECDSA P-256)\n// This is safe to embed - it can only VERIFY signatures, not create them\nconst PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE436rfGofder4lfo4UHsRF2M88Gs0\nzLsikg2H9GMkL8hLGuOtnGMpVfLRlc7cD8FdkPBBRgiQ8UFnG8hm+nMIug==\n-----END PUBLIC KEY-----`;\n/**\n * Convert base64 (or URL-safe base64) to Uint8Array\n */\nfunction base64ToUint8Array(base64) {\n // Convert URL-safe base64 to standard base64\n let standardBase64 = base64.replace(/-/g, '+').replace(/_/g, '/');\n // Add padding if needed\n while (standardBase64.length % 4) {\n standardBase64 += '=';\n }\n const binaryString = atob(standardBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n/**\n * Convert DER-encoded ECDSA signature to raw format (r || s)\n * Web Crypto API expects raw format, but Node.js produces DER format\n */\nfunction derToRaw(der) {\n // DER format: 0x30 [length] 0x02 [r-length] [r] 0x02 [s-length] [s]\n if (der[0] !== 0x30) {\n throw new Error('Invalid DER signature');\n }\n let offset = 2; // Skip 0x30 and length byte\n // Read r\n if (der[offset] !== 0x02)\n throw new Error('Invalid DER signature');\n offset++;\n const rLen = der[offset];\n offset++;\n let r = der.slice(offset, offset + rLen);\n offset += rLen;\n // Read s\n if (der[offset] !== 0x02)\n throw new Error('Invalid DER signature');\n offset++;\n const sLen = der[offset];\n offset++;\n let s = der.slice(offset, offset + sLen);\n // For P-256, r and s should each be 32 bytes\n // Remove leading zero padding if present (used for positive sign in DER)\n if (r.length === 33 && r[0] === 0)\n r = r.slice(1);\n if (s.length === 33 && s[0] === 0)\n s = s.slice(1);\n // Pad to 32 bytes if shorter\n const padR = new Uint8Array(32);\n const padS = new Uint8Array(32);\n padR.set(r, 32 - r.length);\n padS.set(s, 32 - s.length);\n // Concatenate r || s\n const raw = new Uint8Array(64);\n raw.set(padR, 0);\n raw.set(padS, 32);\n return raw;\n}\n/**\n * ECDSA P-256 verification via @noble/curves (pure JS fallback)\n * Used when SubtleCrypto is unavailable (e.g. browser on plain HTTP)\n */\nasync function verifySignatureNoble(rawSig, msgBytes, spkiBytes) {\n const { p256 } = await import('@noble/curves/p256');\n // SPKI for P-256 has a fixed 26-byte header; raw key starts at offset 26\n const rawPublicKey = spkiBytes.slice(26);\n // prehash: true makes noble SHA-256 hash the message before verifying,\n // matching Web Crypto's { name: 'ECDSA', hash: 'SHA-256' } behavior\n return p256.verify(rawSig, msgBytes, rawPublicKey, { prehash: true });\n}\n/**\n * SHA-256 hashing via @noble/hashes (pure JS fallback)\n * Used when SubtleCrypto is unavailable (e.g. browser on plain HTTP)\n */\nasync function hashSecretNoble(secret) {\n const { sha256 } = await import('@noble/hashes/sha256');\n const data = new TextEncoder().encode(secret);\n const hash = sha256(data);\n return Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();\n}\n/**\n * Cached SubtleCrypto instance (undefined = not yet checked)\n */\nlet subtleCryptoCache;\n/**\n * Get a SubtleCrypto instance, falling back to Node.js webcrypto for SSR\n */\nasync function getSubtleCrypto() {\n if (subtleCryptoCache !== undefined)\n return subtleCryptoCache;\n if (globalThis.crypto?.subtle) {\n subtleCryptoCache = globalThis.crypto.subtle;\n return subtleCryptoCache;\n }\n try {\n // Node.js / SSR fallback\n const nodeCrypto = await import('node:crypto');\n const subtle = nodeCrypto.webcrypto?.subtle;\n if (subtle) {\n subtleCryptoCache = subtle;\n return subtleCryptoCache;\n }\n }\n catch { }\n subtleCryptoCache = null;\n return null;\n}\n/**\n * @internal\n */\nexport function _resetCryptoState(forcedValue) {\n // undefined = re-detect on next call, null = force \"no crypto available\"\n subtleCryptoCache = forcedValue;\n insecureContextWarned = false;\n}\nlet insecureContextWarned = false;\n/**\n * Log a one-time info message when crypto.subtle is unavailable (plain HTTP)\n * Not a blocker since @noble/curves provides a pure JS fallback.\n */\nfunction warnInsecureContext() {\n if (insecureContextWarned)\n return;\n insecureContextWarned = true;\n console.info('[TinyPivot] crypto.subtle is not available — using pure JS crypto fallback.\\n'\n + 'This typically happens when serving over plain HTTP. For best performance, consider:\\n'\n + ' 1. Serve your app over HTTPS (recommended for production)\\n'\n + ' 2. Access via localhost (e.g. http://localhost:3000)\\n'\n + ' 3. Use a self-signed certificate for internal IPs');\n}\n/**\n * Import the public key for verification\n */\nasync function importPublicKey() {\n try {\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n return null;\n }\n // Convert PEM to binary\n const pemContents = PUBLIC_KEY_PEM\n .replace('-----BEGIN PUBLIC KEY-----', '')\n .replace('-----END PUBLIC KEY-----', '')\n .replace(/\\s/g, '');\n const binaryKey = base64ToUint8Array(pemContents);\n return await subtle.importKey('spki', new Uint8Array(binaryKey).buffer, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);\n }\n catch {\n return null;\n }\n}\n/**\n * Get SPKI bytes from the embedded PEM public key\n */\nfunction getSpkiBytes() {\n const pemContents = PUBLIC_KEY_PEM\n .replace('-----BEGIN PUBLIC KEY-----', '')\n .replace('-----END PUBLIC KEY-----', '')\n .replace(/\\s/g, '');\n return base64ToUint8Array(pemContents);\n}\n/**\n * ECDSA P-256 signature verification\n * Verifies that the license was signed with our private key\n * Falls back to @noble/curves when SubtleCrypto is unavailable\n */\nasync function verifySignature(typeCode, signature, expiry) {\n const payload = `TP-${typeCode}-${expiry}`;\n const encoder = new TextEncoder();\n const msgData = encoder.encode(payload);\n const derSig = base64ToUint8Array(signature);\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n // Fall back to @noble/curves pure JS implementation\n warnInsecureContext();\n try {\n const rawSig = derToRaw(derSig);\n const spkiBytes = getSpkiBytes();\n return await verifySignatureNoble(rawSig, msgData, spkiBytes);\n }\n catch {\n return false;\n }\n }\n try {\n const rawSig = derToRaw(derSig);\n const publicKey = await importPublicKey();\n if (!publicKey)\n return false;\n return await subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, publicKey, new Uint8Array(rawSig).buffer, msgData);\n }\n catch {\n return false;\n }\n}\n/**\n * Validate a license key and extract info\n *\n * Note: Licenses are PERPETUAL - the expiry date indicates update eligibility,\n * not when features stop working. All Pro features remain active forever.\n */\nexport async function validateLicenseKey(key) {\n // Free tier - no key needed\n if (!key || key === '') {\n return FREE_LICENSE;\n }\n // License key format: TP-{TYPE}-{SIGNATURE}-{EXPIRY}\n // Example: TP-PRO1-base64signature-20251231\n // Note: signature uses URL-safe base64 which can contain dashes\n // So we parse from known positions: prefix (TP), type (4 chars), expiry (8 chars at end)\n if (!key.startsWith('TP-')) {\n return INVALID_LICENSE;\n }\n // Extract expiry (last 8 characters after final dash)\n const lastDashIdx = key.lastIndexOf('-');\n if (lastDashIdx === -1 || key.length - lastDashIdx !== 9) {\n return INVALID_LICENSE;\n }\n const expiryStr = key.slice(lastDashIdx + 1);\n // Extract type code (between first and second dash)\n const withoutPrefix = key.slice(3); // Remove \"TP-\"\n const secondDashIdx = withoutPrefix.indexOf('-');\n if (secondDashIdx === -1) {\n return INVALID_LICENSE;\n }\n const typeCode = withoutPrefix.slice(0, secondDashIdx);\n // Extract signature (everything between type and expiry)\n const signature = withoutPrefix.slice(secondDashIdx + 1, withoutPrefix.lastIndexOf('-'));\n // Verify cryptographic signature\n const isValidSignature = await verifySignature(typeCode, signature, expiryStr);\n if (!isValidSignature) {\n return INVALID_LICENSE;\n }\n // Parse expiry date (for update eligibility tracking, NOT feature expiration)\n const year = Number.parseInt(expiryStr.slice(0, 4));\n const month = Number.parseInt(expiryStr.slice(4, 6)) - 1;\n const day = Number.parseInt(expiryStr.slice(6, 8));\n const expiresAt = new Date(year, month, day);\n // Determine license type\n let type = 'free';\n if (typeCode === 'PRO1')\n type = 'pro-single';\n else if (typeCode === 'PROU')\n type = 'pro-unlimited';\n else if (typeCode === 'PROT')\n type = 'pro-team';\n // PERPETUAL LICENSE: Features never expire, only update eligibility does\n // The expiresAt date is retained for informational purposes only\n return {\n type,\n isValid: true,\n expiresAt,\n features: {\n pivot: type !== 'free',\n advancedAggregations: type !== 'free',\n percentageMode: type !== 'free',\n sessionPersistence: type !== 'free',\n noWatermark: type !== 'free',\n charts: type !== 'free',\n aiAnalyst: type !== 'free',\n },\n };\n}\n/**\n * @deprecated No longer needed - license verification now uses asymmetric cryptography.\n * Kept for backwards compatibility but does nothing.\n */\nexport function configureLicenseSecret(_secret) {\n // No-op: Asymmetric verification doesn't need a shared secret\n console.warn('[TinyPivot] configureLicenseSecret() is deprecated and no longer needed.');\n}\n// Hardcoded SHA-256 hash of the demo secret\nconst DEMO_SECRET_HASH = 'A48AA0618518D3E62F31FCFCA2DD2B86E7FE0863E2F90756FB0A960AE7A51583';\n/**\n * Hash a string using SHA-256 (async for Web Crypto API)\n */\nasync function hashSecret(secret) {\n try {\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n // Fall back to @noble/hashes pure JS implementation\n warnInsecureContext();\n return await hashSecretNoble(secret);\n }\n const encoder = new TextEncoder();\n const data = encoder.encode(secret);\n const hashBuffer = await subtle.digest('SHA-256', data);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();\n }\n catch {\n return '';\n }\n}\n/**\n * Validate demo secret and return demo license info if valid\n * Returns null if secret is invalid\n */\nexport async function getDemoLicenseInfo(secret) {\n if (!secret) {\n return null;\n }\n const hash = await hashSecret(secret);\n if (hash !== DEMO_SECRET_HASH) {\n return null;\n }\n return DEMO_LICENSE;\n}\n/**\n * Get free license info\n */\nexport function getFreeLicenseInfo() {\n return FREE_LICENSE;\n}\n/**\n * Check if license allows pivot feature\n */\nexport function canUsePivot(info) {\n return info.features.pivot;\n}\n/**\n * Check if license allows chart builder feature\n */\nexport function canUseCharts(info) {\n return info.features.charts;\n}\n/**\n * Check if license allows AI Data Analyst feature\n */\nexport function canUseAIAnalyst(info) {\n return info.features.aiAnalyst;\n}\n/**\n * Check if license is pro (any tier)\n */\nexport function isPro(info) {\n return info.isValid && info.type !== 'free';\n}\n/**\n * Check if watermark should be shown\n */\nexport function shouldShowWatermark(info, isDemo) {\n return isDemo || !info.features.noWatermark;\n}\n/**\n * Log pro requirement warning\n */\nexport function logProRequired(feature) {\n console.warn(`[TinyPivot] \"${feature}\" requires a Pro license. `\n + `Visit https://tiny-pivot.com/#pricing to upgrade.`);\n}\n//# sourceMappingURL=index.js.map","/**\n * Detect column data type from values\n */\nexport function detectColumnType(values) {\n const nonNullValues = values.filter(v => v !== null && v !== undefined && v !== '');\n if (nonNullValues.length === 0)\n return 'string';\n const sample = nonNullValues.slice(0, 100);\n let numberCount = 0;\n let dateCount = 0;\n let booleanCount = 0;\n for (const val of sample) {\n if (typeof val === 'boolean') {\n booleanCount++;\n }\n else if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '')) {\n numberCount++;\n }\n else if (val instanceof Date || !Number.isNaN(Date.parse(String(val)))) {\n dateCount++;\n }\n }\n const threshold = sample.length * 0.8;\n if (booleanCount >= threshold)\n return 'boolean';\n if (numberCount >= threshold)\n return 'number';\n if (dateCount >= threshold)\n return 'date';\n return 'string';\n}\n/**\n * Detect field type from sample data (for pivot)\n */\nexport function detectFieldType(data, field) {\n const values = data.map(row => row[field]).filter(v => v !== null && v !== undefined && v !== '');\n const sample = values.slice(0, 100);\n let numberCount = 0;\n const uniqueSet = new Set();\n for (const val of sample) {\n uniqueSet.add(String(val));\n if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '')) {\n numberCount++;\n }\n }\n const isNumeric = numberCount >= sample.length * 0.8;\n return {\n field,\n type: isNumeric ? 'number' : 'string',\n uniqueCount: uniqueSet.size,\n isNumeric,\n };\n}\n/**\n * Get unique values for a column (for Excel-style filter dropdown)\n * For numeric columns, also computes min and max values\n */\nexport function getColumnUniqueValues(data, columnKey, maxValues = 500) {\n const values = [];\n let nullCount = 0;\n let numericMin;\n let numericMax;\n let dateMin;\n let dateMax;\n for (const row of data) {\n const value = row[columnKey];\n if (value === null || value === undefined || value === '') {\n nullCount++;\n }\n else {\n values.push(value);\n // Track numeric min/max\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (!Number.isNaN(num)) {\n if (numericMin === undefined || num < numericMin)\n numericMin = num;\n if (numericMax === undefined || num > numericMax)\n numericMax = num;\n }\n // Track date min/max\n if (value instanceof Date || (typeof value === 'string' && !Number.isNaN(Date.parse(String(value))))) {\n const dateObj = value instanceof Date ? value : new Date(String(value));\n if (!Number.isNaN(dateObj.getTime())) {\n const isoStr = dateObj.toISOString().split('T')[0];\n if (dateMin === undefined || isoStr < dateMin)\n dateMin = isoStr;\n if (dateMax === undefined || isoStr > dateMax)\n dateMax = isoStr;\n }\n }\n }\n }\n // Get unique values\n const uniqueSet = new Set();\n for (const val of values) {\n uniqueSet.add(String(val));\n if (uniqueSet.size >= maxValues)\n break;\n }\n const uniqueValues = Array.from(uniqueSet).sort((a, b) => {\n // Natural sort for numbers\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n const columnType = detectColumnType(values);\n return {\n uniqueValues,\n totalCount: data.length,\n nullCount,\n type: columnType,\n // Only include min/max for numeric columns\n ...(columnType === 'number' && numericMin !== undefined && numericMax !== undefined\n ? { numericMin, numericMax }\n : {}),\n ...(columnType === 'date' && dateMin !== undefined && dateMax !== undefined\n ? { dateMin, dateMax }\n : {}),\n };\n}\n/**\n * Format cell value for display\n */\nexport function formatCellValue(value, type, numberFormat = 'us', dateFormat = 'iso') {\n if (value === null || value === undefined)\n return '';\n if (value === '')\n return '';\n switch (type) {\n case 'number': {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (Number.isNaN(num))\n return String(value);\n return formatNumber(num, numberFormat);\n }\n case 'date':\n return formatDate(value, dateFormat);\n case 'boolean':\n return value ? 'Yes' : 'No';\n default:\n return String(value);\n }\n}\n/**\n * Format number for display with appropriate precision\n */\nexport function formatNumber(value, format = 'us', options) {\n if (value === null)\n return '-';\n const maxDigits = options?.maximumFractionDigits ?? (Math.abs(value) >= 1000 ? 2 : 4);\n switch (format) {\n case 'eu':\n return value.toLocaleString('de-DE', { maximumFractionDigits: maxDigits });\n case 'plain':\n return Number.isInteger(value) ? String(value) : value.toFixed(Math.min(maxDigits, 20));\n case 'us':\n default:\n return value.toLocaleString('en-US', { maximumFractionDigits: maxDigits });\n }\n}\n/**\n * Format date according to the specified format preset\n */\nexport function formatDate(value, format = 'iso') {\n const date = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(date.getTime()))\n return String(value);\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n switch (format) {\n case 'us':\n return `${month}/${day}/${year}`;\n case 'eu':\n return `${day}/${month}/${year}`;\n case 'iso':\n default:\n return `${year}-${month}-${day}`;\n }\n}\n/**\n * Parse a date string in the given format back to an ISO string (YYYY-MM-DD)\n * Returns null if parsing fails\n */\nexport function parseDateInput(input, format = 'iso') {\n const trimmed = input.trim();\n if (!trimmed)\n return null;\n let year, month, day;\n switch (format) {\n case 'us': {\n const parts = trimmed.split('/');\n if (parts.length !== 3)\n return null;\n month = Number.parseInt(parts[0], 10);\n day = Number.parseInt(parts[1], 10);\n year = Number.parseInt(parts[2], 10);\n break;\n }\n case 'eu': {\n const parts = trimmed.split('/');\n if (parts.length !== 3)\n return null;\n day = Number.parseInt(parts[0], 10);\n month = Number.parseInt(parts[1], 10);\n year = Number.parseInt(parts[2], 10);\n break;\n }\n case 'iso':\n default: {\n const parts = trimmed.split('-');\n if (parts.length !== 3)\n return null;\n year = Number.parseInt(parts[0], 10);\n month = Number.parseInt(parts[1], 10);\n day = Number.parseInt(parts[2], 10);\n break;\n }\n }\n if (Number.isNaN(year) || Number.isNaN(month) || Number.isNaN(day))\n return null;\n if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1)\n return null;\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day)\n return null;\n const m = String(month).padStart(2, '0');\n const d = String(day).padStart(2, '0');\n return `${year}-${m}-${d}`;\n}\n/**\n * Get the date format placeholder string\n */\nexport function getDatePlaceholder(format = 'iso') {\n switch (format) {\n case 'us': return 'MM/DD/YYYY';\n case 'eu': return 'DD/MM/YYYY';\n case 'iso':\n default: return 'YYYY-MM-DD';\n }\n}\n/**\n * Create a composite key from field values (for pivot grouping)\n */\nexport function makeKey(row, fields) {\n return fields.map(f => String(row[f] ?? '(blank)')).join('|||');\n}\n/**\n * Parse composite key back to values\n */\nexport function parseKey(key) {\n return key.split('|||');\n}\n/**\n * Natural sort comparator\n */\nexport function naturalSort(a, b) {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n}\n/**\n * Debounce function\n */\nexport function debounce(fn, delay) {\n let timeoutId = null;\n return (...args) => {\n if (timeoutId)\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n}\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value, min, max) {\n return Math.max(min, Math.min(max, value));\n}\n//# sourceMappingURL=index.js.map","import { detectFieldType, formatNumber, makeKey, parseKey } from '../utils';\n/**\n * Calculate median of an array\n */\nfunction calculateMedian(values) {\n const sorted = [...values].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 !== 0\n ? sorted[mid]\n : (sorted[mid - 1] + sorted[mid]) / 2;\n}\n/**\n * Calculate standard deviation of an array\n */\nfunction calculateStdDev(values) {\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const squaredDiffs = values.map(v => (v - mean) ** 2);\n const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;\n return Math.sqrt(avgSquaredDiff);\n}\n/**\n * Aggregate values based on function type\n * @param values - Array of values to aggregate\n * @param fn - Aggregation function to apply\n * @param grandTotal - Optional grand total for percentOfTotal calculation\n * @param customFn - Optional custom aggregation function\n * @param allFieldValues - Optional all field values for cross-field custom calculations\n */\nexport function aggregate(values, fn, grandTotal, customFn, allFieldValues) {\n if (values.length === 0 && fn !== 'custom')\n return null;\n switch (fn) {\n case 'sum':\n return values.reduce((a, b) => a + b, 0);\n case 'count':\n return values.length;\n case 'avg':\n return values.reduce((a, b) => a + b, 0) / values.length;\n case 'min':\n return Math.min(...values);\n case 'max':\n return Math.max(...values);\n case 'countDistinct':\n return new Set(values).size;\n case 'median':\n return calculateMedian(values);\n case 'stdDev':\n return calculateStdDev(values);\n case 'percentOfTotal': {\n const sum = values.reduce((a, b) => a + b, 0);\n if (grandTotal === undefined || grandTotal === 0)\n return null;\n return (sum / grandTotal) * 100;\n }\n case 'custom':\n if (customFn) {\n try {\n return customFn(values, allFieldValues);\n }\n catch {\n return null;\n }\n }\n return null;\n default:\n return values.reduce((a, b) => a + b, 0);\n }\n}\n/**\n * Format aggregated value for display\n */\nexport function formatAggregatedValue(value, fn, numberFormat = 'us') {\n if (value === null)\n return '-';\n if (fn === 'count' || fn === 'countDistinct') {\n return formatNumber(Math.round(value), numberFormat, { maximumFractionDigits: 0 });\n }\n if (fn === 'percentOfTotal') {\n return `${value.toFixed(1)}%`;\n }\n return formatNumber(value, numberFormat);\n}\n/**\n * Get aggregation function display label\n */\nexport function getAggregationLabel(fn, customLabel) {\n if (fn === 'custom' && customLabel)\n return customLabel;\n const labels = {\n sum: 'Sum',\n count: 'Count',\n avg: 'Average',\n min: 'Min',\n max: 'Max',\n countDistinct: 'Count Distinct',\n median: 'Median',\n stdDev: 'Std Dev',\n percentOfTotal: '% of Total',\n custom: 'Custom',\n };\n return labels[fn];\n}\n/**\n * Get aggregation function symbol\n */\nexport function getAggregationSymbol(fn, customSymbol) {\n if (fn === 'custom' && customSymbol)\n return customSymbol;\n const symbols = {\n sum: 'Σ',\n count: '#',\n avg: 'x̄',\n min: '↓',\n max: '↑',\n countDistinct: '◇',\n median: 'M̃',\n stdDev: 'σ',\n percentOfTotal: '%Σ',\n custom: 'ƒ',\n };\n return symbols[fn];\n}\n/**\n * Aggregation options for UI\n */\nexport const AGGREGATION_OPTIONS = [\n { value: 'sum', label: 'Sum', symbol: 'Σ' },\n { value: 'count', label: 'Count', symbol: '#' },\n { value: 'avg', label: 'Avg', symbol: 'x̄' },\n { value: 'min', label: 'Min', symbol: '↓' },\n { value: 'max', label: 'Max', symbol: '↑' },\n { value: 'countDistinct', label: 'Unique', symbol: '◇' },\n { value: 'median', label: 'Median', symbol: 'M̃' },\n { value: 'stdDev', label: 'Std Dev', symbol: 'σ' },\n { value: 'percentOfTotal', label: '% of Total', symbol: '%Σ' },\n];\n// ============================================\n// Calculated Fields & Formula Parsing\n// ============================================\n/**\n * Supported functions in calculated field formulas\n */\nexport const FORMULA_FUNCTIONS = ['SUM', 'AVG', 'MIN', 'MAX', 'COUNT', 'MEDIAN'];\n/**\n * Parse a formula and extract field references\n * e.g., \"SUM(revenue) / SUM(units)\" -> [{fn: 'SUM', field: 'revenue'}, {fn: 'SUM', field: 'units'}]\n */\nexport function parseFormula(formula) {\n const regex = /(SUM|AVG|MIN|MAX|COUNT|MEDIAN)\\s*\\(\\s*([^)]+)\\s*\\)/gi;\n const matches = [];\n let match;\n while ((match = regex.exec(formula)) !== null) {\n matches.push({\n fn: match[1].toUpperCase(),\n field: match[2].trim(),\n });\n }\n return matches;\n}\n/**\n * Evaluate a calculated field formula with aggregated values\n * @param formula - Formula string like \"SUM(revenue) / SUM(units) * 100\"\n * @param aggregatedValues - Map of \"FN(field)\" to aggregated value\n * @returns Calculated value or null if evaluation fails\n */\nexport function evaluateFormula(formula, aggregatedValues) {\n try {\n // Replace function calls with their values\n let expression = formula;\n for (const [key, value] of Object.entries(aggregatedValues)) {\n if (value === null)\n return null;\n // Escape special regex characters in key and replace\n const escaped = key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n expression = expression.replace(new RegExp(escaped, 'gi'), String(value));\n }\n // Safety check - only allow numbers, operators, parentheses, and whitespace\n if (!/^[\\d\\s.+\\-*/()]+$/.test(expression)) {\n console.warn('Invalid formula expression:', expression);\n return null;\n }\n // Evaluate the expression\n // Using Function constructor for safe math evaluation\n const result = new Function(`return (${expression})`)();\n if (typeof result !== 'number' || !Number.isFinite(result)) {\n return null;\n }\n return result;\n }\n catch (error) {\n console.warn('Formula evaluation error:', error);\n return null;\n }\n}\n/**\n * Format calculated field value based on format type\n */\nexport function formatCalculatedValue(value, formatAs, decimals = 2, numberFormat = 'us') {\n if (value === null)\n return '-';\n switch (formatAs) {\n case 'percent':\n return `${value.toFixed(decimals)}%`;\n case 'currency':\n return `$${formatNumber(value, numberFormat, { maximumFractionDigits: decimals })}`;\n default:\n return formatNumber(value, numberFormat, { maximumFractionDigits: decimals });\n }\n}\n/**\n * Validate a calculated field formula\n * @returns Error message if invalid, null if valid\n */\nexport function validateFormula(formula, availableFields) {\n if (!formula.trim()) {\n return 'Formula cannot be empty';\n }\n const references = parseFormula(formula);\n if (references.length === 0) {\n return 'Formula must contain at least one function like SUM(field)';\n }\n // Case-insensitive field matching\n const lowerFields = availableFields.map(f => f.toLowerCase());\n for (const ref of references) {\n const fieldLower = ref.field.toLowerCase();\n if (!lowerFields.includes(fieldLower)) {\n return `Unknown field: ${ref.field}`;\n }\n }\n // Try to evaluate with dummy values to check syntax\n const dummyValues = {};\n for (const ref of references) {\n dummyValues[`${ref.fn}(${ref.field})`] = 1;\n }\n const result = evaluateFormula(formula, dummyValues);\n if (result === null) {\n return 'Invalid formula syntax';\n }\n return null;\n}\n/**\n * Parse a simple formula to extract field references (no aggregation functions)\n * e.g., \"sales / units\" -> [\"sales\", \"units\"]\n */\nexport function parseSimpleFormula(formula) {\n // Match word characters that could be field names (not operators or numbers)\n const matches = formula.match(/[a-z_]\\w*/gi) || [];\n // Filter out common keywords/operators\n const keywords = ['true', 'false', 'null', 'undefined'];\n return [...new Set(matches.filter(m => !keywords.includes(m.toLowerCase())))];\n}\n/**\n * Validate a simple formula (field math, no aggregation functions)\n */\nexport function validateSimpleFormula(formula, availableFields) {\n if (!formula.trim()) {\n return 'Formula is required';\n }\n const referencedFields = parseSimpleFormula(formula);\n if (referencedFields.length === 0) {\n return 'Formula must reference at least one field';\n }\n // Case-insensitive field matching\n const lowerFields = availableFields.map(f => f.toLowerCase());\n for (const field of referencedFields) {\n if (!lowerFields.includes(field.toLowerCase())) {\n return `Unknown field: ${field}`;\n }\n }\n // Test that the formula is valid JavaScript\n try {\n // Replace field names with dummy values\n let testExpr = formula;\n for (const field of referencedFields) {\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n testExpr = testExpr.replace(new RegExp(`\\\\b${escaped}\\\\b`, 'gi'), '1');\n }\n new Function(`return ${testExpr}`);\n }\n catch {\n return 'Invalid formula syntax';\n }\n return null;\n}\n/**\n * Evaluate a simple formula for a single row of data\n */\nexport function evaluateSimpleFormula(formula, row, fieldNames) {\n try {\n const referencedFields = parseSimpleFormula(formula);\n let expression = formula;\n for (const field of referencedFields) {\n // Find actual field name (case-insensitive)\n const actualField = fieldNames.find(f => f.toLowerCase() === field.toLowerCase()) || field;\n const value = row[actualField];\n if (value === null || value === undefined || value === '') {\n return null; // Can't compute if any referenced field is missing\n }\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (Number.isNaN(num)) {\n return null;\n }\n // Replace field name with value\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n expression = expression.replace(new RegExp(`\\\\b${escaped}\\\\b`, 'gi'), String(num));\n }\n // Safety check - only allow numbers, operators, parentheses\n if (!/^[\\d\\s+\\-*/().]+$/.test(expression)) {\n return null;\n }\n const result = new Function(`return ${expression}`)();\n return typeof result === 'number' && Number.isFinite(result) ? result : null;\n }\n catch {\n return null;\n }\n}\n/**\n * Create common calculated field presets\n */\nexport const CALCULATED_FIELD_PRESETS = [\n {\n name: 'Profit Margin %',\n formula: 'SUM(profit) / SUM(revenue) * 100',\n formatAs: 'percent',\n description: 'Profit as percentage of revenue',\n },\n {\n name: 'Average Price',\n formula: 'SUM(revenue) / SUM(units)',\n formatAs: 'currency',\n description: 'Revenue per unit sold',\n },\n {\n name: 'Growth Rate',\n formula: '(SUM(current) - SUM(previous)) / SUM(previous) * 100',\n formatAs: 'percent',\n description: 'Percentage change between periods',\n },\n];\n/**\n * Compute available fields from data\n */\nexport function computeAvailableFields(data) {\n if (data.length === 0)\n return [];\n const keys = Object.keys(data[0]);\n return keys.map(field => detectFieldType(data, field));\n}\n/**\n * Get unassigned fields (not in row, column, or value fields)\n */\nexport function getUnassignedFields(availableFields, rowFields, columnFields, valueFields) {\n const assigned = new Set([\n ...rowFields,\n ...columnFields,\n ...valueFields.map(v => v.field),\n ]);\n return availableFields.filter(f => !assigned.has(f.field));\n}\n/**\n * Check if pivot is configured\n */\nexport function isPivotConfigured(config) {\n return (config.rowFields.length > 0 || config.columnFields.length > 0) && config.valueFields.length > 0;\n}\n/**\n * Build pivot result from data and config\n */\nexport function computePivotResult(data, config) {\n const { rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields } = config;\n if (!isPivotConfigured(config))\n return null;\n if (data.length === 0)\n return null;\n // Build a map of calculated field IDs to their definitions\n const calcFieldMap = new Map();\n if (calculatedFields) {\n for (const cf of calculatedFields) {\n calcFieldMap.set(cf.id, cf);\n }\n }\n // Get all field names from data for formula evaluation\n const allDataFieldNames = data.length > 0 ? Object.keys(data[0]) : [];\n // Collect unique row and column keys\n const rowKeySet = new Set();\n const colKeySet = new Set();\n // Group data by row and column keys\n // Each value field (regular or calculated) gets its own array of values\n const dataMap = new Map();\n for (const row of data) {\n const rowKey = rowFields.length > 0 ? makeKey(row, rowFields) : '__all__';\n const colKey = columnFields.length > 0 ? makeKey(row, columnFields) : '__all__';\n rowKeySet.add(rowKey);\n colKeySet.add(colKey);\n if (!dataMap.has(rowKey)) {\n dataMap.set(rowKey, new Map());\n }\n const colMap = dataMap.get(rowKey);\n if (!colMap.has(colKey)) {\n colMap.set(colKey, valueFields.map(() => []));\n }\n const valueArrays = colMap.get(colKey);\n // Collect values for each value field\n for (let i = 0; i < valueFields.length; i++) {\n const vf = valueFields[i];\n let num = null;\n if (vf.field.startsWith('calc:')) {\n // Calculated field - evaluate formula for this row\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n if (calcDef) {\n num = evaluateSimpleFormula(calcDef.formula, row, allDataFieldNames);\n }\n }\n else {\n // Regular field - get value directly\n const val = row[vf.field];\n if (val !== null && val !== undefined && val !== '') {\n num = typeof val === 'number' ? val : Number.parseFloat(String(val));\n if (Number.isNaN(num)) {\n num = (vf.aggregation === 'count' || vf.aggregation === 'countDistinct') ? 1 : null;\n }\n }\n }\n if (num !== null) {\n valueArrays[i].push(num);\n }\n }\n }\n // Sort keys\n const rowKeys = Array.from(rowKeySet).sort();\n const colKeys = Array.from(colKeySet).sort();\n // Pre-calculate grand totals for percentOfTotal calculations\n const grandTotals = valueFields.map((vf, _i) => {\n let total = 0;\n for (const row of data) {\n let num = null;\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n if (calcDef) {\n num = evaluateSimpleFormula(calcDef.formula, row, allDataFieldNames);\n }\n }\n else {\n const val = row[vf.field];\n if (val !== null && val !== undefined && val !== '') {\n num = typeof val === 'number' ? val : Number.parseFloat(String(val));\n if (Number.isNaN(num))\n num = null;\n }\n }\n if (num !== null)\n total += num;\n }\n return total;\n });\n // Helper to get value field display label\n function getValueFieldLabel(vf) {\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n const name = calcDef?.name || vf.field;\n return `${name} (${getAggregationLabel(vf.aggregation)})`;\n }\n return `${vf.label || vf.field} (${getAggregationLabel(vf.aggregation)})`;\n }\n // Build column headers\n // When there are multiple value fields, each column header must be repeated\n // for each value field so the headers align with the data columns\n const headers = [];\n if (columnFields.length > 0) {\n const repeatCount = valueFields.length > 1 ? valueFields.length : 1;\n for (let level = 0; level < columnFields.length; level++) {\n const headerRow = [];\n for (const colKey of colKeys) {\n const parts = parseKey(colKey);\n // Repeat header for each value field\n for (let i = 0; i < repeatCount; i++) {\n headerRow.push(parts[level] || '');\n }\n }\n headers.push(headerRow);\n }\n }\n // If multiple value fields, add value field labels as last header row\n if (valueFields.length > 1 || headers.length === 0) {\n const valueLabels = [];\n for (const _colKey of colKeys) {\n for (const vf of valueFields) {\n valueLabels.push(getValueFieldLabel(vf));\n }\n }\n if (colKeys.length === 1 && colKeys[0] === '__all__') {\n headers.push(valueFields.map(vf => getValueFieldLabel(vf)));\n }\n else {\n headers.push(valueLabels);\n }\n }\n // Build row headers\n const rowHeaders = rowKeys.map((key) => {\n if (key === '__all__')\n return ['Total'];\n return parseKey(key);\n });\n // Build data matrix\n const pivotData = [];\n const rowTotals = [];\n const columnTotalsMap = new Map(); // colKey -> raw values\n for (const rowKey of rowKeys) {\n const rowData = [];\n // Collect all raw values for this row (for row totals)\n const rowAllValues = valueFields.map(() => []);\n for (const colKey of colKeys) {\n const colMap = dataMap.get(rowKey);\n const rawValues = colMap?.get(colKey) || valueFields.map(() => []);\n // Accumulate for row totals\n for (let fi = 0; fi < rawValues.length; fi++) {\n rowAllValues[fi].push(...rawValues[fi]);\n }\n // Accumulate for column totals\n if (!columnTotalsMap.has(colKey)) {\n columnTotalsMap.set(colKey, valueFields.map(() => []));\n }\n const colTotals = columnTotalsMap.get(colKey);\n for (let fi = 0; fi < rawValues.length; fi++) {\n colTotals[fi].push(...rawValues[fi]);\n }\n // Compute cell for each value field\n for (let vfIdx = 0; vfIdx < valueFields.length; vfIdx++) {\n const vf = valueFields[vfIdx];\n const values = rawValues[vfIdx] || [];\n const gtValue = grandTotals[vfIdx];\n const aggValue = aggregate(values, vf.aggregation, gtValue);\n // Format based on whether it's a calculated field\n let formattedValue;\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n formattedValue = formatCalculatedValue(aggValue, calcDef?.formatAs || 'number', calcDef?.decimals ?? 2);\n }\n else {\n formattedValue = formatAggregatedValue(aggValue, vf.aggregation);\n }\n rowData.push({\n value: aggValue,\n count: values.length,\n formattedValue,\n });\n }\n }\n pivotData.push(rowData);\n // Compute row total (using first value field for now)\n if (showRowTotals && colKeys.length > 1) {\n if (valueFields.length > 0) {\n const vf = valueFields[0];\n const values = rowAllValues[0] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[0]);\n rowTotals.push({\n value: aggValue,\n count: values.length,\n formattedValue: formatAggregatedValue(aggValue, vf.aggregation),\n });\n }\n else {\n rowTotals.push({ value: null, count: 0, formattedValue: '-' });\n }\n }\n }\n // Calculate column totals\n const columnTotals = [];\n if (showColumnTotals && rowKeys.length > 1) {\n for (const colKey of colKeys) {\n const colRawValues = columnTotalsMap.get(colKey) || valueFields.map(() => []);\n for (let vfIdx = 0; vfIdx < valueFields.length; vfIdx++) {\n const vf = valueFields[vfIdx];\n const values = colRawValues[vfIdx] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[vfIdx]);\n columnTotals.push({\n value: aggValue,\n count: values.length,\n formattedValue: formatAggregatedValue(aggValue, vf.aggregation),\n });\n }\n }\n }\n // Grand total - collect all values across entire dataset\n const grandTotal = { value: null, count: 0, formattedValue: '-' };\n if (showRowTotals && showColumnTotals && valueFields.length > 0) {\n // Collect all raw values from the entire dataset\n const allRawValues = valueFields.map(() => []);\n for (const rowKey of rowKeys) {\n const colMap = dataMap.get(rowKey);\n if (colMap) {\n for (const colKey of colKeys) {\n const vals = colMap.get(colKey);\n if (vals) {\n for (let fi = 0; fi < vals.length; fi++) {\n allRawValues[fi].push(...vals[fi]);\n }\n }\n }\n }\n }\n const vf = valueFields[0];\n const values = allRawValues[0] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[0]);\n grandTotal.value = aggValue;\n grandTotal.count = values.length;\n grandTotal.formattedValue = formatAggregatedValue(aggValue, vf.aggregation);\n }\n return {\n headers,\n rowHeaders,\n data: pivotData,\n rowTotals,\n columnTotals,\n grandTotal,\n };\n}\n// Storage helpers for pivot config persistence\nconst STORAGE_KEY_PREFIX = 'vpg-pivot-';\n/**\n * Generate a storage key based on column names\n */\nexport function generateStorageKey(columns) {\n const sorted = [...columns].sort();\n const hash = sorted.join('|').substring(0, 100);\n return `${STORAGE_KEY_PREFIX}${hash}`;\n}\n/**\n * Save pivot config to sessionStorage\n */\nexport function savePivotConfig(key, config) {\n try {\n sessionStorage.setItem(key, JSON.stringify(config));\n }\n catch {\n // Ignore storage errors\n }\n}\n/**\n * Load pivot config from sessionStorage\n */\nexport function loadPivotConfig(key) {\n try {\n const stored = sessionStorage.getItem(key);\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // Ignore parse errors\n }\n return null;\n}\n/**\n * Check if config fields exist in available fields\n */\nexport function isConfigValidForFields(config, availableFieldNames) {\n const available = new Set(availableFieldNames);\n const allConfiguredFields = [\n ...config.rowFields,\n ...config.columnFields,\n ...config.valueFields.map(v => v.field),\n ];\n // Filter out calculated fields (they start with 'calc:')\n return allConfiguredFields\n .filter(f => !f.startsWith('calc:'))\n .every(f => available.has(f));\n}\n// Calculated Fields Storage\nconst CALC_FIELDS_KEY = 'vpg-calculated-fields';\n/**\n * Save calculated fields to localStorage (persists across sessions)\n */\nexport function saveCalculatedFields(fields) {\n try {\n localStorage.setItem(CALC_FIELDS_KEY, JSON.stringify(fields));\n }\n catch {\n // Ignore storage errors\n }\n}\n/**\n * Load calculated fields from localStorage\n */\nexport function loadCalculatedFields() {\n try {\n const stored = localStorage.getItem(CALC_FIELDS_KEY);\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // Ignore parse errors\n }\n return [];\n}\n/**\n * Add a calculated field to storage\n */\nexport function addCalculatedField(field) {\n const fields = loadCalculatedFields();\n const existing = fields.findIndex(f => f.id === field.id);\n if (existing >= 0) {\n fields[existing] = field;\n }\n else {\n fields.push(field);\n }\n saveCalculatedFields(fields);\n return fields;\n}\n/**\n * Remove a calculated field from storage\n */\nexport function removeCalculatedField(id) {\n const fields = loadCalculatedFields().filter(f => f.id !== id);\n saveCalculatedFields(fields);\n return fields;\n}\n//# sourceMappingURL=index.js.map","/**\n * TinyPivot Core - Type Definitions\n * Framework-agnostic types used across Vue and React packages\n */\n/** Type guard to check if filter value is a numeric range */\nexport function isNumericRange(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n if (!('min' in value) && !('max' in value))\n return false;\n const v = value;\n return (v.min === null || typeof v.min === 'number') && (v.max === null || typeof v.max === 'number');\n}\n/** Type guard to check if filter value is a date range */\nexport function isDateRange(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n if (!('min' in value) && !('max' in value))\n return false;\n const v = value;\n return (v.min === null || typeof v.min === 'string') && (v.max === null || typeof v.max === 'string');\n}\n//# sourceMappingURL=index.js.map","/**\n * TinyPivot Vue - AI Analyst Composable\n * Manages AI conversation state and data fetching\n */\nimport type {\n AIAnalystConfig,\n AIConversation,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIDataSource,\n AIErrorEvent,\n AIProxyResponse,\n AIQueryExecutedEvent,\n AITableSchema,\n ListTablesResponse,\n SchemaResponse,\n} from '@smallwebco/tinypivot-core'\nimport {\n addMessageToConversation,\n buildSystemPrompt,\n createAssistantMessage,\n createConversation,\n createUserMessage,\n extractSQLFromResponse,\n findDemoResponse,\n getDefaultDemoResponse,\n getDemoSchema,\n getInitialDemoData,\n getMessagesForAPI,\n setConversationDataSource,\n validateSQLSafety,\n} from '@smallwebco/tinypivot-core'\nimport { computed, onMounted, ref } from 'vue'\n\nexport interface UseAIAnalystOptions {\n config: AIAnalystConfig\n onDataLoaded?: (event: AIDataLoadedEvent) => void\n onConversationUpdate?: (event: AIConversationUpdateEvent) => void\n onQueryExecuted?: (event: AIQueryExecutedEvent) => void\n onError?: (event: AIErrorEvent) => void\n}\n\nexport function useAIAnalyst(options: UseAIAnalystOptions) {\n const { config, onDataLoaded, onConversationUpdate, onQueryExecuted, onError } = options\n\n // LocalStorage key for persistence\n const storageKey = config.persistToLocalStorage\n ? `tinypivot-ai-conversation-${config.sessionId || 'default'}`\n : null\n\n // Load initial conversation from localStorage if enabled\n function loadFromStorage(): AIConversation {\n if (storageKey && typeof window !== 'undefined') {\n try {\n const stored = localStorage.getItem(storageKey)\n if (stored) {\n const parsed = JSON.parse(stored)\n // Validate basic structure\n if (parsed.id && Array.isArray(parsed.messages)) {\n return parsed as AIConversation\n }\n }\n }\n catch (e) {\n console.warn('[TinyPivot] Failed to load conversation from localStorage:', e)\n }\n }\n return createConversation(config.sessionId)\n }\n\n // Save conversation to localStorage if enabled\n function saveToStorage(conv: AIConversation) {\n if (storageKey && typeof window !== 'undefined') {\n try {\n // Custom replacer to handle BigInt values (common in DuckDB results)\n const replacer = (_key: string, value: unknown) => {\n if (typeof value === 'bigint') {\n return Number(value)\n }\n return value\n }\n localStorage.setItem(storageKey, JSON.stringify(conv, replacer))\n }\n catch (e) {\n console.warn('[TinyPivot] Failed to save conversation to localStorage:', e)\n }\n }\n }\n\n // State\n const conversation = ref<AIConversation>(loadFromStorage())\n const schemas = ref<Map<string, AITableSchema>>(new Map())\n const allSchemas = ref<AITableSchema[]>([]) // All table schemas for JOINs\n const isLoading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedData = ref<Record<string, unknown>[] | null>(null)\n\n // Dynamic data sources (discovered from endpoint)\n const discoveredDataSources = ref<AIDataSource[]>([])\n const isLoadingTables = ref(false)\n\n // Get effective data sources (config or discovered)\n const effectiveDataSources = computed<AIDataSource[]>(() => {\n if (config.dataSources && config.dataSources.length > 0) {\n return config.dataSources\n }\n return discoveredDataSources.value\n })\n\n // Computed\n const selectedDataSource = computed(() => conversation.value.dataSourceId)\n const selectedDataSourceInfo = computed(() =>\n effectiveDataSources.value.find(ds => ds.id === conversation.value.dataSourceId),\n )\n const messages = computed(() => conversation.value.messages)\n const hasMessages = computed(() => conversation.value.messages.length > 0)\n\n /**\n * Fetch available tables from endpoint (auto-discovery mode)\n */\n async function fetchTables() {\n if (!config.endpoint)\n return\n\n isLoadingTables.value = true\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'list-tables' }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch tables: ${response.statusText}`)\n }\n\n const data: ListTablesResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n // Convert to AIDataSource format\n discoveredDataSources.value = data.tables.map((t: { name: string, description?: string }) => ({\n id: t.name,\n table: t.name,\n name: t.name.charAt(0).toUpperCase() + t.name.slice(1), // Capitalize\n description: t.description,\n }))\n\n // Fetch all schemas for JOIN support\n await fetchAllSchemas()\n }\n catch (err) {\n console.warn('[TinyPivot] Failed to fetch tables:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to fetch tables',\n type: 'network',\n })\n }\n finally {\n isLoadingTables.value = false\n }\n }\n\n /**\n * Fetch schemas for ALL tables at once (enables JOINs)\n */\n async function fetchAllSchemas() {\n if (!config.endpoint)\n return\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'get-all-schemas' }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch all schemas: ${response.statusText}`)\n }\n\n const data: SchemaResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n // Store all schemas for JOIN support\n allSchemas.value = data.schemas\n\n // Also populate the individual schemas map\n for (const schema of data.schemas) {\n schemas.value.set(schema.table, schema)\n }\n }\n catch (err) {\n // Schema fetch is optional - continue without it\n console.warn('[TinyPivot] Failed to fetch all schemas:', err)\n }\n }\n\n // Initialize: fetch tables if using endpoint\n onMounted(() => {\n if (config.endpoint && (!config.dataSources || config.dataSources.length === 0)) {\n fetchTables()\n }\n })\n\n /**\n * Select a data source and fetch its schema\n */\n async function selectDataSource(dataSourceId: string) {\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource) {\n error.value = `Data source \"${dataSourceId}\" not found`\n return\n }\n\n // Update conversation\n conversation.value = setConversationDataSource(conversation.value, dataSourceId)\n\n // Add system message about selection\n const systemMessage = createAssistantMessage(\n `I'm now connected to **${dataSource.name}**. ${dataSource.description || ''}\\n\\nWhat would you like to know about this data?`,\n )\n conversation.value = addMessageToConversation(conversation.value, systemMessage)\n\n // Load data source if custom loader is provided (demo mode)\n if (config.dataSourceLoader) {\n try {\n const { data, schema } = await config.dataSourceLoader(dataSourceId)\n if (schema) {\n schemas.value.set(dataSourceId, schema)\n }\n // Store the loaded data for the data source\n if (data && data.length > 0) {\n lastLoadedData.value = data\n onDataLoaded?.({\n data,\n query: `SELECT * FROM ${dataSource.table} LIMIT 100`,\n dataSourceId,\n rowCount: data.length,\n })\n }\n }\n catch (err) {\n console.warn('Failed to load data source:', err)\n }\n }\n // Fetch schema (demo mode uses mock schemas)\n else if (config.demoMode) {\n const demoSchema = getDemoSchema(dataSourceId)\n if (demoSchema) {\n schemas.value.set(dataSourceId, demoSchema)\n }\n // Load initial sample data for the preview\n const initialData = getInitialDemoData(dataSourceId)\n if (initialData) {\n lastLoadedData.value = initialData\n onDataLoaded?.({\n data: initialData,\n query: `SELECT * FROM ${dataSource.table} LIMIT 10`,\n dataSourceId,\n rowCount: initialData.length,\n })\n }\n }\n // Use endpoint for schema discovery and sample data\n else if (config.endpoint) {\n await fetchSchema(dataSource)\n await fetchSampleData(dataSource)\n }\n\n emitConversationUpdate()\n }\n\n /**\n * Fetch schema from the unified endpoint\n */\n async function fetchSchema(dataSource: AIDataSource) {\n if (!config.endpoint)\n return\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'get-schema',\n tables: [dataSource.table],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch schema: ${response.statusText}`)\n }\n\n const data: SchemaResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n if (data.schemas.length > 0) {\n schemas.value.set(dataSource.id, data.schemas[0])\n }\n }\n catch (err) {\n // Schema fetch is optional - continue without it\n console.warn('Failed to fetch schema:', err)\n }\n }\n\n /**\n * Fetch sample data (first 100 rows) from the unified endpoint\n */\n async function fetchSampleData(dataSource: AIDataSource) {\n if (!config.endpoint)\n return\n\n try {\n const sql = `SELECT * FROM ${dataSource.table} LIMIT 100`\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql,\n table: dataSource.table,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch sample data: ${response.statusText}`)\n }\n\n const result = await response.json()\n\n if (result.error) {\n throw new Error(result.error)\n }\n\n if (result.data && result.data.length > 0) {\n lastLoadedData.value = result.data\n onDataLoaded?.({\n data: result.data,\n query: sql,\n dataSourceId: dataSource.id,\n rowCount: result.data.length,\n })\n }\n }\n catch (err) {\n // Sample data fetch is optional - continue without it\n console.warn('Failed to fetch sample data:', err)\n }\n }\n\n /**\n * Send a message to the AI\n */\n async function sendMessage(content: string) {\n if (!content.trim())\n return\n if (isLoading.value)\n return\n\n error.value = null\n isLoading.value = true\n\n // Add user message\n const userMessage = createUserMessage(content)\n conversation.value = addMessageToConversation(conversation.value, userMessage)\n emitConversationUpdate()\n\n try {\n // Handle demo mode\n if (config.demoMode) {\n await handleDemoResponse(content)\n return\n }\n\n // Check if data source is selected\n if (!conversation.value.dataSourceId) {\n const assistantMessage = createAssistantMessage(\n 'Please select a data source first by clicking one of the options above.',\n )\n conversation.value = addMessageToConversation(conversation.value, assistantMessage)\n emitConversationUpdate()\n return\n }\n\n // Call AI endpoint\n const aiResponse = await callAIEndpoint(content)\n\n // Check if AI wants to run a query\n const sqlQuery = extractSQLFromResponse(aiResponse)\n\n if (sqlQuery) {\n // Validate SQL\n const validation = validateSQLSafety(sqlQuery)\n if (!validation.valid) {\n const errorMessage = createAssistantMessage(\n `I generated an invalid query: ${validation.error}. Let me try again with a corrected approach.`,\n { error: validation.error },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n return\n }\n\n // Add AI response with query - the executeQuery will update this message with data\n const aiMessage = createAssistantMessage(aiResponse, { query: sqlQuery })\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n\n // Execute query - this will update the last message's metadata with data\n await executeQuery(sqlQuery, aiMessage.id)\n }\n else {\n // Just add AI response\n const aiMessage = createAssistantMessage(aiResponse)\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n }\n }\n catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'An error occurred'\n error.value = errorMsg\n\n const errorMessage = createAssistantMessage(\n `Sorry, I encountered an error: ${errorMsg}. Please try again.`,\n { error: errorMsg },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onError?.({\n message: errorMsg,\n type: 'ai',\n })\n }\n finally {\n isLoading.value = false\n }\n }\n\n /**\n * Handle demo mode responses (canned AI + mock data)\n */\n async function handleDemoResponse(userInput: string) {\n // Simulate loading delay\n await new Promise(resolve => setTimeout(resolve, 800))\n\n const dataSourceId = conversation.value.dataSourceId\n\n if (!dataSourceId) {\n const assistantMessage = createAssistantMessage(\n 'Please select a data source first by clicking one of the options above.',\n )\n conversation.value = addMessageToConversation(conversation.value, assistantMessage)\n emitConversationUpdate()\n isLoading.value = false\n return\n }\n\n // Find matching demo response\n const demoTrigger = findDemoResponse(dataSourceId, userInput)\n\n if (demoTrigger) {\n // Add AI response\n const aiMessage = createAssistantMessage(demoTrigger.response, {\n query: demoTrigger.query,\n rowCount: demoTrigger.mockData?.length,\n })\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n\n // Load mock data\n if (demoTrigger.mockData) {\n lastLoadedData.value = demoTrigger.mockData\n\n onDataLoaded?.({\n data: demoTrigger.mockData,\n query: demoTrigger.query || '',\n dataSourceId,\n rowCount: demoTrigger.mockData.length,\n })\n\n onQueryExecuted?.({\n query: demoTrigger.query || '',\n rowCount: demoTrigger.mockData.length,\n duration: 150, // Fake duration\n dataSourceId,\n success: true,\n })\n }\n }\n else {\n // Use default response\n const defaultResponse = getDefaultDemoResponse(dataSourceId)\n const aiMessage = createAssistantMessage(defaultResponse)\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n }\n\n isLoading.value = false\n }\n\n /**\n * Call the AI endpoint\n */\n async function callAIEndpoint(userInput: string): Promise<string> {\n if (!config.endpoint) {\n throw new Error('No endpoint configured. Set `endpoint` in AI analyst config.')\n }\n\n const dataSourceId = conversation.value.dataSourceId\n\n // Build system prompt using effective data sources\n // Pass allSchemas to enable JOINs with related tables\n const systemPrompt = buildSystemPrompt(\n effectiveDataSources.value,\n schemas.value,\n dataSourceId,\n allSchemas.value.length > 0 ? allSchemas.value : undefined,\n )\n\n // Get conversation messages for API\n const apiMessages = getMessagesForAPI(conversation.value)\n\n // Add system prompt and current user message\n const messages = [\n { role: 'user' as const, content: systemPrompt },\n { role: 'assistant' as const, content: 'I understand. I\\'m ready to help you analyze the data.' },\n ...apiMessages.slice(0, -1), // Exclude the just-added user message\n { role: 'user' as const, content: userInput },\n ]\n\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'chat', messages }),\n })\n\n if (!response.ok) {\n throw new Error(`AI request failed: ${response.statusText}`)\n }\n\n const data: AIProxyResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n return data.content\n }\n\n /**\n * Execute a SQL query and update the specified message with results\n * @param sql The SQL query to execute\n * @param messageId Optional message ID to update with results (instead of adding new message)\n */\n async function executeQuery(sql: string, messageId?: string) {\n const dataSourceId = conversation.value.dataSourceId\n if (!dataSourceId)\n return\n\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource)\n return\n\n const startTime = Date.now()\n\n try {\n let data: { data?: Record<string, unknown>[], rowCount?: number, truncated?: boolean, error?: string, success?: boolean }\n\n // Use custom query executor if provided (demo mode)\n if (config.queryExecutor) {\n const result = await config.queryExecutor(sql, dataSource.table)\n data = {\n data: result.data,\n rowCount: result.rowCount,\n truncated: result.truncated,\n error: result.error,\n success: !result.error,\n }\n }\n // Use unified endpoint\n else if (config.endpoint) {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql,\n table: dataSource.table,\n }),\n })\n\n data = await response.json()\n }\n else {\n throw new Error('No query executor or endpoint configured')\n }\n\n const duration = Date.now() - startTime\n\n if (!data.success || data.error) {\n // Add error message\n const errorMessage = createAssistantMessage(\n `The query failed: ${data.error || 'Unknown error'}. Would you like me to try a different approach?`,\n { error: data.error, query: sql },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onQueryExecuted?.({\n query: sql,\n rowCount: 0,\n duration,\n dataSourceId,\n success: false,\n error: data.error,\n })\n\n onError?.({\n message: data.error || 'Query failed',\n query: sql,\n type: 'query',\n })\n return\n }\n\n // Success - load data\n if (data.data) {\n lastLoadedData.value = data.data\n\n // Update the existing message with data, or add a new one if no messageId\n if (messageId) {\n // Find and update the existing message's metadata with the data\n const updatedMessages = conversation.value.messages.map((msg) => {\n if (msg.id === messageId) {\n return {\n ...msg,\n metadata: {\n ...msg.metadata,\n data: data.data,\n rowCount: data.rowCount,\n truncated: data.truncated,\n },\n }\n }\n return msg\n })\n conversation.value = {\n ...conversation.value,\n messages: updatedMessages,\n updatedAt: Date.now(),\n }\n }\n else {\n // Fallback: add a new message (shouldn't happen in normal flow)\n const truncatedNote = data.truncated\n ? ` (limited to ${config.maxRows || 10000} rows)`\n : ''\n const successMessage = createAssistantMessage(\n `Retrieved **${data.rowCount} rows**${truncatedNote}.`,\n { query: sql, rowCount: data.rowCount, data: data.data },\n )\n conversation.value = addMessageToConversation(conversation.value, successMessage)\n }\n emitConversationUpdate()\n\n onDataLoaded?.({\n data: data.data,\n query: sql,\n dataSourceId,\n rowCount: data.rowCount || data.data.length,\n })\n\n onQueryExecuted?.({\n query: sql,\n rowCount: data.rowCount || data.data.length,\n duration,\n dataSourceId,\n success: true,\n })\n }\n }\n catch (err) {\n const duration = Date.now() - startTime\n const errorMsg = err instanceof Error ? err.message : 'Query execution failed'\n\n const errorMessage = createAssistantMessage(\n `Failed to execute query: ${errorMsg}`,\n { error: errorMsg, query: sql },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onQueryExecuted?.({\n query: sql,\n rowCount: 0,\n duration,\n dataSourceId,\n success: false,\n error: errorMsg,\n })\n\n onError?.({\n message: errorMsg,\n query: sql,\n type: 'network',\n })\n }\n }\n\n /**\n * Load full data for the currently selected data source\n * Returns the full dataset (not limited) for displaying in the grid\n */\n async function loadFullData(): Promise<Record<string, unknown>[] | null> {\n const dataSourceId = conversation.value.dataSourceId\n if (!dataSourceId) {\n return null\n }\n\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource) {\n return null\n }\n\n // Use custom data source loader if provided\n if (config.dataSourceLoader) {\n try {\n const { data } = await config.dataSourceLoader(dataSourceId)\n if (data && data.length > 0) {\n return data\n }\n }\n catch (err) {\n console.warn('Failed to load full data:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Use query executor to get all data\n if (config.queryExecutor) {\n try {\n const result = await config.queryExecutor(\n `SELECT * FROM ${dataSource.table}`,\n dataSource.table,\n )\n if (result.data && result.data.length > 0) {\n return result.data\n }\n }\n catch (err) {\n console.warn('Failed to load full data via query:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Use endpoint query action\n if (config.endpoint) {\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql: `SELECT * FROM ${dataSource.table}`,\n table: dataSource.table,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to load data: ${response.statusText}`)\n }\n\n const data = await response.json()\n if (data.data && data.data.length > 0) {\n return data.data\n }\n }\n catch (err) {\n console.warn('Failed to load full data from endpoint:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Demo mode - get initial data\n if (config.demoMode) {\n const initialData = getInitialDemoData(dataSourceId)\n return initialData || null\n }\n\n return null\n }\n\n /**\n * Clear the conversation\n */\n function clearConversation() {\n conversation.value = createConversation(config.sessionId)\n error.value = null\n lastLoadedData.value = null\n emitConversationUpdate()\n }\n\n /**\n * Export conversation for persistence\n */\n function exportConversation(): AIConversation {\n return { ...conversation.value }\n }\n\n /**\n * Import a conversation\n */\n function importConversation(conv: AIConversation) {\n conversation.value = conv\n emitConversationUpdate()\n }\n\n /**\n * Emit conversation update event and persist to storage if enabled\n */\n function emitConversationUpdate() {\n saveToStorage(conversation.value)\n onConversationUpdate?.({ conversation: conversation.value })\n }\n\n return {\n // State\n conversation,\n messages,\n hasMessages,\n schemas,\n isLoading,\n isLoadingTables,\n error,\n lastLoadedData,\n selectedDataSource,\n selectedDataSourceInfo,\n /** Available data sources (either from config or auto-discovered) */\n dataSources: effectiveDataSources,\n\n // Actions\n selectDataSource,\n sendMessage,\n clearConversation,\n exportConversation,\n importConversation,\n /** Refresh table list from endpoint */\n fetchTables,\n /** Load full data for the currently selected data source */\n loadFullData,\n }\n}\n","<script setup lang=\"ts\">\n/**\n * TinyPivot - AI Data Analyst Component\n * Split-panel layout: 1/4 chat, 3/4 data preview\n * Each query step shows data visually with expandable SQL\n */\nimport type {\n AIAnalystConfig,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIErrorEvent,\n AIMessage,\n AIQueryExecutedEvent,\n AITableSchema,\n} from '@smallwebco/tinypivot-core'\nimport { stripSQLFromContent } from '@smallwebco/tinypivot-core'\nimport { computed, nextTick, ref, watch } from 'vue'\nimport { useAIAnalyst } from '../composables/useAIAnalyst'\n\nconst props = defineProps<{\n config: AIAnalystConfig\n theme?: 'light' | 'dark'\n}>()\n\nconst emit = defineEmits<{\n (e: 'dataLoaded', payload: AIDataLoadedEvent): void\n (e: 'conversationUpdate', payload: AIConversationUpdateEvent): void\n (e: 'queryExecuted', payload: AIQueryExecutedEvent): void\n (e: 'error', payload: AIErrorEvent): void\n (e: 'viewResults', payload: { data: Record<string, unknown>[], query: string }): void\n}>()\n\nconst {\n messages,\n hasMessages,\n isLoading,\n isLoadingTables,\n schemas,\n selectedDataSource,\n selectedDataSourceInfo,\n lastLoadedData,\n dataSources,\n selectDataSource,\n sendMessage,\n clearConversation,\n loadFullData,\n} = useAIAnalyst({\n config: props.config,\n onDataLoaded: payload => emit('dataLoaded', payload),\n onConversationUpdate: payload => emit('conversationUpdate', payload),\n onQueryExecuted: payload => emit('queryExecuted', payload),\n onError: payload => emit('error', payload),\n})\n\n// Expose loadFullData for parent component access\ndefineExpose({\n loadFullData,\n selectedDataSource,\n})\n\n// Input state\nconst inputText = ref('')\nconst searchQuery = ref('')\nconst messagesContainerRef = ref<HTMLDivElement>()\n\n// Track which message's data is being viewed (null = latest)\nconst selectedMessageId = ref<string | null>(null)\n\n// Track SQL panel visibility in the right pane\nconst showSqlPanel = ref(false)\n\n// Filter data sources by search\nconst filteredDataSources = computed(() => {\n if (!searchQuery.value.trim())\n return dataSources.value\n const q = searchQuery.value.toLowerCase()\n return dataSources.value.filter(ds =>\n ds.name.toLowerCase().includes(q)\n || ds.description?.toLowerCase().includes(q)\n || ds.table.toLowerCase().includes(q),\n )\n})\n\n// Get schema for selected data source\nconst currentSchema = computed((): AITableSchema | undefined => {\n if (!selectedDataSource.value)\n return undefined\n return schemas.value.get(selectedDataSource.value)\n})\n\n// Get data for the selected message (or latest)\nconst previewData = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n if (msg?.metadata?.data) {\n return msg.metadata.data.slice(0, 100)\n }\n }\n // Fall back to lastLoadedData\n if (!lastLoadedData.value)\n return []\n return lastLoadedData.value.slice(0, 100)\n})\n\n// Get full data for the selected message\nconst fullPreviewData = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n if (msg?.metadata?.data) {\n return msg.metadata.data\n }\n }\n return lastLoadedData.value || []\n})\n\n// Get column keys from preview data\nconst previewColumns = computed(() => {\n if (previewData.value.length > 0) {\n return Object.keys(previewData.value[0])\n }\n if (currentSchema.value) {\n return currentSchema.value.columns.map(c => c.name)\n }\n return []\n})\n\n// Get the selected message's query\nconst selectedQuery = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n return msg?.metadata?.query || ''\n }\n // Find the last message with data\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].metadata?.data) {\n return messages.value[i].metadata?.query || ''\n }\n }\n return ''\n})\n\n// Scroll to bottom when messages change\nwatch(messages, () => {\n nextTick(() => {\n if (messagesContainerRef.value) {\n messagesContainerRef.value.scrollTop = messagesContainerRef.value.scrollHeight\n }\n })\n // Auto-select the latest message with data\n const latestWithData = [...messages.value].reverse().find(m => m.metadata?.data)\n if (latestWithData) {\n selectedMessageId.value = latestWithData.id\n }\n}, { deep: true })\n\nfunction handleSubmit() {\n if (!inputText.value.trim() || isLoading.value)\n return\n sendMessage(inputText.value)\n inputText.value = ''\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault()\n handleSubmit()\n }\n}\n\nfunction handleViewResults() {\n if (fullPreviewData.value.length > 0) {\n emit('viewResults', { data: fullPreviewData.value, query: selectedQuery.value })\n }\n}\n\nfunction selectMessage(messageId: string) {\n const msg = messages.value.find(m => m.id === messageId)\n if (msg?.metadata?.data) {\n selectedMessageId.value = messageId\n }\n}\n\nfunction toggleSqlPanel() {\n showSqlPanel.value = !showSqlPanel.value\n}\n\nfunction copyToClipboard(text: string) {\n if (typeof window !== 'undefined' && window.navigator?.clipboard) {\n window.navigator.clipboard.writeText(text)\n }\n}\n\nfunction handleClearConversation() {\n clearConversation()\n searchQuery.value = ''\n selectedMessageId.value = null\n showSqlPanel.value = false\n}\n\nfunction handleChangeDataSource() {\n clearConversation()\n searchQuery.value = ''\n selectedMessageId.value = null\n showSqlPanel.value = false\n}\n\nfunction getColumnTypeIcon(type: string): string {\n const t = type.toLowerCase()\n if (t.includes('int') || t.includes('float') || t.includes('decimal') || t.includes('number'))\n return '#'\n if (t.includes('date') || t.includes('time'))\n return 'D'\n if (t.includes('bool'))\n return '?'\n return 'T'\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value === null || value === undefined)\n return ''\n if (typeof value === 'number') {\n if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n return String(value)\n }\n return String(value)\n}\n\nfunction getMessageContent(message: AIMessage): string {\n // Strip SQL blocks and clean up markdown formatting\n return stripSQLFromContent(message.content)\n .replace(/\\*\\*/g, '')\n .replace(/`([^`]+)`/g, '$1')\n .trim()\n}\n\nfunction autoResizeTextarea(event: Event) {\n const textarea = event.target as HTMLTextAreaElement\n textarea.style.height = 'auto'\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`\n}\n\nfunction hasQueryResult(message: AIMessage): boolean {\n return !!message.metadata?.data && message.metadata.data.length > 0\n}\n</script>\n\n<template>\n <div class=\"vpg-ai-analyst\" :class=\"{ 'vpg-theme-dark': theme === 'dark' }\">\n <!-- Data Source Picker (full width when no data source selected) -->\n <div v-if=\"!selectedDataSource\" class=\"vpg-ai-picker-fullscreen\">\n <div class=\"vpg-ai-picker-content\">\n <div class=\"vpg-ai-picker-header\">\n <div class=\"vpg-ai-icon-lg\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <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\" />\n <circle cx=\"7.5\" cy=\"14.5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"16.5\" cy=\"14.5\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </div>\n <h2>AI Data Analyst</h2>\n <p>Select a data source to start exploring with AI</p>\n </div>\n\n <!-- Empty state -->\n <template v-if=\"dataSources.length === 0 && !isLoadingTables\">\n <div class=\"vpg-ai-empty-state\">\n <p>No data sources configured.</p>\n <a\n href=\"https://tinypivot.com/docs/ai-analyst\"\n target=\"_blank\"\n rel=\"noopener\"\n class=\"vpg-ai-docs-link\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n View Documentation\n </a>\n </div>\n </template>\n\n <!-- Data source list -->\n <template v-else>\n <div class=\"vpg-ai-search\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n placeholder=\"Search data sources...\"\n class=\"vpg-ai-search-input\"\n >\n </div>\n\n <div class=\"vpg-ai-datasource-grid\">\n <button\n v-for=\"ds in filteredDataSources\"\n :key=\"ds.id\"\n class=\"vpg-ai-datasource-card\"\n @click=\"selectDataSource(ds.id)\"\n >\n <div class=\"vpg-ai-datasource-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\" />\n </svg>\n </div>\n <div class=\"vpg-ai-datasource-info\">\n <span class=\"vpg-ai-datasource-name\">{{ ds.name }}</span>\n <span v-if=\"ds.description\" class=\"vpg-ai-datasource-desc\">{{ ds.description }}</span>\n </div>\n </button>\n </div>\n\n <div v-if=\"filteredDataSources.length === 0\" class=\"vpg-ai-no-results\">\n No data sources match \"{{ searchQuery }}\"\n </div>\n </template>\n </div>\n </div>\n\n <!-- Split Layout: Chat (1/4) + Data Preview (3/4) -->\n <div v-else class=\"vpg-ai-split-layout\">\n <!-- Left Panel: Chat -->\n <div class=\"vpg-ai-chat-panel\">\n <!-- Chat Header -->\n <div class=\"vpg-ai-chat-header\">\n <button\n class=\"vpg-ai-back-btn\"\n title=\"Change data source\"\n @click=\"handleChangeDataSource\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n <div class=\"vpg-ai-chat-title\">\n <span class=\"vpg-ai-chat-name\">{{ selectedDataSourceInfo?.name }}</span>\n </div>\n <button\n v-if=\"hasMessages\"\n class=\"vpg-ai-clear-btn\"\n title=\"Clear conversation\"\n @click=\"handleClearConversation\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n </button>\n </div>\n\n <!-- Messages -->\n <div ref=\"messagesContainerRef\" class=\"vpg-ai-messages\">\n <!-- Welcome message when no messages -->\n <div v-if=\"!hasMessages\" class=\"vpg-ai-welcome\">\n <p>Ask questions about your data</p>\n <div class=\"vpg-ai-suggestions\">\n <button @click=\"sendMessage('Show me a summary of the data')\">\n Summary\n </button>\n <button @click=\"sendMessage('Show me the top 10 records')\">\n Top 10\n </button>\n <button @click=\"sendMessage('What are the trends?')\">\n Trends\n </button>\n </div>\n </div>\n\n <!-- Message list -->\n <template v-for=\"message in messages\" :key=\"message.id\">\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"vpg-ai-msg vpg-ai-msg-user\"\n >\n <span>{{ message.content }}</span>\n </div>\n\n <!-- Assistant message with query result -->\n <div\n v-else-if=\"hasQueryResult(message)\"\n class=\"vpg-ai-msg vpg-ai-msg-result\"\n :class=\"{ 'vpg-ai-msg-selected': selectedMessageId === message.id }\"\n @click=\"selectMessage(message.id)\"\n >\n <!-- Header with result badge and SQL button -->\n <div class=\"vpg-ai-result-header\">\n <div class=\"vpg-ai-result-badge\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" />\n <polyline points=\"22 4 12 14.01 9 11.01\" />\n </svg>\n <span>{{ message.metadata?.rowCount?.toLocaleString() }} rows</span>\n </div>\n <!-- SQL toggle button - toggles right pane SQL panel -->\n <button\n v-if=\"message.metadata?.query\"\n class=\"vpg-ai-sql-toggle\"\n :class=\"{ 'vpg-ai-sql-expanded': showSqlPanel && selectedMessageId === message.id }\"\n title=\"View SQL query\"\n @click.stop=\"toggleSqlPanel()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </svg>\n <span>SQL</span>\n </button>\n </div>\n <!-- Full message content (insight from AI) -->\n <div class=\"vpg-ai-result-content\">\n {{ getMessageContent(message) }}\n </div>\n </div>\n\n <!-- Assistant message without data (text only) -->\n <div\n v-else-if=\"message.role === 'assistant'\"\n class=\"vpg-ai-msg vpg-ai-msg-assistant\"\n >\n <div class=\"vpg-ai-assistant-content\">\n {{ getMessageContent(message) }}\n </div>\n <!-- Error indicator -->\n <div v-if=\"message.metadata?.error\" class=\"vpg-ai-msg-error\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n Error\n </div>\n </div>\n </template>\n\n <!-- Loading indicator -->\n <div v-if=\"isLoading\" class=\"vpg-ai-msg vpg-ai-msg-loading\">\n <div class=\"vpg-ai-typing\">\n <span /><span /><span />\n </div>\n </div>\n </div>\n\n <!-- Input Area with Controls -->\n <div class=\"vpg-ai-input-area\">\n <form class=\"vpg-ai-input-form\" @submit.prevent=\"handleSubmit\">\n <textarea\n v-model=\"inputText\"\n class=\"vpg-ai-input\"\n placeholder=\"Ask about your data...\"\n :disabled=\"isLoading\"\n rows=\"1\"\n @keydown=\"handleKeydown\"\n @input=\"autoResizeTextarea\"\n />\n <button\n type=\"submit\"\n class=\"vpg-ai-send-btn\"\n :disabled=\"!inputText.trim() || isLoading\"\n title=\"Send\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </form>\n <!-- Action buttons and model info -->\n <div class=\"vpg-ai-input-footer\">\n <span v-if=\"config.aiModelName\" class=\"vpg-ai-model-name\">\n {{ config.aiModelName }}\n </span>\n <div class=\"vpg-ai-input-actions\">\n <button\n v-if=\"fullPreviewData.length > 0\"\n class=\"vpg-ai-action-btn vpg-ai-action-primary\"\n title=\"View in Grid tab\"\n @click=\"handleViewResults\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n View in Grid\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Right Panel: Data Scratchpad -->\n <div class=\"vpg-ai-preview-panel\">\n <!-- Header with schema -->\n <div class=\"vpg-ai-preview-header\">\n <div class=\"vpg-ai-preview-title-row\">\n <h3>{{ selectedDataSourceInfo?.name }}</h3>\n <div class=\"vpg-ai-preview-meta\">\n <span v-if=\"fullPreviewData.length > 0\" class=\"vpg-ai-preview-count\">\n {{ fullPreviewData.length.toLocaleString() }} rows\n </span>\n <button\n v-if=\"selectedQuery\"\n class=\"vpg-ai-preview-sql-btn\"\n :class=\"{ 'vpg-ai-sql-active': showSqlPanel }\"\n title=\"Toggle SQL query\"\n @click=\"toggleSqlPanel()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </svg>\n SQL\n </button>\n <button\n v-if=\"fullPreviewData.length > 0\"\n class=\"vpg-ai-preview-view-btn\"\n title=\"View in Grid\"\n @click=\"handleViewResults\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\" />\n <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\" />\n </svg>\n View in Grid\n </button>\n </div>\n </div>\n <!-- Schema pills in preview header -->\n <div v-if=\"currentSchema\" class=\"vpg-ai-schema-bar\">\n <div\n v-for=\"col in currentSchema.columns\"\n :key=\"col.name\"\n class=\"vpg-ai-schema-chip\"\n :title=\"`${col.name} (${col.type})`\"\n >\n <span class=\"vpg-ai-chip-type\">{{ getColumnTypeIcon(col.type) }}</span>\n <span class=\"vpg-ai-chip-name\">{{ col.name }}</span>\n </div>\n </div>\n </div>\n\n <!-- SQL Panel (expandable, above the table) -->\n <div v-if=\"showSqlPanel && selectedQuery\" class=\"vpg-ai-sql-panel\">\n <div class=\"vpg-ai-sql-panel-header\">\n <span class=\"vpg-ai-sql-panel-title\">SQL Query</span>\n <div class=\"vpg-ai-sql-panel-actions\">\n <button\n class=\"vpg-ai-copy-btn\"\n title=\"Copy SQL\"\n @click=\"copyToClipboard(selectedQuery)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n </button>\n <button\n class=\"vpg-ai-sql-panel-close\"\n title=\"Close\"\n @click=\"showSqlPanel = false\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n <pre class=\"vpg-ai-sql-panel-code\"><code>{{ selectedQuery }}</code></pre>\n </div>\n\n <!-- Loading state -->\n <div v-if=\"isLoading\" class=\"vpg-ai-preview-loading\">\n <div class=\"vpg-ai-preview-spinner\" />\n <span>Running query...</span>\n </div>\n\n <!-- No data yet - show schema only state -->\n <div v-else-if=\"previewData.length === 0 && currentSchema\" class=\"vpg-ai-preview-ready\">\n <div class=\"vpg-ai-preview-ready-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\" />\n <path d=\"M3 12c0 1.66 4 3 9 3s9-1.34 9-3\" />\n </svg>\n </div>\n <p>Data source connected</p>\n <span>{{ currentSchema.columns.length }} columns available</span>\n <div class=\"vpg-ai-preview-hint\">\n Ask a question to explore the data\n </div>\n </div>\n\n <!-- No schema loaded yet -->\n <div v-else-if=\"previewData.length === 0\" class=\"vpg-ai-preview-empty\">\n <div class=\"vpg-ai-preview-empty-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </div>\n <p>Loading data source...</p>\n </div>\n\n <!-- Data table -->\n <div v-else class=\"vpg-ai-preview-table-container\">\n <table class=\"vpg-ai-preview-table\">\n <thead>\n <tr>\n <th v-for=\"col in previewColumns\" :key=\"col\">\n {{ col }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, idx) in previewData\" :key=\"idx\">\n <td v-for=\"col in previewColumns\" :key=\"col\">\n {{ formatCellValue(row[col]) }}\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"fullPreviewData.length > 100\" class=\"vpg-ai-preview-more\">\n Showing 100 of {{ fullPreviewData.length.toLocaleString() }} rows.\n <button @click=\"handleViewResults\">\n View all in Grid\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-ai-analyst {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8fafc;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n/* Full-screen picker */\n.vpg-ai-picker-fullscreen {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n}\n\n.vpg-ai-picker-content {\n max-width: 600px;\n width: 100%;\n max-height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.vpg-ai-picker-header {\n text-align: center;\n margin-bottom: 2rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-icon-lg {\n width: 4rem;\n height: 4rem;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n border-radius: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n margin: 0 auto 1rem;\n}\n\n.vpg-ai-icon-lg svg {\n width: 2rem;\n height: 2rem;\n}\n\n.vpg-ai-picker-header h2 {\n margin: 0 0 0.5rem;\n font-size: 1.5rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-picker-header p {\n margin: 0;\n color: #64748b;\n}\n\n/* Search */\n.vpg-ai-search {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n margin-bottom: 1rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-search svg {\n width: 1.25rem;\n height: 1.25rem;\n color: #94a3b8;\n flex-shrink: 0;\n}\n\n.vpg-ai-search-input {\n flex: 1;\n border: none;\n outline: none;\n font-size: 0.9375rem;\n color: #1e293b;\n background: transparent;\n}\n\n.vpg-ai-search-input::placeholder {\n color: #94a3b8;\n}\n\n/* Data source grid */\n.vpg-ai-datasource-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.75rem;\n overflow-y: auto;\n max-height: 400px;\n padding-right: 0.25rem;\n}\n\n.vpg-ai-datasource-card {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n cursor: pointer;\n text-align: left;\n transition: all 0.15s;\n}\n\n.vpg-ai-datasource-card:hover {\n border-color: #6366f1;\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);\n}\n\n.vpg-ai-datasource-icon {\n width: 2.25rem;\n height: 2.25rem;\n background: #eef2ff;\n border-radius: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #6366f1;\n flex-shrink: 0;\n}\n\n.vpg-ai-datasource-icon svg {\n width: 1.125rem;\n height: 1.125rem;\n}\n\n.vpg-ai-datasource-info {\n flex: 1;\n min-width: 0;\n}\n\n.vpg-ai-datasource-name {\n display: block;\n font-size: 0.8125rem;\n font-weight: 600;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-datasource-desc {\n display: block;\n font-size: 0.6875rem;\n color: #64748b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-no-results,\n.vpg-ai-empty-state {\n text-align: center;\n padding: 2rem;\n color: #94a3b8;\n}\n\n.vpg-ai-docs-link {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.625rem 1rem;\n font-size: 0.875rem;\n color: #6366f1;\n background: #eef2ff;\n border-radius: 0.375rem;\n text-decoration: none;\n transition: all 0.15s;\n}\n\n.vpg-ai-docs-link:hover {\n background: #e0e7ff;\n}\n\n.vpg-ai-docs-link svg {\n width: 1rem;\n height: 1rem;\n}\n\n/* Split Layout */\n.vpg-ai-split-layout {\n flex: 1;\n display: flex;\n min-height: 0;\n}\n\n/* Chat Panel (1/4) */\n.vpg-ai-chat-panel {\n width: 300px;\n min-width: 260px;\n max-width: 360px;\n display: flex;\n flex-direction: column;\n background: white;\n border-right: 1px solid #e2e8f0;\n}\n\n.vpg-ai-chat-header {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.5rem 0.625rem;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-back-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-back-btn:hover {\n background: #f1f5f9;\n color: #1e293b;\n}\n\n.vpg-ai-back-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-ai-clear-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-clear-btn:hover {\n background: #fef2f2;\n color: #dc2626;\n}\n\n.vpg-ai-clear-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-ai-chat-title {\n flex: 1;\n min-width: 0;\n}\n\n.vpg-ai-chat-name {\n display: block;\n font-size: 0.75rem;\n font-weight: 600;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Messages */\n.vpg-ai-messages {\n flex: 1;\n overflow-y: auto;\n padding: 0.75rem;\n padding-bottom: 1rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.vpg-ai-welcome {\n text-align: center;\n padding: 0.75rem 0;\n}\n\n.vpg-ai-welcome p {\n margin: 0 0 0.5rem;\n font-size: 0.75rem;\n color: #64748b;\n}\n\n.vpg-ai-suggestions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 0.25rem;\n}\n\n.vpg-ai-suggestions button {\n padding: 0.25rem 0.5rem;\n font-size: 0.625rem;\n color: #6366f1;\n background: #eef2ff;\n border: none;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-suggestions button:hover {\n background: #e0e7ff;\n}\n\n/* Message styles */\n.vpg-ai-msg {\n max-width: 100%;\n font-size: 0.75rem;\n line-height: 1.5;\n}\n\n.vpg-ai-msg-user {\n align-self: flex-end;\n background: #4f46e5;\n color: white;\n padding: 0.5rem 0.625rem;\n border-radius: 0.75rem 0.75rem 0.25rem 0.75rem;\n max-width: 90%;\n word-wrap: break-word;\n flex-shrink: 0;\n}\n\n.vpg-ai-msg-assistant {\n background: #f1f5f9;\n color: #334155;\n padding: 0.5rem 0.625rem;\n border-radius: 0.75rem 0.75rem 0.75rem 0.25rem;\n max-width: 100%;\n flex-shrink: 0;\n}\n\n.vpg-ai-assistant-content {\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.vpg-ai-msg-error {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-top: 0.375rem;\n padding: 0.25rem 0.5rem;\n background: #fef2f2;\n color: #dc2626;\n font-size: 0.6875rem;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-msg-error svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Result message (clickable) */\n.vpg-ai-msg-result {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n cursor: pointer;\n transition: all 0.15s;\n padding: 0.5rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-msg-result:hover {\n border-color: #c7d2fe;\n}\n\n.vpg-ai-msg-result.vpg-ai-msg-selected {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);\n}\n\n/* Result header with badge and SQL toggle */\n.vpg-ai-result-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.375rem;\n}\n\n/* Result badge */\n.vpg-ai-result-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n background: #ecfdf5;\n color: #059669;\n font-size: 0.625rem;\n font-weight: 600;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-result-badge svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* SQL toggle button */\n.vpg-ai-sql-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n background: #f1f5f9;\n color: #64748b;\n font-size: 0.625rem;\n font-weight: 500;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-sql-toggle:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-sql-toggle.vpg-ai-sql-expanded {\n background: #eef2ff;\n color: #6366f1;\n border-color: #c7d2fe;\n}\n\n.vpg-ai-sql-toggle svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n/* Expanded SQL block */\n.vpg-ai-sql-expanded-block {\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n margin-bottom: 0.375rem;\n overflow: hidden;\n}\n\n.vpg-ai-sql-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.25rem 0.5rem;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n font-size: 0.625rem;\n font-weight: 600;\n color: #64748b;\n}\n\n/* Result content - full text */\n.vpg-ai-result-content {\n font-size: 0.75rem;\n color: #334155;\n line-height: 1.5;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.vpg-ai-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #94a3b8;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-copy-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-copy-btn svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-ai-sql-code {\n margin: 0;\n padding: 0.375rem 0.5rem;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.6875rem;\n color: #334155;\n background: #f8fafc;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.vpg-ai-sql-code code {\n font-family: inherit;\n}\n\n/* Loading */\n.vpg-ai-msg-loading {\n align-self: flex-start;\n}\n\n.vpg-ai-typing {\n display: flex;\n gap: 0.1875rem;\n padding: 0.375rem 0.5rem;\n background: #f1f5f9;\n border-radius: 0.5rem;\n}\n\n.vpg-ai-typing span {\n width: 0.3125rem;\n height: 0.3125rem;\n background: #94a3b8;\n border-radius: 50%;\n animation: vpg-ai-bounce 1.4s infinite ease-in-out both;\n}\n\n.vpg-ai-typing span:nth-child(1) { animation-delay: -0.32s; }\n.vpg-ai-typing span:nth-child(2) { animation-delay: -0.16s; }\n\n@keyframes vpg-ai-bounce {\n 0%, 80%, 100% { transform: scale(0); }\n 40% { transform: scale(1); }\n}\n\n/* Input Area */\n.vpg-ai-input-area {\n padding: 0.5rem;\n border-top: 1px solid #e2e8f0;\n background: white;\n}\n\n.vpg-ai-input-form {\n display: flex;\n gap: 0.375rem;\n align-items: flex-end;\n}\n\n.vpg-ai-input {\n flex: 1;\n padding: 0.5rem 0.75rem;\n font-size: 0.8125rem;\n border: 1px solid #e2e8f0;\n border-radius: 0.75rem;\n resize: none;\n outline: none;\n transition: border-color 0.15s, box-shadow 0.15s;\n min-height: 2.25rem;\n max-height: 120px;\n overflow-y: auto;\n line-height: 1.4;\n}\n\n.vpg-ai-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);\n}\n\n.vpg-ai-input:disabled {\n background: #f8fafc;\n cursor: not-allowed;\n}\n\n.vpg-ai-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n background: #4f46e5;\n border: none;\n border-radius: 50%;\n color: white;\n cursor: pointer;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.vpg-ai-send-btn:hover:not(:disabled) {\n background: #4338ca;\n}\n\n.vpg-ai-send-btn:disabled {\n background: #cbd5e1;\n cursor: not-allowed;\n}\n\n.vpg-ai-send-btn svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Input footer with model name and actions */\n.vpg-ai-input-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 0.375rem;\n}\n\n.vpg-ai-model-name {\n font-size: 0.625rem;\n font-style: italic;\n color: #94a3b8;\n}\n\n/* Action buttons */\n.vpg-ai-input-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.vpg-ai-action-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n background: #f1f5f9;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-action-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-action-btn svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-ai-action-btn.vpg-ai-action-primary {\n background: #eef2ff;\n color: #4f46e5;\n}\n\n.vpg-ai-action-btn.vpg-ai-action-primary:hover {\n background: #e0e7ff;\n}\n\n/* Preview Panel (3/4) */\n.vpg-ai-preview-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n background: #f8fafc;\n}\n\n.vpg-ai-preview-header {\n display: flex;\n flex-direction: column;\n background: white;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-preview-title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n}\n\n.vpg-ai-preview-header h3 {\n margin: 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-preview-meta {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-ai-preview-count {\n font-size: 0.75rem;\n color: #64748b;\n padding: 0.125rem 0.5rem;\n background: #f1f5f9;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-preview-sql-btn,\n.vpg-ai-preview-view-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n background: #f1f5f9;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-preview-sql-btn:hover,\n.vpg-ai-preview-view-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-preview-view-btn {\n background: #eef2ff;\n color: #4f46e5;\n}\n\n.vpg-ai-preview-view-btn:hover {\n background: #e0e7ff;\n}\n\n.vpg-ai-preview-sql-btn svg,\n.vpg-ai-preview-view-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n/* Schema bar in preview header */\n.vpg-ai-schema-bar {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n padding: 0.5rem 0.75rem;\n background: #fafbfc;\n border-top: 1px solid #f1f5f9;\n max-height: 80px;\n overflow-y: auto;\n}\n\n.vpg-ai-schema-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n}\n\n.vpg-ai-chip-type {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #e2e8f0;\n border-radius: 0.125rem;\n font-size: 0.625rem;\n font-weight: 700;\n color: #64748b;\n}\n\n.vpg-ai-chip-name {\n color: #475569;\n font-family: ui-monospace, monospace;\n}\n\n/* SQL Panel (collapsible, above the table) */\n.vpg-ai-sql-panel {\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-sql-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-sql-panel-title {\n font-size: 0.6875rem;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.vpg-ai-sql-panel-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-ai-sql-panel-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #94a3b8;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-sql-panel-close:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-sql-panel-close svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-ai-sql-panel-code {\n margin: 0;\n padding: 0.75rem;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.75rem;\n line-height: 1.5;\n color: #334155;\n background: #f8fafc;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 150px;\n overflow-y: auto;\n}\n\n.vpg-ai-sql-panel-code code {\n font-family: inherit;\n}\n\n/* SQL button active state */\n.vpg-ai-preview-sql-btn.vpg-ai-sql-active {\n background: #eef2ff;\n color: #6366f1;\n border-color: #c7d2fe;\n}\n\n/* Loading state */\n.vpg-ai-preview-loading {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 2rem;\n}\n\n.vpg-ai-preview-spinner {\n width: 2rem;\n height: 2rem;\n border: 2px solid #e2e8f0;\n border-top-color: #6366f1;\n border-radius: 50%;\n animation: vpg-ai-spin 1s linear infinite;\n}\n\n@keyframes vpg-ai-spin {\n to { transform: rotate(360deg); }\n}\n\n.vpg-ai-preview-loading span {\n font-size: 0.8125rem;\n color: #64748b;\n}\n\n/* Ready state (schema loaded, no data yet) */\n.vpg-ai-preview-ready {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n text-align: center;\n}\n\n.vpg-ai-preview-ready-icon {\n width: 4rem;\n height: 4rem;\n background: #ecfdf5;\n border-radius: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #10b981;\n margin-bottom: 1rem;\n}\n\n.vpg-ai-preview-ready-icon svg {\n width: 2rem;\n height: 2rem;\n}\n\n.vpg-ai-preview-ready p {\n margin: 0 0 0.25rem;\n font-size: 1rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-preview-ready span {\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-ai-preview-hint {\n margin-top: 1rem;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-radius: 0.5rem;\n font-size: 0.8125rem;\n color: #64748b;\n}\n\n/* Preview empty state */\n.vpg-ai-preview-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n text-align: center;\n}\n\n.vpg-ai-preview-empty-icon {\n width: 3.5rem;\n height: 3.5rem;\n background: #e2e8f0;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n margin-bottom: 0.75rem;\n}\n\n.vpg-ai-preview-empty-icon svg {\n width: 1.75rem;\n height: 1.75rem;\n}\n\n.vpg-ai-preview-empty p {\n margin: 0 0 0.25rem;\n font-size: 0.8125rem;\n font-weight: 500;\n color: #475569;\n}\n\n.vpg-ai-preview-empty span {\n font-size: 0.75rem;\n color: #94a3b8;\n}\n\n/* Preview table */\n.vpg-ai-preview-table-container {\n flex: 1;\n overflow: auto;\n}\n\n.vpg-ai-preview-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.6875rem;\n}\n\n.vpg-ai-preview-table thead {\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.vpg-ai-preview-table th {\n padding: 0.375rem 0.625rem;\n text-align: left;\n font-size: 0.625rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n white-space: nowrap;\n}\n\n.vpg-ai-preview-table td {\n padding: 0.375rem 0.625rem;\n color: #334155;\n background: white;\n border-bottom: 1px solid #f1f5f9;\n white-space: nowrap;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-preview-table tr:hover td {\n background: #f8fafc;\n}\n\n.vpg-ai-preview-more {\n padding: 0.5rem 0.75rem;\n text-align: center;\n font-size: 0.6875rem;\n color: #64748b;\n background: white;\n border-top: 1px solid #e2e8f0;\n}\n\n.vpg-ai-preview-more button {\n color: #4f46e5;\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 500;\n margin-left: 0.25rem;\n}\n\n.vpg-ai-preview-more button:hover {\n text-decoration: underline;\n}\n\n/* Dark theme */\n.vpg-ai-analyst.vpg-theme-dark {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-ai-picker-header h2 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-picker-header p {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-search {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-search-input {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-card {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-card:hover {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-name {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-chat-panel {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-chat-header {\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-back-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-clear-btn:hover {\n background: rgba(220, 38, 38, 0.15);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-ai-chat-name {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-welcome p {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-suggestions button {\n background: #334155;\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-suggestions button:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-ai-msg-assistant {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result:hover {\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result.vpg-ai-msg-selected {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-result-badge {\n background: rgba(16, 185, 129, 0.15);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-ai-result-content {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-sql-reference {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-label {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-sql-code {\n background: #0f172a;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-copy-btn:hover {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-typing {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-input-area {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-input {\n background: #0f172a;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-input:focus {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn.vpg-ai-action-primary {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-preview-panel {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-ai-preview-header {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-preview-header h3 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn,\n.vpg-theme-dark .vpg-ai-preview-view-btn {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn:hover,\n.vpg-theme-dark .vpg-ai-preview-view-btn:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-view-btn {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-preview-count {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-schema-bar {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-schema-chip {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-chip-type {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-chip-name {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-loading span {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-spinner {\n border-color: #334155;\n border-top-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready-icon {\n background: rgba(16, 185, 129, 0.15);\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready p {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready span {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-hint {\n background: #1e293b;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-empty-icon {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-preview-empty p {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table th {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table td {\n background: #0f172a;\n border-color: #1e293b;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table tr:hover td {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-ai-preview-more {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-result-icon {\n background: rgba(16, 185, 129, 0.15);\n}\n\n.vpg-theme-dark .vpg-ai-model-name {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-header {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-title {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-close:hover {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-code {\n background: #0f172a;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn.vpg-ai-sql-active {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { CalculatedField } from '@smallwebco/tinypivot-core'\nimport {\n validateSimpleFormula,\n} from '@smallwebco/tinypivot-core'\n/**\n * Calculated Field Modal\n * UI for creating custom calculated fields with formulas\n */\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n show: boolean\n availableFields: string[]\n existingField?: CalculatedField | null\n}>()\n\nconst emit = defineEmits<{\n (e: 'close'): void\n (e: 'save', field: CalculatedField): void\n}>()\n\n// Form state\nconst name = ref('')\nconst formula = ref('')\nconst formatAs = ref<'number' | 'percent' | 'currency'>('number')\nconst decimals = ref(2)\nconst error = ref<string | null>(null)\n\n// Reset form when modal opens\nwatch(() => props.show, (show) => {\n if (show) {\n if (props.existingField) {\n name.value = props.existingField.name\n formula.value = props.existingField.formula\n formatAs.value = props.existingField.formatAs || 'number'\n decimals.value = props.existingField.decimals ?? 2\n }\n else {\n name.value = ''\n formula.value = ''\n formatAs.value = 'number'\n decimals.value = 2\n }\n error.value = null\n }\n})\n\n// Validate formula on change\nconst validationError = computed(() => {\n if (!formula.value.trim())\n return null\n return validateSimpleFormula(formula.value, props.availableFields)\n})\n\n// Insert field into formula\nfunction insertField(field: string) {\n // Add field with space padding if there's already content\n if (formula.value.trim() && !formula.value.endsWith(' ')) {\n formula.value += ' '\n }\n formula.value += field\n}\n\n// Insert operator into formula\nfunction insertOperator(op: string) {\n if (formula.value.trim() && !formula.value.endsWith(' ')) {\n formula.value += ' '\n }\n formula.value += `${op} `\n}\n\n// Save calculated field\nfunction save() {\n if (!name.value.trim()) {\n error.value = 'Name is required'\n return\n }\n\n const validationResult = validateSimpleFormula(formula.value, props.availableFields)\n if (validationResult) {\n error.value = validationResult\n return\n }\n\n const field: CalculatedField = {\n id: props.existingField?.id || `calc_${Date.now()}`,\n name: name.value.trim(),\n formula: formula.value.trim(),\n formatAs: formatAs.value,\n decimals: decimals.value,\n }\n\n emit('save', field)\n emit('close')\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div v-if=\"show\" class=\"vpg-modal-overlay\" @click.self=\"emit('close')\">\n <div class=\"vpg-modal\">\n <div class=\"vpg-modal-header\">\n <h3>{{ existingField ? 'Edit' : 'Create' }} Calculated Field</h3>\n <button class=\"vpg-modal-close\" @click=\"emit('close')\">\n ×\n </button>\n </div>\n\n <div class=\"vpg-modal-body\">\n <!-- Name -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label\">Name</label>\n <input\n v-model=\"name\"\n type=\"text\"\n class=\"vpg-input\"\n placeholder=\"e.g., Profit Margin %\"\n >\n </div>\n\n <!-- Formula -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label\">Formula</label>\n <textarea\n v-model=\"formula\"\n class=\"vpg-textarea\"\n placeholder=\"e.g., revenue / units\"\n rows=\"2\"\n />\n <div class=\"vpg-formula-hint\">\n Use field names with math operators: + - * / ( )\n </div>\n <div v-if=\"validationError\" class=\"vpg-error\">\n {{ validationError }}\n </div>\n </div>\n\n <!-- Quick Insert: Operators -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label-small\">Operators</label>\n <div class=\"vpg-button-group\">\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('+')\">\n +\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('-')\">\n −\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('*')\">\n ×\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('/')\">\n ÷\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('(')\">\n (\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator(')')\">\n )\n </button>\n </div>\n </div>\n\n <!-- Quick Insert: Fields (numeric only) -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label-small\">Insert Field</label>\n <div v-if=\"availableFields.length > 0\" class=\"vpg-button-group vpg-field-buttons\">\n <button\n v-for=\"field in availableFields\"\n :key=\"field\"\n class=\"vpg-insert-btn vpg-field-btn\"\n @click=\"insertField(field)\"\n >\n {{ field }}\n </button>\n </div>\n <div v-else class=\"vpg-no-fields\">\n No numeric fields available\n </div>\n </div>\n\n <!-- Format Options -->\n <div class=\"vpg-form-row\">\n <div class=\"vpg-form-group vpg-form-group-half\">\n <label class=\"vpg-label\">Format As</label>\n <select v-model=\"formatAs\" class=\"vpg-select\">\n <option value=\"number\">\n Number\n </option>\n <option value=\"percent\">\n Percentage\n </option>\n <option value=\"currency\">\n Currency ($)\n </option>\n </select>\n </div>\n <div class=\"vpg-form-group vpg-form-group-half\">\n <label class=\"vpg-label\">Decimals</label>\n <input\n v-model.number=\"decimals\"\n type=\"number\"\n class=\"vpg-input\"\n min=\"0\"\n max=\"6\"\n >\n </div>\n </div>\n\n <!-- Error -->\n <div v-if=\"error\" class=\"vpg-error vpg-error-box\">\n {{ error }}\n </div>\n </div>\n\n <div class=\"vpg-modal-footer\">\n <button class=\"vpg-btn vpg-btn-secondary\" @click=\"emit('close')\">\n Cancel\n </button>\n <button class=\"vpg-btn vpg-btn-primary\" @click=\"save\">\n {{ existingField ? 'Update' : 'Add' }} Field\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<style scoped>\n.vpg-modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n backdrop-filter: blur(2px);\n}\n\n.vpg-modal {\n background: white;\n border-radius: 0.75rem;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 90%;\n max-width: 520px;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.25rem;\n border-bottom: 1px solid #e2e8f0;\n background: #f8fafc;\n}\n\n.vpg-modal-header h3 {\n font-size: 1rem;\n font-weight: 600;\n color: #1e293b;\n margin: 0;\n}\n\n.vpg-modal-close {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n color: #64748b;\n background: transparent;\n border: none;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-modal-close:hover {\n background: #e2e8f0;\n color: #1e293b;\n}\n\n.vpg-modal-body {\n padding: 1.25rem;\n overflow-y: auto;\n flex: 1;\n}\n\n.vpg-form-group {\n margin-bottom: 1rem;\n}\n\n.vpg-form-group-half {\n flex: 1;\n}\n\n.vpg-form-row {\n display: flex;\n gap: 1rem;\n}\n\n.vpg-label {\n display: block;\n font-size: 0.8125rem;\n font-weight: 600;\n color: #374151;\n margin-bottom: 0.375rem;\n}\n\n.vpg-label-small {\n display: block;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n margin-bottom: 0.375rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-input,\n.vpg-textarea,\n.vpg-select {\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n border: 1px solid #d1d5db;\n border-radius: 0.375rem;\n background: white;\n color: #1e293b;\n transition: all 0.15s;\n}\n\n.vpg-input:focus,\n.vpg-textarea:focus,\n.vpg-select:focus {\n outline: none;\n border-color: #6366f1;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n}\n\n.vpg-textarea {\n font-family: ui-monospace, monospace;\n resize: vertical;\n}\n\n.vpg-button-group {\n display: flex;\n flex-wrap: wrap;\n gap: 0.375rem;\n}\n\n.vpg-field-buttons {\n max-height: 80px;\n overflow-y: auto;\n}\n\n.vpg-insert-btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 600;\n background: #eef2ff;\n color: #4f46e5;\n border: 1px solid #c7d2fe;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-insert-btn:hover {\n background: #e0e7ff;\n border-color: #a5b4fc;\n}\n\n.vpg-op-btn {\n min-width: 2rem;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.vpg-formula-hint {\n margin-top: 0.25rem;\n font-size: 0.6875rem;\n color: #64748b;\n}\n\n.vpg-field-btn {\n background: #f0fdf4;\n color: #15803d;\n border-color: #bbf7d0;\n}\n\n.vpg-field-btn:hover {\n background: #dcfce7;\n border-color: #86efac;\n}\n\n.vpg-no-fields {\n font-size: 0.75rem;\n color: #94a3b8;\n font-style: italic;\n padding: 0.5rem;\n text-align: center;\n background: #f8fafc;\n border-radius: 0.375rem;\n}\n\n.vpg-error {\n font-size: 0.75rem;\n color: #dc2626;\n margin-top: 0.25rem;\n}\n\n.vpg-error-box {\n padding: 0.5rem 0.75rem;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.375rem;\n margin-top: 0.5rem;\n}\n\n.vpg-modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1rem 1.25rem;\n border-top: 1px solid #e2e8f0;\n background: #f8fafc;\n}\n\n.vpg-btn {\n padding: 0.5rem 1rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-btn-secondary {\n background: white;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.vpg-btn-secondary:hover {\n background: #f3f4f6;\n}\n\n.vpg-btn-primary {\n background: #4f46e5;\n color: white;\n border: 1px solid #4f46e5;\n}\n\n.vpg-btn-primary:hover {\n background: #4338ca;\n border-color: #4338ca;\n}\n</style>\n\n<style>\n/* Dark mode styles */\n.vpg-theme-dark .vpg-modal {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-modal-header {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-modal-header h3 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-modal-close {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-modal-close:hover {\n background: #334155;\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-label {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-label-small {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-input,\n.vpg-theme-dark .vpg-textarea,\n.vpg-theme-dark .vpg-select {\n background: #0f172a;\n border-color: #334155;\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-input:focus,\n.vpg-theme-dark .vpg-textarea:focus,\n.vpg-theme-dark .vpg-select:focus {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-insert-btn {\n background: rgba(99, 102, 241, 0.15);\n color: #a5b4fc;\n border-color: rgba(99, 102, 241, 0.3);\n}\n\n.vpg-theme-dark .vpg-field-btn {\n background: rgba(34, 197, 94, 0.15);\n color: #86efac;\n border-color: rgba(34, 197, 94, 0.3);\n}\n\n.vpg-theme-dark .vpg-no-fields {\n background: #334155;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-modal-footer {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-btn-secondary {\n background: #334155;\n color: #e2e8f0;\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-btn-secondary:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-error-box {\n background: rgba(220, 38, 38, 0.15);\n border-color: rgba(220, 38, 38, 0.3);\n}\n</style>\n","<script setup lang=\"ts\">\nimport type {\n ChartAggregation,\n ChartConfig,\n ChartFieldInfo,\n ChartType,\n} from '@smallwebco/tinypivot-core'\n/**\n * TinyPivot - Chart Builder Component\n * Drag-and-drop chart configuration with ApexCharts rendering\n */\nimport type { ApexOptions } from 'apexcharts'\nimport {\n analyzeFieldsForChart,\n CHART_AGGREGATIONS,\n CHART_COLORS,\n CHART_TYPES,\n createDefaultChartConfig,\n getChartGuidance,\n isChartConfigValid,\n processChartData,\n processChartDataForHeatmap,\n processChartDataForPie,\n processChartDataForScatter,\n} from '@smallwebco/tinypivot-core'\nimport { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue'\n\nconst props = defineProps<{\n data: Record<string, unknown>[]\n theme?: 'light' | 'dark'\n}>()\n\nconst emit = defineEmits<{\n (e: 'configChange', config: ChartConfig): void\n}>()\n\n// Lazy load ApexCharts only on client side to avoid SSR issues\nconst VueApexCharts = defineAsyncComponent(() =>\n import('vue3-apexcharts').then(m => m.default),\n)\n\n// Chart configuration state\nconst chartConfig = ref<ChartConfig>(createDefaultChartConfig())\n\n// Field analysis\nconst fieldInfos = computed(() => analyzeFieldsForChart(props.data))\n\n// Separate fields by role\nconst dimensions = computed(() => fieldInfos.value.filter(f => f.role === 'dimension' || f.role === 'temporal'))\nconst measures = computed(() => fieldInfos.value.filter(f => f.role === 'measure'))\n\n// Drag state\nconst draggingField = ref<ChartFieldInfo | null>(null)\nconst dragOverZone = ref<string | null>(null)\n\n// UI state\nconst showChartTypeSelector = ref(false)\n\n// Current guidance message\nconst guidance = computed(() => getChartGuidance(chartConfig.value))\n\n// Check if chart is ready to render\nconst chartIsValid = computed(() => isChartConfigValid(chartConfig.value))\n\n// Get currently selected chart type info\nconst selectedChartType = computed(() =>\n CHART_TYPES.find(ct => ct.type === chartConfig.value.type),\n)\n\n// Dynamic zone labels based on chart type\nconst zoneLabels = computed(() => {\n const type = chartConfig.value.type\n switch (type) {\n case 'scatter':\n case 'bubble':\n return {\n xAxis: 'X-Axis (measure)',\n xAxisPlaceholder: 'Drop a measure',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Color by (optional)',\n seriesPlaceholder: 'Group points by dimension',\n showSize: type === 'bubble',\n showSeries: true,\n }\n case 'heatmap':\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (dimension)',\n yAxisPlaceholder: 'Drop a dimension',\n series: 'Value / Intensity',\n seriesPlaceholder: 'Drop a measure for color intensity',\n showSize: false,\n showSeries: true,\n }\n case 'pie':\n case 'donut':\n return {\n xAxis: 'Slices (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Values (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: '',\n seriesPlaceholder: '',\n showSize: false,\n showSeries: false,\n }\n case 'radar':\n return {\n xAxis: 'Axes (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Values (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Compare by (optional)',\n seriesPlaceholder: 'Group by dimension',\n showSize: false,\n showSeries: true,\n }\n case 'stackedBar':\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Series (stacking field)',\n seriesPlaceholder: 'Drop a dimension to stack by',\n showSize: false,\n showSeries: true,\n }\n default: // bar, line, area\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Color / Series (optional)',\n seriesPlaceholder: 'Group by dimension',\n showSize: false,\n showSeries: true,\n }\n }\n})\n\n// Check if scatter/bubble needs numeric fields\nconst isScatterType = computed(() => ['scatter', 'bubble'].includes(chartConfig.value.type))\nconst isHeatmapType = computed(() => chartConfig.value.type === 'heatmap')\n\n// Drag handlers\nfunction handleDragStart(field: ChartFieldInfo, event: DragEvent) {\n draggingField.value = field\n event.dataTransfer?.setData('text/plain', field.field)\n}\n\nfunction handleDragEnd() {\n draggingField.value = null\n dragOverZone.value = null\n}\n\nfunction handleDragOver(zone: string, event: DragEvent) {\n event.preventDefault()\n dragOverZone.value = zone\n}\n\nfunction handleDragLeave() {\n dragOverZone.value = null\n}\n\nfunction handleDrop(zone: string, event: DragEvent) {\n event.preventDefault()\n dragOverZone.value = null\n\n if (!draggingField.value)\n return\n\n const field = draggingField.value\n const chartField = {\n field: field.field,\n label: field.label,\n role: field.role,\n aggregation: field.role === 'measure' ? 'sum' as ChartAggregation : undefined,\n }\n\n switch (zone) {\n case 'xAxis':\n chartConfig.value = { ...chartConfig.value, xAxis: chartField }\n break\n case 'yAxis':\n chartConfig.value = { ...chartConfig.value, yAxis: chartField }\n break\n case 'series':\n chartConfig.value = { ...chartConfig.value, seriesField: chartField }\n break\n case 'size':\n chartConfig.value = { ...chartConfig.value, sizeField: chartField }\n break\n case 'color':\n chartConfig.value = { ...chartConfig.value, colorField: chartField }\n break\n }\n\n emit('configChange', chartConfig.value)\n}\n\nfunction removeField(zone: string) {\n switch (zone) {\n case 'xAxis':\n chartConfig.value = { ...chartConfig.value, xAxis: undefined }\n break\n case 'yAxis':\n chartConfig.value = { ...chartConfig.value, yAxis: undefined }\n break\n case 'series':\n chartConfig.value = { ...chartConfig.value, seriesField: undefined }\n break\n case 'size':\n chartConfig.value = { ...chartConfig.value, sizeField: undefined }\n break\n case 'color':\n chartConfig.value = { ...chartConfig.value, colorField: undefined }\n break\n }\n emit('configChange', chartConfig.value)\n}\n\nfunction selectChartType(type: ChartType) {\n chartConfig.value = { ...chartConfig.value, type }\n showChartTypeSelector.value = false\n emit('configChange', chartConfig.value)\n}\n\nfunction updateAggregation(zone: string, aggregation: ChartAggregation) {\n const field = zone === 'yAxis' ? chartConfig.value.yAxis : chartConfig.value.sizeField\n if (!field)\n return\n\n const updated = { ...field, aggregation }\n if (zone === 'yAxis') {\n chartConfig.value = { ...chartConfig.value, yAxis: updated }\n }\n else if (zone === 'size') {\n chartConfig.value = { ...chartConfig.value, sizeField: updated }\n }\n emit('configChange', chartConfig.value)\n}\n\n// Chart rendering\nconst chartOptions = computed<ApexOptions>(() => {\n const isDark = props.theme === 'dark'\n const config = chartConfig.value\n const options = config.options || {}\n\n const baseOptions: ApexOptions = {\n chart: {\n type: getApexChartType(config.type),\n background: 'transparent',\n foreColor: isDark ? '#e2e8f0' : '#334155',\n toolbar: {\n show: true,\n tools: {\n download: true,\n selection: false,\n zoom: options.enableZoom ?? false,\n zoomin: options.enableZoom ?? false,\n zoomout: options.enableZoom ?? false,\n pan: false,\n reset: options.enableZoom ?? false,\n },\n export: {\n csv: { filename: 'chart-data' },\n svg: { filename: 'chart' },\n png: { filename: 'chart' },\n },\n },\n animations: {\n enabled: options.animated ?? true,\n speed: 400,\n dynamicAnimation: { enabled: true, speed: 300 },\n },\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n colors: options.colors || CHART_COLORS,\n theme: {\n mode: isDark ? 'dark' : 'light',\n },\n grid: {\n show: options.showGrid ?? true,\n borderColor: isDark ? '#334155' : '#e2e8f0',\n },\n legend: {\n show: options.showLegend ?? true,\n position: options.legendPosition || 'top',\n },\n dataLabels: {\n enabled: options.showDataLabels ?? false,\n },\n tooltip: {\n theme: isDark ? 'dark' : 'light',\n style: {\n fontSize: '12px',\n },\n // Override light mode tooltip text color for better contrast\n cssClass: isDark ? '' : 'apexcharts-tooltip-light',\n },\n stroke: {\n curve: 'smooth',\n width: config.type === 'line' ? 3 : config.type === 'area' ? 2 : 0,\n },\n fill: {\n opacity: config.type === 'area' ? 0.4 : 1,\n },\n }\n\n // Add axis titles\n if (config.xAxis) {\n baseOptions.xaxis = {\n ...baseOptions.xaxis,\n title: { text: options.xAxisTitle || config.xAxis.label },\n labels: {\n style: { colors: isDark ? '#94a3b8' : '#64748b' },\n },\n }\n }\n\n if (config.yAxis && !['pie', 'donut', 'radar'].includes(config.type)) {\n baseOptions.yaxis = {\n title: { text: options.yAxisTitle || config.yAxis.label },\n labels: {\n style: { colors: isDark ? '#94a3b8' : '#64748b' },\n formatter: (val: number) => formatValue(val, options.valueFormat, options.decimals),\n },\n }\n }\n\n // Chart title\n if (options.title) {\n baseOptions.title = {\n text: options.title,\n style: {\n fontSize: '16px',\n fontWeight: 600,\n color: isDark ? '#e2e8f0' : '#334155',\n },\n }\n }\n\n // Stacking — forced on for stackedBar, optional for bar/area\n if (config.type === 'stackedBar' || (options.stacked && ['bar', 'area'].includes(config.type))) {\n baseOptions.chart!.stacked = true\n }\n\n // Pie/Donut specific\n if (config.type === 'pie' || config.type === 'donut') {\n baseOptions.plotOptions = {\n pie: {\n donut: {\n size: config.type === 'donut' ? '55%' : '0%',\n labels: {\n show: config.type === 'donut',\n total: {\n show: true,\n label: 'Total',\n formatter: (w) => {\n const total = w.globals.seriesTotals.reduce((a: number, b: number) => a + b, 0)\n return formatValue(total, options.valueFormat, options.decimals)\n },\n },\n },\n },\n },\n }\n }\n\n // Radar specific\n if (config.type === 'radar') {\n baseOptions.plotOptions = {\n radar: {\n polygons: {\n strokeColors: isDark ? '#334155' : '#e2e8f0',\n fill: { colors: isDark ? ['#1e293b', '#0f172a'] : ['#f8fafc', '#f1f5f9'] },\n },\n },\n }\n }\n\n return baseOptions\n})\n\nconst chartSeries = computed(() => {\n const config = chartConfig.value\n\n if (!chartIsValid.value)\n return []\n\n // Process based on chart type\n if (config.type === 'pie' || config.type === 'donut') {\n const data = processChartDataForPie(props.data, config)\n return data.series[0]?.data || []\n }\n\n if (config.type === 'scatter' || config.type === 'bubble') {\n const scatterData = processChartDataForScatter(props.data, config)\n return scatterData.series\n }\n\n if (config.type === 'heatmap') {\n const heatmapData = processChartDataForHeatmap(props.data, config)\n return heatmapData.series\n }\n\n // Standard charts (bar, line, area, etc.)\n const data = processChartData(props.data, config)\n return data.series\n})\n\nconst chartLabels = computed(() => {\n const config = chartConfig.value\n\n if (!chartIsValid.value)\n return []\n\n if (config.type === 'pie' || config.type === 'donut') {\n const data = processChartDataForPie(props.data, config)\n return data.categories\n }\n\n const data = processChartData(props.data, config)\n return data.categories\n})\n\n// Update xaxis categories in options\nconst chartOptionsWithCategories = computed<ApexOptions>(() => {\n const options = { ...chartOptions.value }\n const config = chartConfig.value\n\n // Heatmap, scatter, bubble have x values in data itself\n if (!['pie', 'donut', 'scatter', 'bubble', 'heatmap'].includes(config.type)) {\n options.xaxis = {\n ...options.xaxis,\n categories: chartLabels.value,\n }\n }\n\n if (config.type === 'pie' || config.type === 'donut') {\n options.labels = chartLabels.value\n }\n\n // Heatmap specific options\n if (config.type === 'heatmap') {\n options.chart = {\n ...options.chart,\n type: 'heatmap',\n }\n options.xaxis = {\n ...options.xaxis,\n type: 'category',\n }\n options.dataLabels = {\n enabled: true,\n style: {\n colors: ['#fff'],\n fontSize: '10px',\n },\n formatter: (val: unknown) => {\n if (val === null || val === undefined)\n return ''\n if (typeof val !== 'number')\n return String(val)\n if (val >= 1000000)\n return `${(val / 1000000).toFixed(1)}M`\n if (val >= 1000)\n return `${(val / 1000).toFixed(0)}K`\n return Math.round(val).toLocaleString()\n },\n }\n options.plotOptions = {\n heatmap: {\n shadeIntensity: 0.5,\n radius: 2,\n enableShades: true,\n colorScale: {\n inverse: false,\n },\n },\n }\n // Use a single color that varies by intensity\n options.colors = ['#6366f1']\n // Disable legend for heatmap (color scale is self-explanatory)\n options.legend = { show: false }\n }\n\n return options\n})\n\ntype ApexChartType = 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter' | 'heatmap' | 'bubble'\n\nfunction getApexChartType(type: ChartType): ApexChartType {\n const mapping: Record<ChartType, ApexChartType> = {\n bar: 'bar',\n stackedBar: 'bar',\n line: 'line',\n area: 'area',\n pie: 'pie',\n donut: 'donut',\n radar: 'radar',\n scatter: 'scatter',\n bubble: 'bubble',\n heatmap: 'heatmap',\n }\n return mapping[type] || 'bar'\n}\n\nfunction formatValue(val: unknown, format?: string, decimals?: number): string {\n // Handle non-number values (ApexCharts sometimes passes strings or undefined)\n if (val === null || val === undefined)\n return ''\n if (typeof val !== 'number')\n return String(val)\n if (Number.isNaN(val))\n return ''\n\n const dec = decimals ?? 0\n if (format === 'percent') {\n return `${val.toFixed(dec)}%`\n }\n if (format === 'currency') {\n return `$${val.toLocaleString(undefined, { minimumFractionDigits: dec, maximumFractionDigits: dec })}`\n }\n if (Math.abs(val) >= 1000) {\n return val.toLocaleString(undefined, { maximumFractionDigits: dec })\n }\n return val.toFixed(dec)\n}\n\n// Icons for chart types (inline SVG paths)\nfunction getChartIcon(type: ChartType): string {\n const icons: Record<ChartType, string> = {\n bar: 'M3 3v18h18V3H3zm4 14H5v-6h2v6zm4 0H9V7h2v10zm4 0h-2V9h2v8zm4 0h-2v-4h2v4z',\n stackedBar: 'M3 3v18h18V3H3zm4 14H5v-3h2v3zm0-4H5v-3h2v3zm4 4H9v-5h2v5zm0-6H9v-4h2v4zm4 6h-2v-3h2v3zm0-4h-2v-5h2v5zm4 4h-2v-2h2v2zm0-3h-2v-2h2v2z',\n line: 'M3.5 18.5l6-6 4 4 8-8M14.5 8.5h6v6',\n area: 'M3 17l6-6 4 4 8-8v10H3z',\n pie: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8v8l5.66 5.66C14.28 19.04 13.18 20 12 20z',\n donut: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z',\n scatter: 'M7 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-3 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4z',\n bubble: 'M7 14a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm5-5a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',\n heatmap: 'M3 3h4v4H3V3zm6 0h4v4H9V3zm6 0h4v4h-4V3zM3 9h4v4H3V9zm6 0h4v4H9V9zm6 0h4v4h-4V9zM3 15h4v4H3v-4zm6 0h4v4H9v-4zm6 0h4v4h-4v-4z',\n radar: 'M12 2L4 6v6c0 5.55 3.84 10.74 8 12 4.16-1.26 8-6.45 8-12V6l-8-4zm0 3.18l6 3v5.09c0 4.08-2.76 7.91-6 9.14V5.18z',\n }\n return icons[type] || icons.bar\n}\n\n// Watch for data changes\nwatch(() => props.data, () => {\n // Fields might have changed, could reset config if needed\n}, { deep: true })\n\n// Emit initial config\nonMounted(() => {\n emit('configChange', chartConfig.value)\n})\n</script>\n\n<template>\n <div class=\"vpg-chart-builder\">\n <!-- Chart Type Selector -->\n <div class=\"vpg-chart-type-bar\">\n <button\n v-for=\"ct in CHART_TYPES\"\n :key=\"ct.type\"\n class=\"vpg-chart-type-btn\"\n :class=\"{ active: chartConfig.type === ct.type }\"\n :title=\"ct.description\"\n @click=\"selectChartType(ct.type)\"\n >\n <svg class=\"vpg-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path :d=\"getChartIcon(ct.type)\" />\n </svg>\n <span class=\"vpg-chart-type-label\">{{ ct.label.replace(' Chart', '') }}</span>\n </button>\n </div>\n\n <div class=\"vpg-chart-builder-content\">\n <!-- Field Lists -->\n <div class=\"vpg-chart-fields-panel\">\n <div class=\"vpg-chart-fields-section\">\n <h4 class=\"vpg-chart-fields-title\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6h16M4 12h10M4 18h6\" />\n </svg>\n Dimensions\n <span class=\"vpg-chart-fields-hint\">(text/date)</span>\n </h4>\n <div class=\"vpg-chart-fields-list\">\n <div\n v-for=\"field in dimensions\"\n :key=\"field.field\"\n class=\"vpg-chart-field-chip vpg-field-dimension\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-name\">{{ field.label }}</span>\n <span class=\"vpg-field-type\">{{ field.role === 'temporal' ? 'date' : 'text' }}</span>\n </div>\n <div v-if=\"dimensions.length === 0\" class=\"vpg-chart-fields-empty\">\n No dimension fields detected\n </div>\n </div>\n </div>\n\n <div class=\"vpg-chart-fields-section\">\n <h4 class=\"vpg-chart-fields-title\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16 8v8M12 11v5M8 14v2M4 4v16h16\" />\n </svg>\n Measures\n <span class=\"vpg-chart-fields-hint\">(numbers)</span>\n </h4>\n <div class=\"vpg-chart-fields-list\">\n <div\n v-for=\"field in measures\"\n :key=\"field.field\"\n class=\"vpg-chart-field-chip vpg-field-measure\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-name\">{{ field.label }}</span>\n <span class=\"vpg-field-type\">#</span>\n </div>\n <div v-if=\"measures.length === 0\" class=\"vpg-chart-fields-empty\">\n No numeric fields detected\n </div>\n </div>\n </div>\n </div>\n\n <!-- Drop Zones -->\n <div class=\"vpg-chart-config-panel\">\n <!-- X-Axis -->\n <div class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.xAxis }}</label>\n <div\n class=\"vpg-chart-drop-zone\"\n :class=\"{ 'drag-over': dragOverZone === 'xAxis', 'has-field': chartConfig.xAxis }\"\n @dragover=\"handleDragOver('xAxis', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('xAxis', $event)\"\n >\n <template v-if=\"chartConfig.xAxis\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.xAxis.label }}</span>\n <select\n v-if=\"isScatterType && chartConfig.xAxis.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.xAxis.aggregation || 'sum'\"\n @change=\"updateAggregation('xAxis', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('xAxis')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.xAxisPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Y-Axis -->\n <div class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.yAxis }}</label>\n <div\n class=\"vpg-chart-drop-zone\"\n :class=\"{ 'drag-over': dragOverZone === 'yAxis', 'has-field': chartConfig.yAxis }\"\n @dragover=\"handleDragOver('yAxis', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('yAxis', $event)\"\n >\n <template v-if=\"chartConfig.yAxis\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.yAxis.label }}</span>\n <select\n v-if=\"chartConfig.yAxis.role === 'measure' && !isHeatmapType\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.yAxis.aggregation || 'sum'\"\n @change=\"updateAggregation('yAxis', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('yAxis')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.yAxisPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Series / Color (conditional) -->\n <div v-if=\"zoneLabels.showSeries\" class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.series }}</label>\n <div\n class=\"vpg-chart-drop-zone vpg-zone-optional\"\n :class=\"{ 'drag-over': dragOverZone === 'series', 'has-field': chartConfig.seriesField || (isHeatmapType && chartConfig.colorField) }\"\n @dragover=\"handleDragOver(isHeatmapType ? 'color' : 'series', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop(isHeatmapType ? 'color' : 'series', $event)\"\n >\n <template v-if=\"isHeatmapType ? chartConfig.colorField : chartConfig.seriesField\">\n <span class=\"vpg-zone-field-name\">{{ isHeatmapType ? chartConfig.colorField?.label : chartConfig.seriesField?.label }}</span>\n <select\n v-if=\"isHeatmapType && chartConfig.colorField?.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.colorField?.aggregation || 'sum'\"\n @change=\"updateAggregation('color', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField(isHeatmapType ? 'color' : 'series')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.seriesPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Size (for bubble charts) -->\n <div v-if=\"zoneLabels.showSize\" class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">Size (number)</label>\n <div\n class=\"vpg-chart-drop-zone vpg-zone-optional\"\n :class=\"{ 'drag-over': dragOverZone === 'size', 'has-field': chartConfig.sizeField }\"\n @dragover=\"handleDragOver('size', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('size', $event)\"\n >\n <template v-if=\"chartConfig.sizeField\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.sizeField.label }}</span>\n <select\n v-if=\"chartConfig.sizeField.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.sizeField.aggregation || 'sum'\"\n @change=\"updateAggregation('size', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('size')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">Drop a number for bubble size</span>\n </template>\n </div>\n </div>\n\n <!-- Guidance -->\n <div class=\"vpg-chart-guidance\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4M12 8h.01\" />\n </svg>\n <span>{{ guidance }}</span>\n </div>\n </div>\n\n <!-- Chart Preview -->\n <div class=\"vpg-chart-preview-panel\">\n <div v-if=\"chartIsValid\" class=\"vpg-chart-container\">\n <Suspense>\n <VueApexCharts\n :key=\"`${chartConfig.type}-${JSON.stringify(chartConfig.xAxis)}-${JSON.stringify(chartConfig.yAxis)}`\"\n :type=\"getApexChartType(chartConfig.type)\"\n :options=\"chartOptionsWithCategories\"\n :series=\"chartSeries\"\n height=\"100%\"\n />\n <template #fallback>\n <div class=\"vpg-chart-loading\">\n <div class=\"vpg-chart-spinner\" />\n <span>Loading chart...</span>\n </div>\n </template>\n </Suspense>\n </div>\n <div v-else class=\"vpg-chart-empty-state\">\n <svg class=\"vpg-icon-lg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path :d=\"getChartIcon(chartConfig.type)\" />\n </svg>\n <h3>Build your chart</h3>\n <p>Drag fields from the left panel to configure your visualization</p>\n <div class=\"vpg-chart-hint\">\n <strong>{{ selectedChartType?.label }}</strong>: {{ selectedChartType?.description }}\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { DateFormat, DateRange } from '@smallwebco/tinypivot-core'\nimport { formatDate, getDatePlaceholder, parseDateInput } from '@smallwebco/tinypivot-core'\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n dataMin: string // ISO date string\n dataMax: string // ISO date string\n currentRange: DateRange | null\n dateFormat?: DateFormat\n}>()\n\nconst emit = defineEmits<{\n change: [range: DateRange | null]\n}>()\n\nconst format = computed(() => props.dateFormat ?? 'iso')\n\n// Local state\nconst localMinText = ref('')\nconst localMaxText = ref('')\nconst minError = ref(false)\nconst maxError = ref(false)\n\n// Initialize from props\nfunction initFromRange(range: DateRange | null) {\n if (range?.min) {\n localMinText.value = formatDate(range.min, format.value)\n }\n else {\n localMinText.value = ''\n }\n if (range?.max) {\n localMaxText.value = formatDate(range.max, format.value)\n }\n else {\n localMaxText.value = ''\n }\n minError.value = false\n maxError.value = false\n}\n\n// Display formatted data bounds\nconst formattedMin = computed(() => formatDate(props.dataMin, format.value))\nconst formattedMax = computed(() => formatDate(props.dataMax, format.value))\n\nconst isFilterActive = computed(() => localMinText.value !== '' || localMaxText.value !== '')\n\nfunction handleMinInput() {\n if (localMinText.value === '') {\n minError.value = false\n emitChange()\n return\n }\n const parsed = parseDateInput(localMinText.value, format.value)\n minError.value = parsed === null\n if (!minError.value)\n emitChange()\n}\n\nfunction handleMaxInput() {\n if (localMaxText.value === '') {\n maxError.value = false\n emitChange()\n return\n }\n const parsed = parseDateInput(localMaxText.value, format.value)\n maxError.value = parsed === null\n if (!maxError.value)\n emitChange()\n}\n\nfunction emitChange() {\n const min = localMinText.value ? parseDateInput(localMinText.value, format.value) : null\n const max = localMaxText.value ? parseDateInput(localMaxText.value, format.value) : null\n if (min === null && max === null) {\n emit('change', null)\n }\n else {\n emit('change', { min, max })\n }\n}\n\nfunction clearFilter() {\n localMinText.value = ''\n localMaxText.value = ''\n minError.value = false\n maxError.value = false\n emit('change', null)\n}\n\nfunction setFullRange() {\n localMinText.value = formatDate(props.dataMin, format.value)\n localMaxText.value = formatDate(props.dataMax, format.value)\n minError.value = false\n maxError.value = false\n emit('change', { min: props.dataMin, max: props.dataMax })\n}\n\nwatch(() => props.currentRange, (newRange) => {\n initFromRange(newRange)\n}, { immediate: true })\n</script>\n\n<template>\n <div class=\"vpg-range-filter\">\n <!-- Data range info -->\n <div class=\"vpg-range-info\">\n <span class=\"vpg-range-label\">Data range:</span>\n <span class=\"vpg-range-bounds\">{{ formattedMin }} – {{ formattedMax }}</span>\n </div>\n\n <!-- Input fields -->\n <div class=\"vpg-range-inputs\">\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">From</label>\n <input\n v-model=\"localMinText\"\n type=\"text\"\n class=\"vpg-range-input\"\n :class=\"{ 'vpg-input-error': minError }\"\n :placeholder=\"getDatePlaceholder(format)\"\n @blur=\"handleMinInput\"\n @keyup.enter=\"handleMinInput\"\n >\n </div>\n <span class=\"vpg-input-separator\">to</span>\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">To</label>\n <input\n v-model=\"localMaxText\"\n type=\"text\"\n class=\"vpg-range-input\"\n :class=\"{ 'vpg-input-error': maxError }\"\n :placeholder=\"getDatePlaceholder(format)\"\n @blur=\"handleMaxInput\"\n @keyup.enter=\"handleMaxInput\"\n >\n </div>\n </div>\n\n <!-- Quick actions -->\n <div class=\"vpg-range-actions\">\n <button\n class=\"vpg-range-btn\"\n :disabled=\"!isFilterActive\"\n @click=\"clearFilter\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear\n </button>\n <button class=\"vpg-range-btn\" @click=\"setFullRange\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n Full Range\n </button>\n </div>\n\n <!-- Filter summary -->\n <div v-if=\"isFilterActive && !minError && !maxError\" class=\"vpg-filter-summary\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span>\n Showing dates\n <strong v-if=\"localMinText\">from {{ localMinText }}</strong>\n {{ localMinText && localMaxText ? ' ' : '' }}\n <strong v-if=\"localMaxText\">to {{ localMaxText }}</strong>\n </span>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-range-filter { padding: 0.5rem; }\n.vpg-range-info { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; font-size: 0.6875rem; }\n.vpg-range-label { color: #64748b; }\n.vpg-range-bounds { font-weight: 500; color: #334155; background: #f1f5f9; padding: 0.125rem 0.375rem; border-radius: 0.25rem; }\n.vpg-range-inputs { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }\n.vpg-input-group { flex: 1; }\n.vpg-input-label { display: block; font-size: 0.625rem; font-weight: 500; color: #64748b; margin-bottom: 0.125rem; text-transform: uppercase; letter-spacing: 0.025em; }\n.vpg-range-input { width: 100%; padding: 0.375rem 0.5rem; font-size: 0.75rem; border: 1px solid #cbd5e1; border-radius: 0.25rem; outline: none; transition: border-color 0.15s, box-shadow 0.15s; }\n.vpg-range-input:focus { border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); }\n.vpg-range-input::placeholder { color: #94a3b8; }\n.vpg-range-input.vpg-input-error { border-color: #ef4444; }\n.vpg-range-input.vpg-input-error:focus { box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.15); }\n.vpg-input-separator { color: #94a3b8; font-size: 0.6875rem; padding-top: 1rem; }\n.vpg-range-actions { display: flex; gap: 0.375rem; margin-bottom: 0.5rem; }\n.vpg-range-btn { display: flex; align-items: center; gap: 0.25rem; padding: 0.25rem 0.5rem; font-size: 0.6875rem; font-weight: 500; color: #475569; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.25rem; cursor: pointer; transition: all 0.15s; }\n.vpg-range-btn:hover:not(:disabled) { background: #f1f5f9; border-color: #cbd5e1; color: #334155; }\n.vpg-range-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.vpg-icon-xs { width: 0.75rem; height: 0.75rem; }\n.vpg-filter-summary { display: flex; align-items: center; gap: 0.375rem; padding: 0.375rem 0.5rem; background: #eef2ff; border-radius: 0.25rem; font-size: 0.6875rem; color: #4338ca; }\n.vpg-filter-summary strong { font-weight: 600; }\n</style>\n","<script setup lang=\"ts\">\nimport type { NumberFormat, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Numeric Range Filter Component\n * Provides an intuitive dual-handle slider and input fields for filtering numeric data\n */\nimport { formatNumber } from '@smallwebco/tinypivot-core'\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n dataMin: number\n dataMax: number\n currentRange: NumericRange | null\n numberFormat?: NumberFormat\n}>()\n\nconst emit = defineEmits<{\n change: [range: NumericRange | null]\n}>()\n\n// Local state for the range values\nconst localMin = ref<number | null>(props.currentRange?.min ?? null)\nconst localMax = ref<number | null>(props.currentRange?.max ?? null)\n\n// Calculate step based on data range\nconst step = computed(() => {\n const range = props.dataMax - props.dataMin\n if (range === 0)\n return 1\n if (range <= 1)\n return 0.01\n if (range <= 10)\n return 0.1\n if (range <= 100)\n return 1\n if (range <= 1000)\n return 10\n return 10 ** (Math.floor(Math.log10(range)) - 2)\n})\n\n// Format numbers for display\nfunction formatValue(val: number | null): string {\n if (val === null)\n return ''\n return formatNumber(val, props.numberFormat ?? 'us')\n}\n\n// Check if filter is active\nconst isFilterActive = computed(() => {\n return localMin.value !== null || localMax.value !== null\n})\n\n// Calculate slider percentages for visual representation\nconst minPercent = computed(() => {\n if (localMin.value === null || props.dataMax === props.dataMin)\n return 0\n return ((localMin.value - props.dataMin) / (props.dataMax - props.dataMin)) * 100\n})\n\nconst maxPercent = computed(() => {\n if (localMax.value === null || props.dataMax === props.dataMin)\n return 100\n return ((localMax.value - props.dataMin) / (props.dataMax - props.dataMin)) * 100\n})\n\n// Handle min slider change\nfunction handleMinSlider(event: Event) {\n const target = event.target as HTMLInputElement\n const value = Number.parseFloat(target.value)\n\n // Ensure min doesn't exceed max\n if (localMax.value !== null && value > localMax.value) {\n localMin.value = localMax.value\n }\n else {\n localMin.value = value\n }\n}\n\n// Handle max slider change\nfunction handleMaxSlider(event: Event) {\n const target = event.target as HTMLInputElement\n const value = Number.parseFloat(target.value)\n\n // Ensure max doesn't go below min\n if (localMin.value !== null && value < localMin.value) {\n localMax.value = localMin.value\n }\n else {\n localMax.value = value\n }\n}\n\n// Handle min input change\nfunction handleMinInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? null : Number.parseFloat(target.value)\n\n if (value !== null && !Number.isNaN(value)) {\n // Clamp to data bounds\n localMin.value = Math.max(props.dataMin, Math.min(value, localMax.value ?? props.dataMax))\n }\n else if (value === null) {\n localMin.value = null\n }\n}\n\n// Handle max input change\nfunction handleMaxInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? null : Number.parseFloat(target.value)\n\n if (value !== null && !Number.isNaN(value)) {\n // Clamp to data bounds\n localMax.value = Math.min(props.dataMax, Math.max(value, localMin.value ?? props.dataMin))\n }\n else if (value === null) {\n localMax.value = null\n }\n}\n\n// Clear the filter\nfunction clearFilter() {\n localMin.value = null\n localMax.value = null\n emitChange()\n}\n\n// Set to full range\nfunction setFullRange() {\n localMin.value = props.dataMin\n localMax.value = props.dataMax\n emitChange()\n}\n\n// Emit change\nfunction emitChange() {\n if (localMin.value === null && localMax.value === null) {\n emit('change', null)\n }\n else {\n emit('change', { min: localMin.value, max: localMax.value })\n }\n}\n\n// Sync with props\nwatch(() => props.currentRange, (newRange) => {\n localMin.value = newRange?.min ?? null\n localMax.value = newRange?.max ?? null\n}, { immediate: true })\n</script>\n\n<template>\n <div class=\"vpg-range-filter\">\n <!-- Data range info -->\n <div class=\"vpg-range-info\">\n <span class=\"vpg-range-label\">Data range:</span>\n <span class=\"vpg-range-bounds\">{{ formatValue(dataMin) }} – {{ formatValue(dataMax) }}</span>\n </div>\n\n <!-- Dual slider track -->\n <div class=\"vpg-slider-container\">\n <div class=\"vpg-slider-track\">\n <div\n class=\"vpg-slider-fill\"\n :style=\"{\n left: `${minPercent}%`,\n right: `${100 - maxPercent}%`,\n }\"\n />\n </div>\n\n <!-- Min slider (lower handle) -->\n <input\n type=\"range\"\n class=\"vpg-slider vpg-slider-min\"\n :min=\"dataMin\"\n :max=\"dataMax\"\n :step=\"step\"\n :value=\"localMin ?? dataMin\"\n @input=\"handleMinSlider\"\n @change=\"emitChange\"\n >\n\n <!-- Max slider (upper handle) -->\n <input\n type=\"range\"\n class=\"vpg-slider vpg-slider-max\"\n :min=\"dataMin\"\n :max=\"dataMax\"\n :step=\"step\"\n :value=\"localMax ?? dataMax\"\n @input=\"handleMaxSlider\"\n @change=\"emitChange\"\n >\n </div>\n\n <!-- Input fields for precise entry -->\n <div class=\"vpg-range-inputs\">\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">Min</label>\n <input\n type=\"number\"\n class=\"vpg-range-input\"\n :placeholder=\"formatValue(dataMin)\"\n :value=\"localMin ?? ''\"\n :step=\"step\"\n @input=\"handleMinInput\"\n @change=\"emitChange\"\n >\n </div>\n <span class=\"vpg-input-separator\">to</span>\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">Max</label>\n <input\n type=\"number\"\n class=\"vpg-range-input\"\n :placeholder=\"formatValue(dataMax)\"\n :value=\"localMax ?? ''\"\n :step=\"step\"\n @input=\"handleMaxInput\"\n @change=\"emitChange\"\n >\n </div>\n </div>\n\n <!-- Quick actions -->\n <div class=\"vpg-range-actions\">\n <button\n class=\"vpg-range-btn\"\n :disabled=\"!isFilterActive\"\n @click=\"clearFilter\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear\n </button>\n <button class=\"vpg-range-btn\" @click=\"setFullRange\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n Full Range\n </button>\n </div>\n\n <!-- Current filter display -->\n <div v-if=\"isFilterActive\" class=\"vpg-filter-summary\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span>\n Showing values\n <strong>{{ localMin !== null ? `≥ ${formatValue(localMin)}` : '' }}</strong>\n {{ localMin !== null && localMax !== null ? ' and ' : '' }}\n <strong>{{ localMax !== null ? `≤ ${formatValue(localMax)}` : '' }}</strong>\n </span>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-range-filter {\n padding: 0.5rem;\n}\n\n.vpg-range-info {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.75rem;\n font-size: 0.6875rem;\n}\n\n.vpg-range-label {\n color: #64748b;\n}\n\n.vpg-range-bounds {\n font-weight: 500;\n color: #334155;\n background: #f1f5f9;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n}\n\n/* Slider container with dual handles */\n.vpg-slider-container {\n position: relative;\n height: 24px;\n margin: 0.75rem 0;\n}\n\n.vpg-slider-track {\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 4px;\n background: #e2e8f0;\n border-radius: 2px;\n transform: translateY(-50%);\n}\n\n.vpg-slider-fill {\n position: absolute;\n top: 0;\n bottom: 0;\n background: linear-gradient(90deg, #6366f1, #8b5cf6);\n border-radius: 2px;\n transition: left 0.1s, right 0.1s;\n}\n\n.vpg-slider {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: transparent;\n pointer-events: none;\n -webkit-appearance: none;\n appearance: none;\n margin: 0;\n}\n\n.vpg-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n pointer-events: auto;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: white;\n border: 2px solid #6366f1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n}\n\n.vpg-slider::-webkit-slider-thumb:hover {\n transform: scale(1.15);\n box-shadow: 0 2px 6px rgba(99, 102, 241, 0.4);\n}\n\n.vpg-slider::-webkit-slider-thumb:active {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.5);\n}\n\n.vpg-slider::-moz-range-thumb {\n pointer-events: auto;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: white;\n border: 2px solid #6366f1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n}\n\n.vpg-slider::-moz-range-thumb:hover {\n transform: scale(1.15);\n}\n\n.vpg-slider-min {\n z-index: 1;\n}\n\n.vpg-slider-max {\n z-index: 2;\n}\n\n/* Input fields */\n.vpg-range-inputs {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n.vpg-input-group {\n flex: 1;\n}\n\n.vpg-input-label {\n display: block;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n margin-bottom: 0.125rem;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.vpg-range-input {\n width: 100%;\n padding: 0.375rem 0.5rem;\n font-size: 0.75rem;\n border: 1px solid #cbd5e1;\n border-radius: 0.25rem;\n outline: none;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.vpg-range-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);\n}\n\n.vpg-range-input::placeholder {\n color: #94a3b8;\n}\n\n/* Hide number input spinners */\n.vpg-range-input::-webkit-outer-spin-button,\n.vpg-range-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n.vpg-range-input[type=\"number\"] {\n -moz-appearance: textfield;\n}\n\n.vpg-input-separator {\n color: #94a3b8;\n font-size: 0.6875rem;\n padding-top: 1rem;\n}\n\n/* Action buttons */\n.vpg-range-actions {\n display: flex;\n gap: 0.375rem;\n margin-bottom: 0.5rem;\n}\n\n.vpg-range-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #475569;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-range-btn:hover:not(:disabled) {\n background: #f1f5f9;\n border-color: #cbd5e1;\n color: #334155;\n}\n\n.vpg-range-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Filter summary */\n.vpg-filter-summary {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.5rem;\n background: #eef2ff;\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n color: #4338ca;\n}\n\n.vpg-filter-summary strong {\n font-weight: 600;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { ColumnStats, DateFormat, DateRange, NumberFormat, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Column Filter Dropdown Component\n * Shows unique values with checkboxes, search, and sort controls\n * For numeric columns, also provides a range filter option\n * For date columns, also provides a date range filter option\n */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport DateRangeFilter from './DateRangeFilter.vue'\nimport NumericRangeFilter from './NumericRangeFilter.vue'\n\ntype FilterMode = 'values' | 'range'\n\nconst props = defineProps<{\n columnId: string\n columnName: string\n stats: ColumnStats\n selectedValues: string[]\n sortDirection: 'asc' | 'desc' | null\n /** Current numeric range filter (if any) */\n numericRange?: NumericRange | null\n /** Current date range filter (if any) */\n dateRange?: DateRange | null\n /** Number display format */\n numberFormat?: NumberFormat\n /** Date display format */\n dateFormat?: DateFormat\n}>()\n\nconst emit = defineEmits<{\n filter: [values: string[]]\n sort: [direction: 'asc' | 'desc' | null]\n close: []\n /** Emitted when a numeric range filter is applied */\n rangeFilter: [range: NumericRange | null]\n /** Emitted when a date range filter is applied */\n dateRangeFilter: [range: DateRange | null]\n}>()\n\n// Local state\nconst searchQuery = ref('')\nconst dropdownRef = ref<HTMLDivElement>()\nconst searchInputRef = ref<HTMLInputElement>()\n\n// Filter mode (values vs range) - only available for numeric/date columns\nconst isNumericColumn = computed(() => props.stats.type === 'number'\n && props.stats.numericMin !== undefined\n && props.stats.numericMax !== undefined)\n\nconst isDateColumn = computed(() => props.stats.type === 'date'\n && props.stats.dateMin !== undefined\n && props.stats.dateMax !== undefined)\n\n// Determine initial mode based on existing filters\nconst filterMode = ref<FilterMode>(props.numericRange || props.dateRange ? 'range' : 'values')\n\n// Local range for the numeric filter\nconst localRange = ref<NumericRange | null>(props.numericRange ?? null)\n\n// Local range for the date filter\nconst localDateRange = ref<DateRange | null>(props.dateRange ?? null)\n\n// Initialize with selected values\nconst localSelected = ref<Set<string>>(new Set(props.selectedValues))\n\n// Include blank option if there are null values\nconst hasBlankValues = computed(() => props.stats.nullCount > 0)\n\n// Filtered unique values based on search\nconst filteredValues = computed(() => {\n const values = props.stats.uniqueValues\n if (!searchQuery.value)\n return values\n\n const query = searchQuery.value.toLowerCase()\n return values.filter(v => v.toLowerCase().includes(query))\n})\n\n// All values including blank\nconst allValues = computed(() => {\n const values = [...filteredValues.value]\n if (hasBlankValues.value && (!searchQuery.value || '(blank)'.includes(searchQuery.value.toLowerCase()))) {\n values.unshift('(blank)')\n }\n return values\n})\n\n// Sort label helpers\nconst ascLabel = computed(() => {\n if (isDateColumn.value)\n return 'Old\\u2192New'\n if (isNumericColumn.value)\n return '1\\u21929'\n return 'A\\u2192Z'\n})\n\nconst descLabel = computed(() => {\n if (isDateColumn.value)\n return 'New\\u2192Old'\n if (isNumericColumn.value)\n return '9\\u21921'\n return 'Z\\u2192A'\n})\n\nconst ascTitle = computed(() => {\n if (isDateColumn.value)\n return 'Sort Old to New'\n if (isNumericColumn.value)\n return 'Sort Low to High'\n return 'Sort A to Z'\n})\n\nconst descTitle = computed(() => {\n if (isDateColumn.value)\n return 'Sort New to Old'\n if (isNumericColumn.value)\n return 'Sort High to Low'\n return 'Sort Z to A'\n})\n\n// Toggle single value\nfunction toggleValue(value: string) {\n if (localSelected.value.has(value)) {\n localSelected.value.delete(value)\n }\n else {\n localSelected.value.add(value)\n }\n localSelected.value = new Set(localSelected.value)\n}\n\n// Select all visible\nfunction selectAll() {\n for (const value of allValues.value) {\n localSelected.value.add(value)\n }\n localSelected.value = new Set(localSelected.value)\n}\n\n// Clear all\nfunction clearAll() {\n localSelected.value.clear()\n localSelected.value = new Set(localSelected.value)\n}\n\n// Apply filter\nfunction applyFilter() {\n if (localSelected.value.size === 0) {\n emit('filter', [])\n }\n else {\n emit('filter', Array.from(localSelected.value))\n }\n emit('close')\n}\n\n// Sort handlers\nfunction sortAscending() {\n emit('sort', props.sortDirection === 'asc' ? null : 'asc')\n}\n\nfunction sortDescending() {\n emit('sort', props.sortDirection === 'desc' ? null : 'desc')\n}\n\n// Clear filter only\nfunction clearFilter() {\n localSelected.value.clear()\n localSelected.value = new Set(localSelected.value)\n emit('filter', [])\n emit('close')\n}\n\n// Handle range filter change from the NumericRangeFilter component\nfunction handleRangeChange(range: NumericRange | null) {\n localRange.value = range\n}\n\n// Apply the range filter\nfunction applyRangeFilter() {\n emit('rangeFilter', localRange.value)\n emit('close')\n}\n\n// Clear range filter\nfunction clearRangeFilter() {\n localRange.value = null\n emit('rangeFilter', null)\n emit('close')\n}\n\n// Handle date range filter change from the DateRangeFilter component\nfunction handleDateRangeChange(range: DateRange | null) {\n localDateRange.value = range\n}\n\n// Apply the date range filter\nfunction applyDateRangeFilter() {\n emit('dateRangeFilter', localDateRange.value)\n emit('close')\n}\n\n// Clear date range filter\nfunction clearDateRangeFilter() {\n localDateRange.value = null\n emit('dateRangeFilter', null)\n emit('close')\n}\n\n// Switch filter mode\nfunction setFilterMode(mode: FilterMode) {\n filterMode.value = mode\n}\n\n// Click outside handler\nfunction handleClickOutside(event: MouseEvent) {\n if (dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {\n emit('close')\n }\n}\n\n// Keyboard handling\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n emit('close')\n }\n else if (event.key === 'Enter' && event.ctrlKey) {\n applyFilter()\n }\n}\n\n// Focus search on mount\nonMounted(() => {\n nextTick(() => {\n searchInputRef.value?.focus()\n })\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeydown)\n})\n\n// Sync with props\nwatch(() => props.selectedValues, (newValues) => {\n localSelected.value = new Set(newValues)\n}, { immediate: true })\n\n// Sync numeric range with props\nwatch(() => props.numericRange, (newRange) => {\n localRange.value = newRange ?? null\n if (newRange) {\n filterMode.value = 'range'\n }\n}, { immediate: true })\n\n// Sync date range with props\nwatch(() => props.dateRange, (newRange) => {\n localDateRange.value = newRange ?? null\n if (newRange) {\n filterMode.value = 'range'\n }\n}, { immediate: true })\n</script>\n\n<template>\n <div ref=\"dropdownRef\" class=\"vpg-filter-dropdown\">\n <!-- Header -->\n <div class=\"vpg-filter-header\">\n <span class=\"vpg-filter-title\">{{ columnName }}</span>\n <span class=\"vpg-filter-count\">\n {{ stats.uniqueValues.length.toLocaleString() }} unique\n </span>\n </div>\n\n <!-- Sort Controls -->\n <div class=\"vpg-sort-controls\">\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'asc' }\"\n :title=\"ascTitle\"\n @click=\"sortAscending\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12\" />\n </svg>\n <span>{{ ascLabel }}</span>\n </button>\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'desc' }\"\n :title=\"descTitle\"\n @click=\"sortDescending\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4\" />\n </svg>\n <span>{{ descLabel }}</span>\n </button>\n </div>\n\n <div class=\"vpg-divider\" />\n\n <!-- Filter Mode Tabs (for numeric or date columns) -->\n <div v-if=\"isNumericColumn || isDateColumn\" class=\"vpg-filter-tabs\">\n <button\n class=\"vpg-tab-btn\"\n :class=\"{ active: filterMode === 'values' }\"\n @click=\"setFilterMode('values')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\" />\n </svg>\n Values\n </button>\n <button\n class=\"vpg-tab-btn\"\n :class=\"{ active: filterMode === 'range' }\"\n @click=\"setFilterMode('range')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01\" />\n </svg>\n Range\n </button>\n </div>\n\n <!-- Values Filter Mode -->\n <template v-if=\"(!isNumericColumn && !isDateColumn) || filterMode === 'values'\">\n <!-- Search -->\n <div class=\"vpg-search-container\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n ref=\"searchInputRef\"\n v-model=\"searchQuery\"\n type=\"text\"\n placeholder=\"Search values...\"\n class=\"vpg-search-input\"\n >\n <button v-if=\"searchQuery\" class=\"vpg-clear-search\" @click=\"searchQuery = ''\">\n ×\n </button>\n </div>\n\n <!-- Select All / Clear All -->\n <div class=\"vpg-bulk-actions\">\n <button class=\"vpg-bulk-btn\" @click=\"selectAll\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Select All\n </button>\n <button class=\"vpg-bulk-btn\" @click=\"clearAll\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear All\n </button>\n </div>\n\n <!-- Values List -->\n <div class=\"vpg-values-list\">\n <label\n v-for=\"value in allValues\"\n :key=\"value\"\n class=\"vpg-value-item\"\n :class=\"{ selected: localSelected.has(value) }\"\n >\n <input\n type=\"checkbox\"\n :checked=\"localSelected.has(value)\"\n class=\"vpg-value-checkbox\"\n @change=\"toggleValue(value)\"\n >\n <span class=\"vpg-value-text\" :class=\"{ 'vpg-blank': value === '(blank)' }\">\n {{ value }}\n </span>\n </label>\n\n <div v-if=\"allValues.length === 0\" class=\"vpg-no-results\">\n No matching values\n </div>\n </div>\n\n <!-- Footer for Values Mode -->\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyFilter\">\n Apply\n </button>\n </div>\n </template>\n\n <!-- Numeric Range Filter Mode -->\n <template v-else-if=\"isNumericColumn && filterMode === 'range'\">\n <NumericRangeFilter\n :data-min=\"stats.numericMin!\"\n :data-max=\"stats.numericMax!\"\n :current-range=\"localRange\"\n :number-format=\"numberFormat\"\n @change=\"handleRangeChange\"\n />\n\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearRangeFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyRangeFilter\">\n Apply\n </button>\n </div>\n </template>\n\n <!-- Date Range Filter Mode -->\n <template v-else-if=\"isDateColumn && filterMode === 'range'\">\n <DateRangeFilter\n :data-min=\"stats.dateMin!\"\n :data-max=\"stats.dateMax!\"\n :current-range=\"localDateRange\"\n :date-format=\"dateFormat\"\n @change=\"handleDateRangeChange\"\n />\n\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearDateRangeFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyDateRangeFilter\">\n Apply\n </button>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.vpg-filter-dropdown {\n position: absolute;\n z-index: 50;\n background: white;\n border-radius: 0.375rem;\n box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n border: 1px solid #e2e8f0;\n min-width: 220px;\n max-width: 280px;\n top: 100%;\n left: 0;\n margin-top: 2px;\n max-height: calc(100vh - 100px);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-filter-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.625rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n border-radius: 0.375rem 0.375rem 0 0;\n}\n\n.vpg-filter-title {\n font-size: 0.75rem;\n font-weight: 600;\n color: #1e293b;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vpg-filter-count {\n font-size: 0.625rem;\n color: #64748b;\n}\n\n.vpg-sort-controls {\n display: flex;\n gap: 0.25rem;\n padding: 0.5rem;\n background: #f8fafc;\n}\n\n.vpg-sort-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n border-radius: 0.25rem;\n color: #475569;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-sort-btn:hover {\n background: #e2e8f0;\n}\n\n.vpg-sort-btn.active {\n background: #e0e7ff;\n color: #4338ca;\n}\n\n.vpg-icon-sm {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-divider {\n height: 1px;\n background: #e2e8f0;\n}\n\n/* Filter mode tabs */\n.vpg-filter-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.375rem 0.5rem;\n background: #f8fafc;\n}\n\n.vpg-tab-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n padding: 0.375rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-tab-btn:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-tab-btn.active {\n background: #4f46e5;\n color: white;\n border-color: #4f46e5;\n}\n\n.vpg-tab-btn.active:hover {\n background: #4338ca;\n}\n\n.vpg-search-container {\n position: relative;\n padding: 0.375rem 0.5rem;\n}\n\n.vpg-search-icon {\n position: absolute;\n left: 0.875rem;\n top: 50%;\n transform: translateY(-50%);\n width: 0.875rem;\n height: 0.875rem;\n color: #94a3b8;\n}\n\n.vpg-search-input {\n width: 100%;\n padding: 0.25rem 1.5rem 0.25rem 1.75rem;\n font-size: 0.75rem;\n border: 1px solid #cbd5e1;\n border-radius: 0.25rem;\n outline: none;\n}\n\n.vpg-search-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 1px #6366f1;\n}\n\n.vpg-clear-search {\n position: absolute;\n right: 0.875rem;\n top: 50%;\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n font-size: 0.875rem;\n line-height: 1;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.vpg-clear-search:hover {\n color: #475569;\n}\n\n.vpg-bulk-actions {\n display: flex;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n border-bottom: 1px solid #f1f5f9;\n}\n\n.vpg-bulk-btn {\n display: flex;\n align-items: center;\n gap: 0.125rem;\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-bulk-btn:hover {\n color: #4f46e5;\n background: #eef2ff;\n}\n\n.vpg-values-list {\n max-height: 200px;\n overflow-y: auto;\n padding: 0.125rem 0.25rem;\n flex: 1;\n min-height: 0;\n}\n\n.vpg-value-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.375rem;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: background 0.15s;\n}\n\n.vpg-value-item:hover {\n background: #f1f5f9;\n}\n\n.vpg-value-item.selected {\n background: #eef2ff;\n}\n\n.vpg-value-checkbox {\n width: 0.875rem;\n height: 0.875rem;\n accent-color: #4f46e5;\n border-radius: 0.25rem;\n}\n\n.vpg-value-text {\n font-size: 0.75rem;\n color: #334155;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.vpg-value-text.vpg-blank {\n font-style: italic;\n color: #94a3b8;\n}\n\n.vpg-no-results {\n text-align: center;\n padding: 0.75rem;\n font-size: 0.75rem;\n color: #94a3b8;\n}\n\n.vpg-filter-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5rem 0.625rem;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n border-radius: 0 0 0.375rem 0.375rem;\n}\n\n.vpg-btn-clear {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-btn-clear:hover {\n background: #e2e8f0;\n color: #1e293b;\n}\n\n.vpg-btn-apply {\n padding: 0.25rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: white;\n background: #4f46e5;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-btn-apply:hover {\n background: #4338ca;\n}\n</style>\n","import type { ColumnFilterValue, ColumnStats, DateRange, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Excel-like Grid Composable for Vue\n * Provides Excel-like filtering, sorting, and data manipulation functionality\n */\nimport type { ColumnDef, ColumnFiltersState, FilterFn, SortingState, VisibilityState } from '@tanstack/vue-table'\nimport { formatCellValue, getColumnUniqueValues, isDateRange, isNumericRange } from '@smallwebco/tinypivot-core'\nimport {\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useVueTable,\n} from '@tanstack/vue-table'\nimport { computed, type Ref, ref, watch } from 'vue'\n\n// Re-export for convenience\nexport { formatCellValue, getColumnUniqueValues, isDateRange, isNumericRange }\n\nexport interface ExcelGridOptions<T> {\n data: Ref<T[]>\n columns?: string[]\n enableSorting?: boolean\n enableFiltering?: boolean\n pageSize?: number\n}\n\n/**\n * Combined filter function for Excel-style filtering, numeric range, and date range filtering\n */\n\nconst multiSelectFilter: FilterFn<any> = (row, columnId, filterValue: ColumnFilterValue | undefined) => {\n if (!filterValue)\n return true\n\n // Handle numeric range filter\n if (isNumericRange(filterValue)) {\n const cellValue = row.getValue(columnId)\n if (cellValue === null || cellValue === undefined || cellValue === '') {\n return false // Exclude null/empty values from numeric range filtering\n }\n const num = typeof cellValue === 'number' ? cellValue : Number.parseFloat(String(cellValue))\n if (Number.isNaN(num))\n return false\n\n const { min, max } = filterValue\n if (min !== null && num < min)\n return false\n if (max !== null && num > max)\n return false\n return true\n }\n\n // Handle date range filter\n if (isDateRange(filterValue)) {\n const cellValue = row.getValue(columnId)\n if (cellValue === null || cellValue === undefined || cellValue === '') {\n return false\n }\n const dateObj = cellValue instanceof Date ? cellValue : new Date(String(cellValue))\n if (Number.isNaN(dateObj.getTime()))\n return false\n const dateStr = dateObj.toISOString().split('T')[0]\n\n const { min, max } = filterValue\n if (min !== null && dateStr < min)\n return false\n if (max !== null && dateStr > max)\n return false\n return true\n }\n\n // Handle multi-select array filter\n if (Array.isArray(filterValue) && filterValue.length > 0) {\n const cellValue = row.getValue(columnId)\n const cellString = cellValue === null || cellValue === undefined || cellValue === ''\n ? '(blank)'\n : String(cellValue)\n return filterValue.includes(cellString)\n }\n\n return true\n}\n\n/**\n * Create Excel-like grid composable\n */\nexport function useExcelGrid<T extends Record<string, unknown>>(options: ExcelGridOptions<T>) {\n const { data, enableSorting = true, enableFiltering = true } = options\n\n // State\n const sorting = ref<SortingState>([])\n const columnFilters = ref<ColumnFiltersState>([])\n const columnVisibility = ref<VisibilityState>({})\n const globalFilter = ref('')\n\n // Column statistics cache\n const columnStatsCache = ref<Record<string, ColumnStats>>({})\n\n // Compute columns from data\n const columnKeys = computed(() => {\n if (data.value.length === 0)\n return []\n return Object.keys(data.value[0] as Record<string, unknown>)\n })\n\n // Get column stats (memoized)\n function getColumnStats(columnKey: string): ColumnStats {\n const cacheKey = `${columnKey}-${data.value.length}`\n if (!columnStatsCache.value[cacheKey]) {\n columnStatsCache.value[cacheKey] = getColumnUniqueValues(data.value, columnKey)\n }\n return columnStatsCache.value[cacheKey]\n }\n\n // Clear stats cache when data changes\n function clearStatsCache() {\n columnStatsCache.value = {}\n }\n\n // Create column definitions dynamically\n const columnDefs = computed<ColumnDef<T, unknown>[]>(() => {\n return columnKeys.value.map((key) => {\n const stats = getColumnStats(key)\n\n return {\n id: key,\n accessorKey: key,\n header: key,\n\n cell: (info: any) => formatCellValue(info.getValue(), stats.type),\n filterFn: multiSelectFilter,\n meta: {\n type: stats.type,\n uniqueCount: stats.uniqueValues.length,\n },\n } as ColumnDef<T, unknown>\n })\n })\n\n // Create table instance\n const table = useVueTable({\n get data() { return data.value },\n get columns() { return columnDefs.value },\n state: {\n get sorting() { return sorting.value },\n get columnFilters() { return columnFilters.value },\n get columnVisibility() { return columnVisibility.value },\n get globalFilter() { return globalFilter.value },\n },\n onSortingChange: (updater) => {\n sorting.value = typeof updater === 'function' ? updater(sorting.value) : updater\n },\n onColumnFiltersChange: (updater) => {\n columnFilters.value = typeof updater === 'function' ? updater(columnFilters.value) : updater\n },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: enableSorting ? getSortedRowModel() : undefined,\n getFilteredRowModel: enableFiltering ? getFilteredRowModel() : undefined,\n filterFns: {\n multiSelect: multiSelectFilter,\n },\n enableSorting,\n enableFilters: enableFiltering,\n })\n\n // Computed properties\n const filteredRowCount = computed(() => table.getFilteredRowModel().rows.length)\n const totalRowCount = computed(() => data.value.length)\n\n // Active filters (handles array values, numeric ranges, and date ranges)\n const activeFilters = computed(() => {\n return columnFilters.value.map((f) => {\n const filterValue = f.value as ColumnFilterValue | undefined\n\n // Handle numeric range\n if (filterValue && isNumericRange(filterValue)) {\n return {\n column: f.id,\n type: 'range' as const,\n range: filterValue,\n dateRange: null as DateRange | null,\n values: [] as string[],\n }\n }\n\n // Handle date range\n if (filterValue && isDateRange(filterValue)) {\n return {\n column: f.id,\n type: 'dateRange' as const,\n range: null as NumericRange | null,\n dateRange: filterValue,\n values: [] as string[],\n }\n }\n\n // Handle value array\n return {\n column: f.id,\n type: 'values' as const,\n values: Array.isArray(filterValue) ? filterValue : [],\n range: null as NumericRange | null,\n dateRange: null as DateRange | null,\n }\n })\n })\n\n // Check if column has active filter (handles array, numeric range, and date range)\n function hasActiveFilter(columnId: string): boolean {\n const column = table.getColumn(columnId)\n if (!column)\n return false\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (!filterValue)\n return false\n\n // Check for numeric range\n if (isNumericRange(filterValue)) {\n return filterValue.min !== null || filterValue.max !== null\n }\n\n // Check for date range\n if (isDateRange(filterValue)) {\n return filterValue.min !== null || filterValue.max !== null\n }\n\n // Check for value array\n return Array.isArray(filterValue) && filterValue.length > 0\n }\n\n // Set column filter (value-based)\n function setColumnFilter(columnId: string, values: string[]) {\n const column = table.getColumn(columnId)\n if (column) {\n column.setFilterValue(values.length === 0 ? undefined : values)\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Set numeric range filter\n function setNumericRangeFilter(columnId: string, range: NumericRange | null) {\n const column = table.getColumn(columnId)\n if (column) {\n if (!range || (range.min === null && range.max === null)) {\n column.setFilterValue(undefined)\n }\n else {\n column.setFilterValue(range)\n }\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Get numeric range filter for a column\n function getNumericRangeFilter(columnId: string): NumericRange | null {\n const column = table.getColumn(columnId)\n if (!column)\n return null\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (filterValue && isNumericRange(filterValue)) {\n return filterValue\n }\n return null\n }\n\n // Set date range filter\n function setDateRangeFilter(columnId: string, range: DateRange | null) {\n const column = table.getColumn(columnId)\n if (column) {\n if (!range || (range.min === null && range.max === null)) {\n column.setFilterValue(undefined)\n }\n else {\n column.setFilterValue(range)\n }\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Get date range filter for a column\n function getDateRangeFilter(columnId: string): DateRange | null {\n const column = table.getColumn(columnId)\n if (!column)\n return null\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (filterValue && isDateRange(filterValue)) {\n return filterValue\n }\n return null\n }\n\n // Clear all filters\n function clearAllFilters() {\n table.resetColumnFilters()\n globalFilter.value = ''\n // Force sync columnFilters ref with table state\n columnFilters.value = []\n }\n\n // Get filter values for a specific column\n function getColumnFilterValues(columnId: string): string[] {\n const column = table.getColumn(columnId)\n if (!column)\n return []\n const filterValue = column.getFilterValue()\n return Array.isArray(filterValue) ? filterValue : []\n }\n\n // Toggle column sort\n function toggleSort(columnId: string) {\n const current = sorting.value.find(s => s.id === columnId)\n if (!current) {\n sorting.value = [{ id: columnId, desc: false }]\n }\n else if (!current.desc) {\n sorting.value = [{ id: columnId, desc: true }]\n }\n else {\n sorting.value = []\n }\n }\n\n // Get sort direction for column\n function getSortDirection(columnId: string): 'asc' | 'desc' | null {\n const sort = sorting.value.find(s => s.id === columnId)\n if (!sort)\n return null\n return sort.desc ? 'desc' : 'asc'\n }\n\n // Watch data changes to clear cache\n watch(data, () => {\n clearStatsCache()\n })\n\n return {\n // Table instance\n table,\n\n // State\n sorting,\n columnFilters,\n columnVisibility,\n globalFilter,\n columnKeys,\n\n // Computed\n filteredRowCount,\n totalRowCount,\n activeFilters,\n\n // Methods\n getColumnStats,\n clearStatsCache,\n hasActiveFilter,\n setColumnFilter,\n getColumnFilterValues,\n clearAllFilters,\n toggleSort,\n getSortDirection,\n // Numeric range filters\n setNumericRangeFilter,\n getNumericRangeFilter,\n // Date range filters\n setDateRangeFilter,\n getDateRangeFilter,\n }\n}\n","import type { ExportOptions, PaginationOptions, PivotExportData, PivotValueField, SelectionBounds } from '@smallwebco/tinypivot-core'\nimport {\n copyToClipboard as coreCopyToClipboard,\n exportPivotToCSV as coreExportPivotToCSV,\n exportToCSV as coreExportToCSV,\n formatSelectionForClipboard as coreFormatSelection,\n} from '@smallwebco/tinypivot-core'\n/**\n * Grid Features Composable for Vue\n * Provides CSV export, clipboard, pagination, and other utility features\n */\nimport { computed, ref, type Ref } from 'vue'\n\n// Re-export core functions\nexport {\n copyToClipboard,\n exportPivotToCSV,\n exportToCSV,\n formatSelectionForClipboard,\n}\n\n/**\n * CSV Export functionality wrapper\n */\nfunction exportToCSV<T extends Record<string, unknown>>(\n data: T[],\n columns: string[],\n options?: ExportOptions,\n): void {\n coreExportToCSV(data, columns, options)\n}\n\n/**\n * Pivot CSV export wrapper\n */\nfunction exportPivotToCSV(\n pivotData: PivotExportData,\n rowFields: string[],\n columnFields: string[],\n valueFields: PivotValueField[],\n options?: ExportOptions,\n): void {\n coreExportPivotToCSV(pivotData, rowFields, columnFields, valueFields, options)\n}\n\n/**\n * Copy to clipboard wrapper\n */\nfunction copyToClipboard(\n text: string,\n onSuccess?: () => void,\n onError?: (err: Error) => void,\n): void {\n coreCopyToClipboard(text, onSuccess, onError)\n}\n\n/**\n * Format selection for clipboard wrapper\n */\nfunction formatSelectionForClipboard<T extends Record<string, unknown>>(\n rows: T[],\n columns: string[],\n selectionBounds: SelectionBounds,\n): string {\n return coreFormatSelection(rows, columns, selectionBounds)\n}\n\n/**\n * Pagination composable\n */\nexport function usePagination<T>(data: Ref<T[]>, options: PaginationOptions = {}) {\n const pageSize = ref(options.pageSize ?? 50)\n const currentPage = ref(options.currentPage ?? 1)\n\n const totalPages = computed(() =>\n Math.max(1, Math.ceil(data.value.length / pageSize.value)),\n )\n\n const paginatedData = computed(() => {\n const start = (currentPage.value - 1) * pageSize.value\n const end = start + pageSize.value\n return data.value.slice(start, end)\n })\n\n const startIndex = computed(() => (currentPage.value - 1) * pageSize.value + 1)\n const endIndex = computed(() =>\n Math.min(currentPage.value * pageSize.value, data.value.length),\n )\n\n function goToPage(page: number) {\n currentPage.value = Math.max(1, Math.min(page, totalPages.value))\n }\n\n function nextPage() {\n if (currentPage.value < totalPages.value) {\n currentPage.value++\n }\n }\n\n function prevPage() {\n if (currentPage.value > 1) {\n currentPage.value--\n }\n }\n\n function firstPage() {\n currentPage.value = 1\n }\n\n function lastPage() {\n currentPage.value = totalPages.value\n }\n\n function setPageSize(size: number) {\n pageSize.value = size\n currentPage.value = 1\n }\n\n return {\n pageSize,\n currentPage,\n totalPages,\n paginatedData,\n startIndex,\n endIndex,\n goToPage,\n nextPage,\n prevPage,\n firstPage,\n lastPage,\n setPageSize,\n }\n}\n\n/**\n * Global search/filter composable\n */\nexport function useGlobalSearch<T extends Record<string, unknown>>(\n data: Ref<T[]>,\n columns: Ref<string[]>,\n) {\n const searchTerm = ref('')\n const caseSensitive = ref(false)\n\n const filteredData = computed(() => {\n if (!searchTerm.value.trim()) {\n return data.value\n }\n\n const term = caseSensitive.value\n ? searchTerm.value.trim()\n : searchTerm.value.trim().toLowerCase()\n\n return data.value.filter((row) => {\n for (const col of columns.value) {\n const value = row[col]\n if (value === null || value === undefined)\n continue\n\n const strValue = caseSensitive.value ? String(value) : String(value).toLowerCase()\n\n if (strValue.includes(term)) {\n return true\n }\n }\n return false\n })\n })\n\n function clearSearch() {\n searchTerm.value = ''\n }\n\n return {\n searchTerm,\n caseSensitive,\n filteredData,\n clearSearch,\n }\n}\n\n/**\n * Row selection composable\n */\nexport function useRowSelection<T>(data: Ref<T[]>) {\n const selectedRowIndices = ref<Set<number>>(new Set())\n\n const selectedRows = computed(() => {\n return Array.from(selectedRowIndices.value)\n .sort((a, b) => a - b)\n .map(idx => data.value[idx])\n .filter(Boolean)\n })\n\n const allSelected = computed(() => {\n return data.value.length > 0 && selectedRowIndices.value.size === data.value.length\n })\n\n const someSelected = computed(() => {\n return selectedRowIndices.value.size > 0 && selectedRowIndices.value.size < data.value.length\n })\n\n function toggleRow(index: number) {\n if (selectedRowIndices.value.has(index)) {\n selectedRowIndices.value.delete(index)\n }\n else {\n selectedRowIndices.value.add(index)\n }\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function selectRow(index: number) {\n selectedRowIndices.value.add(index)\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function deselectRow(index: number) {\n selectedRowIndices.value.delete(index)\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function selectAll() {\n selectedRowIndices.value = new Set(data.value.map((_, idx) => idx))\n }\n\n function deselectAll() {\n selectedRowIndices.value = new Set()\n }\n\n function toggleAll() {\n if (allSelected.value) {\n deselectAll()\n }\n else {\n selectAll()\n }\n }\n\n function isSelected(index: number): boolean {\n return selectedRowIndices.value.has(index)\n }\n\n function selectRange(startIndex: number, endIndex: number) {\n const min = Math.min(startIndex, endIndex)\n const max = Math.max(startIndex, endIndex)\n for (let i = min; i <= max; i++) {\n selectedRowIndices.value.add(i)\n }\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n return {\n selectedRowIndices,\n selectedRows,\n allSelected,\n someSelected,\n toggleRow,\n selectRow,\n deselectRow,\n selectAll,\n deselectAll,\n toggleAll,\n isSelected,\n selectRange,\n }\n}\n\n/**\n * Column resizing composable\n */\nexport function useColumnResize(\n initialWidths: Ref<Record<string, number>>,\n minWidth = 60,\n maxWidth = 600,\n) {\n const columnWidths = ref<Record<string, number>>({ ...initialWidths.value })\n const isResizing = ref(false)\n const resizingColumn = ref<string | null>(null)\n\n function startResize(columnId: string, event: MouseEvent) {\n isResizing.value = true\n resizingColumn.value = columnId\n const startX = event.clientX\n const startWidth = columnWidths.value[columnId] || 150\n\n const handleMouseMove = (e: MouseEvent) => {\n const diff = e.clientX - startX\n const newWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + diff))\n columnWidths.value = {\n ...columnWidths.value,\n [columnId]: newWidth,\n }\n }\n\n const handleMouseUp = () => {\n isResizing.value = false\n resizingColumn.value = null\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }\n\n function resetColumnWidth(columnId: string) {\n if (initialWidths.value[columnId]) {\n columnWidths.value = {\n ...columnWidths.value,\n [columnId]: initialWidths.value[columnId],\n }\n }\n }\n\n function resetAllWidths() {\n columnWidths.value = { ...initialWidths.value }\n }\n\n return {\n columnWidths,\n isResizing,\n resizingColumn,\n startResize,\n resetColumnWidth,\n resetAllWidths,\n }\n}\n","import type { LicenseInfo } from '@smallwebco/tinypivot-core'\nimport {\n canUseAIAnalyst as coreCanUseAIAnalyst,\n canUseCharts as coreCanUseCharts,\n canUsePivot as coreCanUsePivot,\n configureLicenseSecret as coreConfigureLicenseSecret,\n isPro as coreIsPro,\n shouldShowWatermark as coreShouldShowWatermark,\n getDemoLicenseInfo,\n getFreeLicenseInfo,\n logProRequired,\n validateLicenseKey,\n} from '@smallwebco/tinypivot-core'\n/**\n * License Management Composable for Vue\n * Wraps core license logic with Vue reactivity\n */\nimport { computed, ref } from 'vue'\n\n// License state\nconst licenseKey = ref<string | null>(null)\nconst demoMode = ref(false)\nconst licenseInfo = ref<LicenseInfo>(getFreeLicenseInfo())\n\n// Cached validation result\nlet validationPromise: Promise<LicenseInfo> | null = null\n\n/**\n * Set the license key for the library\n * Returns a promise that resolves when validation is complete\n */\nexport async function setLicenseKey(key: string): Promise<void> {\n licenseKey.value = key\n\n // Start validation\n validationPromise = validateLicenseKey(key)\n licenseInfo.value = await validationPromise\n validationPromise = null\n\n if (!licenseInfo.value.isValid) {\n console.warn('[TinyPivot] License validation failed. Check the console for environment details. Running in free mode.')\n }\n else if (licenseInfo.value.type !== 'free') {\n console.info(`[TinyPivot] Pro license activated (${licenseInfo.value.type})`)\n }\n}\n\n/**\n * Enable demo mode - unlocks all features for evaluation\n * Requires the correct demo secret\n * Shows \"Demo Mode\" watermark\n */\nexport async function enableDemoMode(secret: string): Promise<boolean> {\n const demoLicense = await getDemoLicenseInfo(secret)\n if (!demoLicense) {\n console.warn('[TinyPivot] Demo mode activation failed - invalid secret')\n return false\n }\n demoMode.value = true\n licenseInfo.value = demoLicense\n console.info('[TinyPivot] Demo mode enabled - all Pro features unlocked for evaluation')\n return true\n}\n\n/**\n * Configure the license secret\n */\nexport function configureLicenseSecret(secret: string): void {\n coreConfigureLicenseSecret(secret)\n}\n\n/**\n * Composable for accessing license information\n */\nexport function useLicense() {\n const isDemo = computed(() => demoMode.value)\n\n const isPro = computed(() => demoMode.value || coreIsPro(licenseInfo.value))\n\n const canUsePivot = computed(() => demoMode.value || coreCanUsePivot(licenseInfo.value))\n\n const canUseAdvancedAggregations = computed(\n () => demoMode.value || licenseInfo.value.features.advancedAggregations,\n )\n\n const canUsePercentageMode = computed(\n () => demoMode.value || licenseInfo.value.features.percentageMode,\n )\n\n const canUseCharts = computed(() => demoMode.value || coreCanUseCharts(licenseInfo.value))\n\n const canUseAIAnalyst = computed(() => demoMode.value || coreCanUseAIAnalyst(licenseInfo.value))\n\n const showWatermark = computed(() => coreShouldShowWatermark(licenseInfo.value, demoMode.value))\n\n function requirePro(feature: string): boolean {\n if (!isPro.value) {\n logProRequired(feature)\n return false\n }\n return true\n }\n\n return {\n licenseInfo: computed(() => licenseInfo.value),\n isDemo,\n isPro,\n canUsePivot,\n canUseAdvancedAggregations,\n canUsePercentageMode,\n canUseCharts,\n canUseAIAnalyst,\n showWatermark,\n requirePro,\n }\n}\n","import type { AggregationFunction, CalculatedField, FieldStats, PivotConfig, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n computeAvailableFields,\n computePivotResult,\n generateStorageKey,\n getAggregationLabel,\n getUnassignedFields,\n isConfigValidForFields,\n isPivotConfigured,\n loadCalculatedFields,\n loadPivotConfig,\n saveCalculatedFields,\n savePivotConfig,\n} from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Composable for Vue\n * Wraps core pivot logic with Vue reactivity\n */\nimport { computed, type Ref, ref, watch } from 'vue'\nimport { useLicense } from './useLicense'\n\n// Re-export for convenience\nexport { getAggregationLabel }\n\n/**\n * Main pivot table composable\n */\nexport function usePivotTable(data: Ref<Record<string, unknown>[]>) {\n const { canUsePivot, requirePro } = useLicense()\n\n // Configuration state\n const rowFields = ref<string[]>([])\n const columnFields = ref<string[]>([])\n const valueFields = ref<PivotValueField[]>([])\n const showRowTotals = ref(true)\n const showColumnTotals = ref(true)\n const calculatedFields = ref<CalculatedField[]>(loadCalculatedFields())\n\n // Track current storage key\n const currentStorageKey = ref<string | null>(null)\n\n // Compute available fields from data\n const availableFields = computed((): FieldStats[] => {\n return computeAvailableFields(data.value)\n })\n\n // Get fields that haven't been assigned yet\n const unassignedFields = computed(() => {\n return getUnassignedFields(\n availableFields.value,\n rowFields.value,\n columnFields.value,\n valueFields.value,\n )\n })\n\n // Check if pivot is configured\n const isConfigured = computed(() => {\n return isPivotConfigured({\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n })\n })\n\n // Build pivot result\n const pivotResult = computed(() => {\n if (!isConfigured.value)\n return null\n\n // Check license for pivot feature\n if (!canUsePivot.value)\n return null\n\n return computePivotResult(data.value, {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n calculatedFields: calculatedFields.value,\n })\n })\n\n // Actions - pivot is free with sum aggregation, Pro required for other aggregations\n function addRowField(field: string) {\n if (!rowFields.value.includes(field)) {\n rowFields.value = [...rowFields.value, field]\n }\n }\n\n function removeRowField(field: string) {\n rowFields.value = rowFields.value.filter(f => f !== field)\n }\n\n function addColumnField(field: string) {\n if (!columnFields.value.includes(field)) {\n columnFields.value = [...columnFields.value, field]\n }\n }\n\n function removeColumnField(field: string) {\n columnFields.value = columnFields.value.filter(f => f !== field)\n }\n\n function addValueField(field: string, aggregation: AggregationFunction = 'sum') {\n // Pro required for non-sum aggregations\n if (aggregation !== 'sum' && !requirePro(`${aggregation} aggregation`)) {\n return\n }\n if (valueFields.value.some(v => v.field === field && v.aggregation === aggregation)) {\n return\n }\n valueFields.value = [...valueFields.value, { field, aggregation }]\n }\n\n function removeValueField(field: string, aggregation?: AggregationFunction) {\n if (aggregation) {\n valueFields.value = valueFields.value.filter(\n v => !(v.field === field && v.aggregation === aggregation),\n )\n }\n else {\n valueFields.value = valueFields.value.filter(v => v.field !== field)\n }\n }\n\n function updateValueFieldAggregation(\n field: string,\n oldAgg: AggregationFunction,\n newAgg: AggregationFunction,\n ) {\n valueFields.value = valueFields.value.map((v) => {\n if (v.field === field && v.aggregation === oldAgg) {\n return { ...v, aggregation: newAgg }\n }\n return v\n })\n }\n\n function clearConfig() {\n rowFields.value = []\n columnFields.value = []\n valueFields.value = []\n }\n\n function moveField(\n from: { area: 'row' | 'column' | 'value', index: number },\n to: { area: 'row' | 'column' | 'value', index: number },\n ) {\n if (from.area === to.area) {\n if (from.area === 'row') {\n const items = [...rowFields.value]\n const [removed] = items.splice(from.index, 1)\n items.splice(to.index, 0, removed)\n rowFields.value = items\n }\n else if (from.area === 'column') {\n const items = [...columnFields.value]\n const [removed] = items.splice(from.index, 1)\n items.splice(to.index, 0, removed)\n columnFields.value = items\n }\n }\n }\n\n function autoSuggestConfig() {\n if (!requirePro('Pivot Table - Auto Suggest'))\n return\n if (availableFields.value.length === 0)\n return\n\n const categoricalFields = availableFields.value.filter(f => !f.isNumeric && f.uniqueCount < 50)\n const numericFields = availableFields.value.filter(f => f.isNumeric)\n\n if (categoricalFields.length > 0 && numericFields.length > 0) {\n rowFields.value = [categoricalFields[0].field]\n valueFields.value = [{ field: numericFields[0].field, aggregation: 'sum' }]\n }\n }\n\n // Calculated field management\n function addCalculatedField(field: CalculatedField) {\n const existing = calculatedFields.value.findIndex(f => f.id === field.id)\n if (existing >= 0) {\n calculatedFields.value = [\n ...calculatedFields.value.slice(0, existing),\n field,\n ...calculatedFields.value.slice(existing + 1),\n ]\n }\n else {\n calculatedFields.value = [...calculatedFields.value, field]\n }\n saveCalculatedFields(calculatedFields.value)\n }\n\n function removeCalculatedField(id: string) {\n calculatedFields.value = calculatedFields.value.filter(f => f.id !== id)\n // Also remove from value fields if it was being used\n valueFields.value = valueFields.value.filter(v => v.field !== `calc:${id}`)\n saveCalculatedFields(calculatedFields.value)\n }\n\n // Watch data to restore or validate config\n watch(\n data,\n (newData) => {\n if (newData.length === 0)\n return\n\n const newKeys = Object.keys(newData[0])\n const storageKey = generateStorageKey(newKeys)\n\n if (storageKey !== currentStorageKey.value) {\n currentStorageKey.value = storageKey\n\n const savedConfig = loadPivotConfig(storageKey)\n if (savedConfig && isConfigValidForFields(savedConfig, newKeys)) {\n rowFields.value = savedConfig.rowFields\n columnFields.value = savedConfig.columnFields\n valueFields.value = savedConfig.valueFields\n showRowTotals.value = savedConfig.showRowTotals\n showColumnTotals.value = savedConfig.showColumnTotals\n if (savedConfig.calculatedFields) {\n calculatedFields.value = savedConfig.calculatedFields\n }\n }\n else {\n const currentConfig: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n }\n if (!isConfigValidForFields(currentConfig, newKeys)) {\n clearConfig()\n }\n }\n }\n else {\n const currentConfig: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n }\n if (!isConfigValidForFields(currentConfig, newKeys)) {\n clearConfig()\n }\n }\n },\n { immediate: true },\n )\n\n // Watch config changes and save to sessionStorage\n watch(\n [rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields],\n () => {\n if (!currentStorageKey.value)\n return\n\n const config: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n calculatedFields: calculatedFields.value,\n }\n savePivotConfig(currentStorageKey.value, config)\n },\n { deep: true },\n )\n\n return {\n // State\n rowFields,\n columnFields,\n valueFields,\n showRowTotals,\n showColumnTotals,\n calculatedFields,\n\n // Computed\n availableFields,\n unassignedFields,\n isConfigured,\n pivotResult,\n\n // Actions\n addRowField,\n removeRowField,\n addColumnField,\n removeColumnField,\n addValueField,\n removeValueField,\n updateValueFieldAggregation,\n clearConfig,\n moveField,\n autoSuggestConfig,\n addCalculatedField,\n removeCalculatedField,\n }\n}\n","<script setup lang=\"ts\">\nimport type { AggregationFunction, CalculatedField, PivotValueField } from '@smallwebco/tinypivot-core'\nimport { AGGREGATION_OPTIONS, getAggregationSymbol } from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Configuration Panel\n * Draggable fields with aggregation selection\n */\nimport { computed, ref } from 'vue'\nimport { useLicense } from '../composables/useLicense'\nimport CalculatedFieldModal from './CalculatedFieldModal.vue'\n\ninterface FieldStats {\n field: string\n type: 'string' | 'number' | 'date' | 'boolean' | 'mixed'\n uniqueCount: number\n isNumeric: boolean\n}\n\ninterface ExtendedFieldStats extends FieldStats {\n isCalculated: boolean\n calcId?: string\n calcName?: string\n calcFormula?: string\n}\n\nconst props = defineProps<{\n availableFields: FieldStats[]\n rowFields: string[]\n columnFields: string[]\n valueFields: PivotValueField[]\n showRowTotals: boolean\n showColumnTotals: boolean\n calculatedFields?: CalculatedField[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'update:showRowTotals', value: boolean): void\n (e: 'update:showColumnTotals', value: boolean): void\n (e: 'clearConfig'): void\n (e: 'dragStart', field: string, event: DragEvent): void\n (e: 'dragEnd'): void\n (e: 'updateAggregation', field: string, oldAgg: AggregationFunction, newAgg: AggregationFunction): void\n (e: 'addRowField', field: string): void\n (e: 'removeRowField', field: string): void\n (e: 'addColumnField', field: string): void\n (e: 'removeColumnField', field: string): void\n (e: 'addValueField', field: string, aggregation: AggregationFunction): void\n (e: 'removeValueField', field: string, aggregation: AggregationFunction): void\n (e: 'addCalculatedField', field: CalculatedField): void\n (e: 'removeCalculatedField', id: string): void\n (e: 'updateCalculatedField', field: CalculatedField): void\n}>()\n\nconst { canUseAdvancedAggregations } = useLicense()\n\n// Use aggregation options from core\nconst aggregationOptions = AGGREGATION_OPTIONS\n\n// Check if an aggregation requires Pro (everything except sum)\nfunction aggregationRequiresPro(agg: AggregationFunction): boolean {\n return agg !== 'sum'\n}\n\n// Check if an aggregation is available based on license\nfunction isAggregationAvailable(agg: AggregationFunction): boolean {\n return !aggregationRequiresPro(agg) || canUseAdvancedAggregations.value\n}\n\n// Calculated field modal state\nconst showCalcModal = ref(false)\nconst editingCalcField = ref<CalculatedField | null>(null)\n\n// Get only numeric field names for calculated field formulas\nconst numericFieldNames = computed(() =>\n props.availableFields\n .filter(f => f.isNumeric)\n .map(f => f.field),\n)\n\nfunction openCalcModal(field?: CalculatedField) {\n editingCalcField.value = field || null\n showCalcModal.value = true\n}\n\nfunction handleSaveCalcField(field: CalculatedField) {\n if (editingCalcField.value) {\n emit('updateCalculatedField', field)\n }\n else {\n emit('addCalculatedField', field)\n }\n showCalcModal.value = false\n editingCalcField.value = null\n}\n\n// Toggle both row and column totals together\nfunction handleTotalsToggle(checked: boolean) {\n emit('update:showRowTotals', checked)\n emit('update:showColumnTotals', checked)\n}\n\n// Convert calculated fields to virtual FieldStats for display\nconst calculatedFieldsAsStats = computed<ExtendedFieldStats[]>(() => {\n if (!props.calculatedFields)\n return []\n return props.calculatedFields.map(calc => ({\n field: `calc:${calc.id}`,\n type: 'number' as const,\n uniqueCount: 0,\n isNumeric: true,\n isCalculated: true,\n calcId: calc.id,\n calcName: calc.name,\n calcFormula: calc.formula,\n }))\n})\n\n// Combined available fields (data fields + calculated fields)\nconst allAvailableFields = computed<ExtendedFieldStats[]>(() => [\n ...props.availableFields.map(f => ({ ...f, isCalculated: false as const })),\n ...calculatedFieldsAsStats.value,\n])\n\n// Assigned fields\nconst assignedFields = computed(() => {\n const rowSet = new Set(props.rowFields)\n const colSet = new Set(props.columnFields)\n const valueMap = new Map(props.valueFields.map(v => [v.field, v]))\n\n return allAvailableFields.value\n .filter(f => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field))\n .map(f => ({\n ...f,\n assignedTo: rowSet.has(f.field)\n ? 'row' as const\n : colSet.has(f.field)\n ? 'column' as const\n : 'value' as const,\n valueConfig: valueMap.get(f.field),\n }))\n})\n\n// Unassigned fields (including unassigned calculated fields)\nconst unassignedFields = computed(() => {\n const rowSet = new Set(props.rowFields)\n const colSet = new Set(props.columnFields)\n const valSet = new Set(props.valueFields.map(v => v.field))\n\n return allAvailableFields.value.filter(f =>\n !rowSet.has(f.field) && !colSet.has(f.field) && !valSet.has(f.field),\n )\n})\n\nconst assignedCount = computed(() => assignedFields.value.length)\n\n// Field search\nconst fieldSearch = ref('')\nconst filteredUnassignedFields = computed(() => {\n if (!fieldSearch.value.trim())\n return unassignedFields.value\n const search = fieldSearch.value.toLowerCase().trim()\n return unassignedFields.value.filter((f) => {\n // Search by field name or calculated field display name\n const fieldName = f.field.toLowerCase()\n const displayName = f.isCalculated && f.calcName ? f.calcName.toLowerCase() : ''\n return fieldName.includes(search) || displayName.includes(search)\n })\n})\n\n// Field type icons\nfunction getFieldIcon(type: FieldStats['type'], isCalculated?: boolean): string {\n if (isCalculated)\n return 'ƒ'\n switch (type) {\n case 'number': return '#'\n case 'date': return '📅'\n case 'boolean': return '✓'\n default: return 'Aa'\n }\n}\n\n// Get display name for field (handles calculated fields)\nfunction getFieldDisplayName(field: any): string {\n if (field.isCalculated && field.calcName) {\n return field.calcName\n }\n return field.field\n}\n\nfunction handleDragStart(field: string, event: DragEvent) {\n event.dataTransfer?.setData('text/plain', field)\n event.dataTransfer!.effectAllowed = 'move'\n emit('dragStart', field, event)\n}\n\nfunction handleDragEnd() {\n emit('dragEnd')\n}\n\nfunction handleAggregationChange(field: string, currentAgg: AggregationFunction, newAgg: AggregationFunction) {\n // Prevent changing to Pro aggregations without license\n if (!isAggregationAvailable(newAgg)) {\n console.warn(`[TinyPivot] \"${newAgg}\" aggregation requires a Pro license. Visit https://tiny-pivot.com/#pricing to upgrade.`)\n return\n }\n emit('updateAggregation', field, currentAgg, newAgg)\n}\n\nfunction toggleRowColumn(field: string, currentAssignment: 'row' | 'column') {\n if (currentAssignment === 'row') {\n emit('removeRowField', field)\n emit('addColumnField', field)\n }\n else {\n emit('removeColumnField', field)\n emit('addRowField', field)\n }\n}\n\nfunction removeField(field: string, assignedTo: 'row' | 'column' | 'value', valueConfig?: PivotValueField) {\n if (assignedTo === 'row') {\n emit('removeRowField', field)\n }\n else if (assignedTo === 'column') {\n emit('removeColumnField', field)\n }\n else if (valueConfig) {\n emit('removeValueField', field, valueConfig.aggregation)\n }\n}\n</script>\n\n<template>\n <div class=\"vpg-pivot-config\">\n <!-- Header -->\n <div class=\"vpg-config-header\">\n <h3 class=\"vpg-config-title\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 10h16M4 14h16M4 18h16\" />\n </svg>\n Fields\n </h3>\n <div class=\"vpg-header-actions\">\n <button\n v-if=\"assignedCount > 0\"\n class=\"vpg-action-btn vpg-clear-btn\"\n title=\"Clear all\"\n @click=\"emit('clearConfig')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Assigned Fields -->\n <div v-if=\"assignedCount > 0\" class=\"vpg-assigned-section\">\n <div class=\"vpg-section-label\">\n Active\n </div>\n <div class=\"vpg-assigned-list\">\n <div\n v-for=\"field in assignedFields\"\n :key=\"field.field\"\n class=\"vpg-assigned-item\"\n :class=\"[`vpg-type-${field.assignedTo}`, { 'vpg-type-calc': field.isCalculated }]\"\n :title=\"field.isCalculated ? field.calcFormula : field.field\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field.field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <div class=\"vpg-item-main\">\n <span class=\"vpg-item-badge\" :class=\"[field.assignedTo, { calc: field.isCalculated }]\">\n {{ field.isCalculated ? 'ƒ' : (field.assignedTo === 'row' ? 'R' : field.assignedTo === 'column' ? 'C' : getAggregationSymbol(field.valueConfig?.aggregation || 'sum')) }}\n </span>\n <span class=\"vpg-item-name\">{{ getFieldDisplayName(field) }}</span>\n </div>\n\n <div class=\"vpg-item-actions\">\n <button\n v-if=\"field.assignedTo === 'row' || field.assignedTo === 'column'\"\n class=\"vpg-toggle-btn\"\n :title=\"field.assignedTo === 'row' ? 'Move to Columns' : 'Move to Rows'\"\n @click.stop=\"toggleRowColumn(field.field, field.assignedTo)\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4\" />\n </svg>\n </button>\n\n <select\n v-if=\"field.assignedTo === 'value' && field.valueConfig\"\n class=\"vpg-agg-select\"\n :value=\"field.valueConfig.aggregation\"\n @change=\"handleAggregationChange(field.field, field.valueConfig!.aggregation, ($event.target as HTMLSelectElement).value as AggregationFunction)\"\n @click.stop\n >\n <option\n v-for=\"agg in aggregationOptions\"\n :key=\"agg.value\"\n :value=\"agg.value\"\n :disabled=\"aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations\"\n >\n {{ agg.symbol }} {{ agg.label }}{{ aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations ? ' (Pro)' : '' }}\n </option>\n </select>\n\n <button\n class=\"vpg-remove-btn\"\n title=\"Remove\"\n @click.stop=\"removeField(field.field, field.assignedTo, field.valueConfig)\"\n >\n ×\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Unassigned Fields -->\n <div class=\"vpg-unassigned-section\">\n <div class=\"vpg-section-header\">\n <div class=\"vpg-section-label\">\n Available <span class=\"vpg-count\">{{ unassignedFields.length }}</span>\n </div>\n </div>\n\n <!-- Field Search -->\n <div class=\"vpg-field-search\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n v-model=\"fieldSearch\"\n type=\"text\"\n placeholder=\"Search fields...\"\n class=\"vpg-search-input\"\n >\n <button v-if=\"fieldSearch\" class=\"vpg-clear-search\" @click=\"fieldSearch = ''\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div class=\"vpg-field-list\">\n <div\n v-for=\"field in filteredUnassignedFields\"\n :key=\"field.field\"\n class=\"vpg-field-item\"\n :class=\"{\n 'vpg-is-numeric': field.isNumeric && !field.isCalculated,\n 'vpg-is-calculated': field.isCalculated,\n }\"\n :title=\"field.isCalculated ? field.calcFormula : field.field\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field.field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-type-icon\" :class=\"{ 'vpg-calc-type': field.isCalculated }\">\n {{ getFieldIcon(field.type, field.isCalculated) }}\n </span>\n <span class=\"vpg-field-name\">{{ getFieldDisplayName(field) }}</span>\n <template v-if=\"field.isCalculated\">\n <button\n class=\"vpg-field-edit\"\n title=\"Edit calculated field\"\n @click.stop=\"openCalcModal(calculatedFields?.find(c => c.id === field.calcId))\"\n >\n ✎\n </button>\n <button\n class=\"vpg-field-delete\"\n title=\"Delete calculated field\"\n @click.stop=\"field.calcId && emit('removeCalculatedField', field.calcId)\"\n >\n ×\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-unique-count\">{{ field.uniqueCount }}</span>\n </template>\n </div>\n <div v-if=\"filteredUnassignedFields.length === 0 && fieldSearch\" class=\"vpg-empty-hint\">\n No fields match \"{{ fieldSearch }}\"\n </div>\n <div v-else-if=\"unassignedFields.length === 0\" class=\"vpg-empty-hint\">\n All fields assigned\n </div>\n </div>\n </div>\n\n <!-- Options -->\n <div class=\"vpg-options-section\">\n <label class=\"vpg-option-toggle\">\n <input\n type=\"checkbox\"\n :checked=\"showRowTotals\"\n @change=\"handleTotalsToggle(($event.target as HTMLInputElement).checked)\"\n >\n <span>Totals</span>\n </label>\n <button class=\"vpg-calc-btn\" title=\"Add calculated field (e.g. Profit Margin %)\" @click=\"openCalcModal()\">\n <span class=\"vpg-calc-icon\">ƒ</span>\n <span>+ Calc</span>\n </button>\n </div>\n\n <!-- Calculated Field Modal -->\n <CalculatedFieldModal\n :show=\"showCalcModal\"\n :available-fields=\"numericFieldNames\"\n :existing-field=\"editingCalcField\"\n @close=\"showCalcModal = false; editingCalcField = null\"\n @save=\"handleSaveCalcField\"\n />\n </div>\n</template>\n\n<style scoped>\n.vpg-pivot-config {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-config-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-config-title {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-icon-sm {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-header-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-action-btn {\n padding: 0.375rem;\n border-radius: 0.25rem;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-clear-btn {\n color: #94a3b8;\n}\n\n.vpg-clear-btn:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-section-label {\n font-size: 0.625rem;\n font-weight: 700;\n color: #94a3b8;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n padding: 0.25rem 0.5rem;\n}\n\n.vpg-section-label .vpg-count {\n color: #cbd5e1;\n margin-left: 0.25rem;\n}\n\n.vpg-assigned-section {\n border-bottom: 1px solid #e2e8f0;\n background: linear-gradient(to bottom, #f8fafc, white);\n padding-bottom: 0.5rem;\n flex-shrink: 0;\n}\n\n.vpg-assigned-list {\n padding: 0 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.vpg-assigned-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.375rem 0.5rem;\n border-radius: 0.5rem;\n font-size: 0.75rem;\n cursor: grab;\n transition: all 0.15s;\n}\n\n.vpg-assigned-item:active {\n cursor: grabbing;\n transform: scale(0.98);\n}\n\n.vpg-assigned-item.vpg-type-row {\n background: #eef2ff;\n border: 1px solid #c7d2fe;\n}\n\n.vpg-assigned-item.vpg-type-column {\n background: #f5f3ff;\n border: 1px solid #ddd6fe;\n}\n\n.vpg-assigned-item.vpg-type-value {\n background: #ecfdf5;\n border: 1px solid #a7f3d0;\n}\n\n.vpg-assigned-item.vpg-type-calc {\n background: #fdf4ff;\n border: 1px solid #f0abfc;\n cursor: pointer;\n}\n\n.vpg-item-main {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n min-width: 0;\n}\n\n.vpg-item-badge {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n}\n\n.vpg-item-badge.row {\n background: #c7d2fe;\n color: #4338ca;\n}\n\n.vpg-item-badge.column {\n background: #ddd6fe;\n color: #7c3aed;\n}\n\n.vpg-item-badge.value {\n background: #a7f3d0;\n color: #059669;\n}\n\n.vpg-item-badge.calc {\n background: #f0abfc;\n color: #86198f;\n}\n\n.vpg-item-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n color: #334155;\n}\n\n.vpg-item-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n.vpg-toggle-btn {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.25rem;\n color: #94a3b8;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-toggle-btn:hover {\n background: white;\n color: #475569;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-agg-select {\n font-size: 0.625rem;\n background: white;\n border: 1px solid #a7f3d0;\n border-radius: 0.25rem;\n padding: 0.125rem 0.25rem;\n color: #059669;\n font-weight: 500;\n min-width: 70px;\n cursor: pointer;\n}\n\n.vpg-agg-select:focus {\n outline: none;\n box-shadow: 0 0 0 1px #10b981;\n}\n\n.vpg-remove-btn {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n line-height: 1;\n color: #94a3b8;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-remove-btn:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-unassigned-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.vpg-section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 0.5rem;\n}\n\n.vpg-field-search {\n position: relative;\n margin: 0 0.5rem 0.5rem;\n}\n\n.vpg-search-icon {\n position: absolute;\n left: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n width: 0.875rem;\n height: 0.875rem;\n color: #94a3b8;\n pointer-events: none;\n}\n\n.vpg-search-input {\n width: 100%;\n padding: 0.375rem 1.75rem 0.375rem 1.75rem;\n font-size: 0.75rem;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n background: white;\n color: #334155;\n}\n\n.vpg-search-input::placeholder {\n color: #94a3b8;\n}\n\n.vpg-search-input:focus {\n outline: none;\n box-shadow: 0 0 0 1px #6366f1;\n border-color: #6366f1;\n}\n\n.vpg-clear-search {\n position: absolute;\n right: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n padding: 0.125rem;\n border-radius: 0.25rem;\n color: #94a3b8;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-clear-search:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-field-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 0.5rem 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.vpg-field-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0.5rem;\n border-radius: 0.375rem;\n font-size: 0.75rem;\n cursor: grab;\n background: white;\n border: 1px solid #e2e8f0;\n color: #475569;\n transition: all 0.15s;\n}\n\n.vpg-field-item:hover {\n border-color: #cbd5e1;\n background: #f8fafc;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-field-item:active {\n cursor: grabbing;\n transform: scale(0.98);\n}\n\n.vpg-field-item.vpg-is-numeric {\n border-color: #bfdbfe;\n background: rgba(239, 246, 255, 0.3);\n}\n\n.vpg-field-item.vpg-is-calculated {\n border-color: #e9d5ff;\n background: rgba(250, 232, 255, 0.5);\n}\n\n.vpg-calc-type {\n background: #f0abfc !important;\n color: #86198f !important;\n}\n\n.vpg-field-edit,\n.vpg-field-delete {\n width: 1.125rem;\n height: 1.125rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n line-height: 1;\n color: #94a3b8;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.vpg-field-edit:hover {\n background: #e0e7ff;\n color: #4f46e5;\n}\n\n.vpg-field-delete:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-field-type-icon {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n background: #f1f5f9;\n border-radius: 0.25rem;\n color: #64748b;\n flex-shrink: 0;\n}\n\n.vpg-field-item.vpg-is-numeric .vpg-field-type-icon {\n background: #dbeafe;\n color: #2563eb;\n}\n\n.vpg-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.vpg-unique-count {\n font-size: 0.625rem;\n color: #94a3b8;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n}\n\n.vpg-empty-hint {\n font-size: 0.6875rem;\n color: #94a3b8;\n font-style: italic;\n text-align: center;\n padding: 1rem;\n}\n\n.vpg-options-section {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n border-top: 1px solid #f1f5f9;\n background: rgba(248, 250, 252, 0.5);\n flex-shrink: 0;\n}\n\n.vpg-option-toggle {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.6875rem;\n color: #64748b;\n cursor: pointer;\n user-select: none;\n}\n\n.vpg-option-toggle input {\n width: 0.875rem;\n height: 0.875rem;\n border-radius: 0.25rem;\n accent-color: #10b981;\n cursor: pointer;\n}\n\n.vpg-calc-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n border-radius: 0.25rem;\n background: #fdf4ff;\n color: #a855f7;\n border: 1px solid #e9d5ff;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-calc-btn:hover {\n background: #fae8ff;\n border-color: #d8b4fe;\n}\n\n.vpg-calc-icon {\n font-size: 0.75rem;\n font-weight: 700;\n}\n\n/* Scrollbar */\n.vpg-field-list::-webkit-scrollbar {\n width: 0.375rem;\n}\n\n.vpg-field-list::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.vpg-field-list::-webkit-scrollbar-thumb {\n background: #e2e8f0;\n border-radius: 9999px;\n}\n\n.vpg-field-list::-webkit-scrollbar-thumb:hover {\n background: #cbd5e1;\n}\n</style>\n\n<style>\n/* Dark mode - PivotConfig */\n.vpg-theme-dark .vpg-pivot-config {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-config-header {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-config-title {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-section-label {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-section-label .vpg-count {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-assigned-section {\n border-color: #334155;\n background: linear-gradient(to bottom, #0f172a, #1e293b);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-row {\n background: rgba(99, 102, 241, 0.15);\n border-color: rgba(99, 102, 241, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-column {\n background: rgba(139, 92, 246, 0.15);\n border-color: rgba(139, 92, 246, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-value {\n background: rgba(16, 185, 129, 0.15);\n border-color: rgba(16, 185, 129, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-calc {\n background: rgba(168, 85, 247, 0.15);\n border-color: rgba(168, 85, 247, 0.3);\n}\n\n.vpg-theme-dark .vpg-item-badge.row {\n background: rgba(99, 102, 241, 0.3);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-item-badge.column {\n background: rgba(139, 92, 246, 0.3);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-item-badge.value {\n background: rgba(16, 185, 129, 0.3);\n color: #6ee7b7;\n}\n\n.vpg-theme-dark .vpg-item-badge.calc {\n background: rgba(168, 85, 247, 0.3);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-item-name {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-toggle-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-toggle-btn:hover {\n background: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-agg-select {\n background: #0f172a;\n border-color: rgba(16, 185, 129, 0.3);\n color: #6ee7b7;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-agg-select:focus {\n box-shadow: 0 0 0 1px #10b981;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-remove-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-remove-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input {\n background: #0f172a;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input::placeholder {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 1px #6366f1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-icon {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-search:hover {\n background: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item {\n background: #0f172a;\n border-color: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item:hover {\n border-color: #475569;\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-numeric {\n border-color: rgba(59, 130, 246, 0.3);\n background: rgba(59, 130, 246, 0.1);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-type-icon {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-numeric .vpg-field-type-icon {\n background: rgba(59, 130, 246, 0.3);\n color: #60a5fa;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-calculated {\n border-color: rgba(168, 85, 247, 0.3);\n background: rgba(168, 85, 247, 0.1);\n}\n\n.vpg-theme-dark .vpg-calc-type {\n background: rgba(168, 85, 247, 0.4) !important;\n color: #c4b5fd !important;\n}\n\n.vpg-theme-dark .vpg-field-edit,\n.vpg-theme-dark .vpg-field-delete {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-field-edit:hover {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-field-delete:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-unique-count {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-empty-hint {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-options-section {\n border-color: #334155;\n background: rgba(15, 23, 42, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-option-toggle {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-calc-btn {\n background: rgba(168, 85, 247, 0.15);\n color: #c084fc;\n border-color: rgba(168, 85, 247, 0.3);\n}\n\n.vpg-theme-dark .vpg-calc-btn:hover {\n background: rgba(168, 85, 247, 0.25);\n border-color: rgba(168, 85, 247, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-list::-webkit-scrollbar-thumb {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-list::-webkit-scrollbar-thumb:hover {\n background: #475569;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { AggregationFunction, CalculatedField, PivotResult, PivotValueField } from '@smallwebco/tinypivot-core'\nimport { getAggregationLabel, getAggregationSymbol } from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Skeleton + Data Display\n * Visual layout for pivot configuration and results\n */\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\nimport { useLicense } from '../composables/useLicense'\n\ninterface ActiveFilter {\n column: string\n valueCount: number\n values?: string[]\n displayText?: string\n isRange?: boolean\n}\n\nconst props = defineProps<{\n rowFields: string[]\n columnFields: string[]\n valueFields: PivotValueField[]\n calculatedFields?: CalculatedField[]\n isConfigured: boolean\n draggingField: string | null\n pivotResult: PivotResult | null\n fontSize?: 'xs' | 'sm' | 'base'\n activeFilters?: ActiveFilter[] | null\n totalRowCount?: number\n filteredRowCount?: number\n}>()\n\nconst emit = defineEmits<{\n (e: 'addRowField', field: string): void\n (e: 'removeRowField', field: string): void\n (e: 'addColumnField', field: string): void\n (e: 'removeColumnField', field: string): void\n (e: 'addValueField', field: string, aggregation: AggregationFunction): void\n (e: 'removeValueField', field: string, aggregation: AggregationFunction): void\n (e: 'updateAggregation', field: string, oldAgg: AggregationFunction, newAgg: AggregationFunction): void\n (e: 'reorderRowFields', fields: string[]): void\n (e: 'reorderColumnFields', fields: string[]): void\n}>()\n\n// Helper to get display name for value fields (resolves calc IDs to names)\nfunction getValueFieldDisplayName(field: string): string {\n if (field.startsWith('calc:')) {\n const calcId = field.replace('calc:', '')\n const calcField = props.calculatedFields?.find(c => c.id === calcId)\n return calcField?.name || field\n }\n return field\n}\n\n// Helper to check if field is a calculated field\nfunction isCalculatedField(field: string): boolean {\n return field.startsWith('calc:')\n}\n\nconst { showWatermark, canUsePivot, isDemo } = useLicense()\n\n// Drag state\nconst dragOverArea = ref<'row' | 'column' | 'value' | null>(null)\n\n// Reorder drag state\nconst reorderDragSource = ref<{ zone: 'row' | 'column', index: number } | null>(null)\nconst reorderDropTarget = ref<{ zone: 'row' | 'column', index: number } | null>(null)\n\n// Use getAggregationLabel and getAggregationSymbol from core\n\n// Font size\nconst currentFontSize = ref(props.fontSize || 'xs')\nconst fontSizeOptions = [\n { value: 'xs', label: 'S' },\n { value: 'sm', label: 'M' },\n { value: 'base', label: 'L' },\n] as const\n\n// Filter status\nconst hasActiveFilters = computed(() => props.activeFilters && props.activeFilters.length > 0)\nconst filterSummary = computed(() => {\n if (!props.activeFilters || props.activeFilters.length === 0)\n return ''\n const columns = props.activeFilters.map(f => f.column).join(', ')\n return columns\n})\n\n// Detailed filter tooltip\nconst filterTooltipDetails = computed(() => {\n if (!props.activeFilters || props.activeFilters.length === 0)\n return []\n return props.activeFilters.map((f) => {\n // Handle range filters\n if (f.isRange && f.displayText) {\n return {\n column: f.column,\n displayText: f.displayText,\n isRange: true,\n values: [],\n remaining: 0,\n }\n }\n // Handle value filters\n const values = f.values || []\n const maxDisplay = 5\n const displayValues = values.slice(0, maxDisplay)\n const remaining = values.length - maxDisplay\n return {\n column: f.column,\n values: displayValues,\n remaining: remaining > 0 ? remaining : 0,\n isRange: false,\n }\n })\n})\n\n// Show/hide tooltip\nconst showFilterTooltip = ref(false)\n\n// Sorting\ntype SortDirection = 'asc' | 'desc'\ntype SortTarget = 'row' | number\nconst sortDirection = ref<SortDirection>('asc')\nconst sortTarget = ref<SortTarget>('row')\n\nfunction toggleSort(target: SortTarget = 'row') {\n if (sortTarget.value === target) {\n sortDirection.value = sortDirection.value === 'asc' ? 'desc' : 'asc'\n }\n else {\n sortTarget.value = target\n sortDirection.value = 'asc'\n }\n}\n\n// Sorted row indices\nconst sortedRowIndices = computed(() => {\n if (!props.pivotResult)\n return []\n\n const indices = props.pivotResult.rowHeaders.map((_, i) => i)\n const headers = props.pivotResult.rowHeaders\n const data = props.pivotResult.data\n\n indices.sort((a, b) => {\n let cmp: number\n\n if (sortTarget.value === 'row') {\n const aHeader = headers[a]?.join(' / ') || ''\n const bHeader = headers[b]?.join(' / ') || ''\n cmp = aHeader.localeCompare(bHeader, undefined, { numeric: true, sensitivity: 'base' })\n }\n else {\n const colIdx = sortTarget.value as number\n const aVal = data[a]?.[colIdx]?.value ?? null\n const bVal = data[b]?.[colIdx]?.value ?? null\n\n if (aVal === null && bVal === null)\n cmp = 0\n else if (aVal === null)\n cmp = 1\n else if (bVal === null)\n cmp = -1\n else cmp = aVal - bVal\n }\n\n return sortDirection.value === 'asc' ? cmp : -cmp\n })\n\n return indices\n})\n\n// Column headers\nconst columnHeaderCells = computed(() => {\n if (!props.pivotResult || props.pivotResult.headers.length === 0) {\n return [props.valueFields.map(vf => ({\n label: isCalculatedField(vf.field)\n ? `${getValueFieldDisplayName(vf.field)} (${getAggregationLabel(vf.aggregation)})`\n : `${vf.field} (${getAggregationLabel(vf.aggregation)})`,\n colspan: 1,\n }))]\n }\n\n const result: Array<Array<{ label: string, colspan: number }>> = []\n\n for (let level = 0; level < props.pivotResult.headers.length; level++) {\n const headerRow = props.pivotResult.headers[level]\n const cells: Array<{ label: string, colspan: number }> = []\n\n let i = 0\n while (i < headerRow.length) {\n const value = headerRow[i]\n let colspan = 1\n\n while (i + colspan < headerRow.length && headerRow[i + colspan] === value) {\n colspan++\n }\n\n cells.push({ label: value, colspan })\n i += colspan\n }\n\n result.push(cells)\n }\n\n return result\n})\n\n// Selection for copy support with drag\nconst selectedCell = ref<{ row: number, col: number } | null>(null)\nconst selectionStart = ref<{ row: number, col: number } | null>(null)\nconst selectionEnd = ref<{ row: number, col: number } | null>(null)\nconst isSelecting = ref(false)\nconst showCopyToast = ref(false)\nconst copyToastMessage = ref('')\n\nconst selectionBounds = computed(() => {\n if (!selectionStart.value || !selectionEnd.value)\n return null\n return {\n minRow: Math.min(selectionStart.value.row, selectionEnd.value.row),\n maxRow: Math.max(selectionStart.value.row, selectionEnd.value.row),\n minCol: Math.min(selectionStart.value.col, selectionEnd.value.col),\n maxCol: Math.max(selectionStart.value.col, selectionEnd.value.col),\n }\n})\n\nfunction handleCellMouseDown(rowIndex: number, colIndex: number, event: MouseEvent) {\n event.preventDefault()\n\n if (event.shiftKey && selectedCell.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n else {\n selectedCell.value = { row: rowIndex, col: colIndex }\n selectionStart.value = { row: rowIndex, col: colIndex }\n selectionEnd.value = { row: rowIndex, col: colIndex }\n isSelecting.value = true\n }\n}\n\nfunction handleCellMouseEnter(rowIndex: number, colIndex: number) {\n if (isSelecting.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n}\n\nfunction handleMouseUp() {\n isSelecting.value = false\n}\n\nfunction isCellSelected(rowIndex: number, colIndex: number): boolean {\n if (!selectionBounds.value) {\n return selectedCell.value?.row === rowIndex && selectedCell.value?.col === colIndex\n }\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n return rowIndex >= minRow && rowIndex <= maxRow && colIndex >= minCol && colIndex <= maxCol\n}\n\nfunction copySelectionToClipboard() {\n if (!selectionBounds.value || !props.pivotResult)\n return\n\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n const lines: string[] = []\n\n for (let r = minRow; r <= maxRow; r++) {\n const sortedIdx = sortedRowIndices.value[r]\n if (sortedIdx === undefined)\n continue\n\n const rowValues: string[] = []\n for (let c = minCol; c <= maxCol; c++) {\n const cell = props.pivotResult.data[sortedIdx]?.[c]\n rowValues.push(cell?.formattedValue ?? '')\n }\n lines.push(rowValues.join('\\t'))\n }\n\n const text = lines.join('\\n')\n\n navigator.clipboard.writeText(text).then(() => {\n const cellCount = (maxRow - minRow + 1) * (maxCol - minCol + 1)\n copyToastMessage.value = `Copied ${cellCount} cell${cellCount > 1 ? 's' : ''}`\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n }).catch((err) => {\n console.error('Copy failed:', err)\n })\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n // Only handle if pivot has focus or selection\n if (!selectionBounds.value)\n return\n\n if ((event.ctrlKey || event.metaKey) && event.key === 'c') {\n event.preventDefault()\n copySelectionToClipboard()\n return\n }\n\n if (event.key === 'Escape') {\n selectedCell.value = null\n selectionStart.value = null\n selectionEnd.value = null\n }\n}\n\n// Selection statistics for the footer\nconst selectionStats = computed(() => {\n if (!selectionBounds.value || !props.pivotResult)\n return null\n\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n const values: number[] = []\n let count = 0\n\n for (let r = minRow; r <= maxRow; r++) {\n const sortedIdx = sortedRowIndices.value[r]\n if (sortedIdx === undefined)\n continue\n\n for (let c = minCol; c <= maxCol; c++) {\n const cell = props.pivotResult.data[sortedIdx]?.[c]\n count++\n if (cell?.value !== null && cell?.value !== undefined && typeof cell.value === 'number') {\n values.push(cell.value)\n }\n }\n }\n\n if (count <= 1)\n return null\n\n const sum = values.reduce((a, b) => a + b, 0)\n const avg = values.length > 0 ? sum / values.length : 0\n\n return {\n count,\n numericCount: values.length,\n sum,\n avg,\n }\n})\n\nfunction formatStatValue(val: number): string {\n if (Math.abs(val) >= 1_000_000)\n return `${(val / 1_000_000).toFixed(2)}M`\n if (Math.abs(val) >= 1_000)\n return `${(val / 1_000).toFixed(2)}K`\n return val.toFixed(2)\n}\n\n// Lifecycle hooks for event listeners\nonMounted(() => {\n document.addEventListener('mouseup', handleMouseUp)\n document.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mouseup', handleMouseUp)\n document.removeEventListener('keydown', handleKeydown)\n})\n\n// Drag handlers\nfunction handleDragOver(area: 'row' | 'column' | 'value', event: DragEvent) {\n event.preventDefault()\n event.dataTransfer!.dropEffect = 'move'\n dragOverArea.value = area\n}\n\nfunction handleDragLeave() {\n dragOverArea.value = null\n}\n\nfunction handleDrop(area: 'row' | 'column' | 'value', event: DragEvent) {\n event.preventDefault()\n const field = event.dataTransfer?.getData('text/plain')\n\n // Skip if this is a reorder operation (handled by chip drop)\n if (!field || field.startsWith('reorder:')) {\n dragOverArea.value = null\n return\n }\n\n if (props.rowFields.includes(field))\n emit('removeRowField', field)\n if (props.columnFields.includes(field))\n emit('removeColumnField', field)\n const existingValue = props.valueFields.find(v => v.field === field)\n if (existingValue)\n emit('removeValueField', field, existingValue.aggregation)\n\n switch (area) {\n case 'row':\n emit('addRowField', field)\n break\n case 'column':\n emit('addColumnField', field)\n break\n case 'value':\n emit('addValueField', field, 'sum')\n break\n }\n dragOverArea.value = null\n}\n\n// Reorder handlers for chips within zones\nfunction handleChipDragStart(zone: 'row' | 'column', index: number, event: DragEvent) {\n reorderDragSource.value = { zone, index }\n event.dataTransfer!.effectAllowed = 'move'\n event.dataTransfer!.setData('text/plain', `reorder:${zone}:${index}`)\n // Add a slight delay to ensure visual feedback\n requestAnimationFrame(() => {\n dragOverArea.value = null\n })\n}\n\nfunction handleChipDragEnd() {\n reorderDragSource.value = null\n reorderDropTarget.value = null\n}\n\nfunction handleChipDragOver(zone: 'row' | 'column', index: number, event: DragEvent) {\n event.preventDefault()\n // Only handle reorder within same zone\n if (reorderDragSource.value && reorderDragSource.value.zone === zone) {\n event.dataTransfer!.dropEffect = 'move'\n reorderDropTarget.value = { zone, index }\n }\n}\n\nfunction handleChipDragLeave() {\n reorderDropTarget.value = null\n}\n\nfunction handleChipDrop(zone: 'row' | 'column', targetIndex: number, event: DragEvent) {\n event.preventDefault()\n event.stopPropagation()\n\n if (!reorderDragSource.value || reorderDragSource.value.zone !== zone) {\n return\n }\n\n const sourceIndex = reorderDragSource.value.index\n if (sourceIndex === targetIndex) {\n reorderDragSource.value = null\n reorderDropTarget.value = null\n return\n }\n\n // Create reordered array\n const fields = zone === 'row' ? [...props.rowFields] : [...props.columnFields]\n const [movedField] = fields.splice(sourceIndex, 1)\n fields.splice(targetIndex, 0, movedField)\n\n // Emit reorder event\n if (zone === 'row') {\n emit('reorderRowFields', fields)\n }\n else {\n emit('reorderColumnFields', fields)\n }\n\n reorderDragSource.value = null\n reorderDropTarget.value = null\n}\n\nfunction isChipDragSource(zone: 'row' | 'column', index: number): boolean {\n return reorderDragSource.value?.zone === zone && reorderDragSource.value?.index === index\n}\n\nfunction isChipDropTarget(zone: 'row' | 'column', index: number): boolean {\n return reorderDropTarget.value?.zone === zone && reorderDropTarget.value?.index === index\n}\n\n// Column width\nconst rowHeaderWidth = ref(180)\nconst dataColWidth = ref(80)\n\n// Calculate width per row header column\nconst rowHeaderColWidth = computed(() => {\n const numCols = Math.max(props.rowFields.length, 1)\n return Math.max(rowHeaderWidth.value / numCols, 80)\n})\n\n// Calculate left offset for each row header column (for sticky positioning)\nfunction getRowHeaderLeftOffset(fieldIdx: number): number {\n return fieldIdx * rowHeaderColWidth.value\n}\n</script>\n\n<template>\n <div\n class=\"vpg-pivot-skeleton\"\n :class=\"[\n `vpg-font-${currentFontSize}`,\n { 'vpg-is-dragging': draggingField },\n ]\"\n >\n <!-- Copy Toast -->\n <Transition name=\"vpg-toast\">\n <div v-if=\"showCopyToast\" class=\"vpg-toast\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n {{ copyToastMessage }}\n </div>\n </Transition>\n\n <!-- Header Bar -->\n <div class=\"vpg-skeleton-header\">\n <div class=\"vpg-skeleton-title\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\" />\n </svg>\n <span>Pivot Table</span>\n </div>\n\n <div class=\"vpg-header-right\">\n <!-- Filter indicator with tooltip -->\n <div\n v-if=\"hasActiveFilters\"\n class=\"vpg-filter-indicator\"\n @mouseenter=\"showFilterTooltip = true\"\n @mouseleave=\"showFilterTooltip = false\"\n >\n <svg class=\"vpg-filter-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span class=\"vpg-filter-text\">\n Filtered: <strong>{{ filterSummary }}</strong>\n <span v-if=\"filteredRowCount !== undefined && totalRowCount !== undefined\" class=\"vpg-filter-count\">\n ({{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} rows)\n </span>\n </span>\n\n <!-- Tooltip -->\n <div v-if=\"showFilterTooltip\" class=\"vpg-filter-tooltip\">\n <div class=\"vpg-tooltip-header\">\n Active Filters\n </div>\n <div v-for=\"filter in filterTooltipDetails\" :key=\"filter.column\" class=\"vpg-tooltip-filter\">\n <div class=\"vpg-tooltip-column\">\n {{ filter.column }}\n </div>\n <div class=\"vpg-tooltip-values\">\n <!-- Range filter display -->\n <template v-if=\"filter.isRange\">\n <span class=\"vpg-tooltip-value vpg-range-value\">{{ filter.displayText }}</span>\n </template>\n <!-- Value filter display -->\n <template v-else>\n <span v-for=\"(val, idx) in filter.values\" :key=\"idx\" class=\"vpg-tooltip-value\">\n {{ val }}\n </span>\n <span v-if=\"filter.remaining > 0\" class=\"vpg-tooltip-more\">\n +{{ filter.remaining }} more\n </span>\n </template>\n </div>\n </div>\n <div v-if=\"filteredRowCount !== undefined && totalRowCount !== undefined\" class=\"vpg-tooltip-summary\">\n Showing {{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} rows\n </div>\n </div>\n </div>\n\n <div v-if=\"isConfigured\" class=\"vpg-config-summary\">\n <span class=\"vpg-summary-badge vpg-rows\">{{ rowFields.length }} row{{ rowFields.length !== 1 ? 's' : '' }}</span>\n <span class=\"vpg-summary-badge vpg-cols\">{{ columnFields.length }} col{{ columnFields.length !== 1 ? 's' : '' }}</span>\n <span class=\"vpg-summary-badge vpg-vals\">{{ valueFields.length }} val{{ valueFields.length !== 1 ? 's' : '' }}</span>\n </div>\n\n <div v-if=\"isConfigured && pivotResult\" class=\"vpg-font-size-toggle\">\n <button\n v-for=\"opt in fontSizeOptions\"\n :key=\"opt.value\"\n class=\"vpg-font-size-btn\"\n :class=\"{ active: currentFontSize === opt.value }\"\n @click=\"currentFontSize = opt.value\"\n >\n {{ opt.label }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- License Required Message -->\n <div v-if=\"!canUsePivot\" class=\"vpg-pro-required\">\n <div class=\"vpg-pro-content\">\n <svg class=\"vpg-pro-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n <h3>Pro Feature</h3>\n <p>Pivot Table functionality requires a Pro license.</p>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" class=\"vpg-pro-link\">\n Get Pro License →\n </a>\n </div>\n </div>\n\n <!-- Content when licensed -->\n <template v-else>\n <!-- Config Bar -->\n <div class=\"vpg-config-bar\">\n <!-- Row drop zone -->\n <div\n class=\"vpg-drop-zone vpg-row-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'row' }\"\n @dragover=\"handleDragOver('row', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('row', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-row-icon\">↓</span>\n <span class=\"vpg-zone-label\">Rows</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"(field, idx) in rowFields\"\n :key=\"field\"\n class=\"vpg-mini-chip vpg-row-chip\"\n :class=\"{\n 'vpg-chip-dragging': isChipDragSource('row', idx),\n 'vpg-chip-drop-target': isChipDropTarget('row', idx),\n }\"\n draggable=\"true\"\n @dragstart=\"handleChipDragStart('row', idx, $event)\"\n @dragend=\"handleChipDragEnd\"\n @dragover=\"handleChipDragOver('row', idx, $event)\"\n @dragleave=\"handleChipDragLeave\"\n @drop=\"handleChipDrop('row', idx, $event)\"\n >\n <span class=\"vpg-drag-handle\">⋮⋮</span>\n <span class=\"vpg-mini-name\">{{ field }}</span>\n <button class=\"vpg-mini-remove\" @click.stop=\"emit('removeRowField', field)\">\n ×\n </button>\n </div>\n <span v-if=\"rowFields.length === 0\" class=\"vpg-zone-hint\">Drop here</span>\n </div>\n </div>\n\n <!-- Column drop zone -->\n <div\n class=\"vpg-drop-zone vpg-column-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'column' }\"\n @dragover=\"handleDragOver('column', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('column', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-column-icon\">→</span>\n <span class=\"vpg-zone-label\">Columns</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"(field, idx) in columnFields\"\n :key=\"field\"\n class=\"vpg-mini-chip vpg-column-chip\"\n :class=\"{\n 'vpg-chip-dragging': isChipDragSource('column', idx),\n 'vpg-chip-drop-target': isChipDropTarget('column', idx),\n }\"\n draggable=\"true\"\n @dragstart=\"handleChipDragStart('column', idx, $event)\"\n @dragend=\"handleChipDragEnd\"\n @dragover=\"handleChipDragOver('column', idx, $event)\"\n @dragleave=\"handleChipDragLeave\"\n @drop=\"handleChipDrop('column', idx, $event)\"\n >\n <span class=\"vpg-drag-handle\">⋮⋮</span>\n <span class=\"vpg-mini-name\">{{ field }}</span>\n <button class=\"vpg-mini-remove\" @click.stop=\"emit('removeColumnField', field)\">\n ×\n </button>\n </div>\n <span v-if=\"columnFields.length === 0\" class=\"vpg-zone-hint\">Drop here</span>\n </div>\n </div>\n\n <!-- Values drop zone -->\n <div\n class=\"vpg-drop-zone vpg-value-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'value' }\"\n @dragover=\"handleDragOver('value', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('value', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-value-icon\">Σ</span>\n <span class=\"vpg-zone-label\">Values</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"vf in valueFields\"\n :key=\"`${vf.field}-${vf.aggregation}`\"\n class=\"vpg-mini-chip vpg-value-chip\"\n :class=\"{ 'vpg-calc-chip': isCalculatedField(vf.field) }\"\n >\n <span class=\"vpg-agg-symbol\">{{ isCalculatedField(vf.field) ? 'ƒ' : getAggregationSymbol(vf.aggregation) }}</span>\n <span class=\"vpg-mini-name\">{{ getValueFieldDisplayName(vf.field) }}</span>\n <button class=\"vpg-mini-remove\" @click=\"emit('removeValueField', vf.field, vf.aggregation)\">\n ×\n </button>\n </div>\n <span v-if=\"valueFields.length === 0\" class=\"vpg-zone-hint\">Drop numeric</span>\n </div>\n </div>\n </div>\n\n <!-- Placeholder when not configured -->\n <div v-if=\"!isConfigured || !pivotResult\" class=\"vpg-placeholder\">\n <div class=\"vpg-placeholder-content\">\n <svg class=\"vpg-placeholder-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n <span class=\"vpg-placeholder-text\">\n <template v-if=\"valueFields.length === 0\">\n Add a <strong>Values</strong> field to see your pivot table\n </template>\n <template v-else-if=\"rowFields.length === 0 && columnFields.length === 0\">\n Add <strong>Row</strong> or <strong>Column</strong> fields to group your data\n </template>\n <template v-else>\n Your pivot table will appear here\n </template>\n </span>\n </div>\n </div>\n\n <!-- Data Table -->\n <div v-else class=\"vpg-table-container\">\n <table class=\"vpg-pivot-table\">\n <thead>\n <tr v-for=\"(headerRow, levelIdx) in columnHeaderCells\" :key=\"`header-${levelIdx}`\" class=\"vpg-column-header-row\">\n <template v-if=\"levelIdx === 0\">\n <th\n v-for=\"(field, fieldIdx) in (rowFields.length > 0 ? rowFields : ['Rows'])\"\n :key=\"`row-header-${fieldIdx}`\"\n class=\"vpg-row-header-label\"\n :rowspan=\"columnHeaderCells.length\"\n :style=\"{ width: `${rowHeaderColWidth}px`, minWidth: '80px', left: `${getRowHeaderLeftOffset(fieldIdx)}px` }\"\n @click=\"toggleSort('row')\"\n >\n <div class=\"vpg-header-content\">\n <span>{{ field }}</span>\n <span v-if=\"fieldIdx === rowFields.length - 1 || rowFields.length === 0\" class=\"vpg-sort-indicator\" :class=\"{ active: sortTarget === 'row' }\">\n {{ sortTarget === 'row' ? (sortDirection === 'asc' ? '↑' : '↓') : '⇅' }}\n </span>\n </div>\n </th>\n </template>\n <th\n v-for=\"(cell, idx) in headerRow\"\n :key=\"idx\"\n class=\"vpg-column-header-cell\"\n :colspan=\"cell.colspan\"\n :style=\"{ width: `${dataColWidth * cell.colspan}px` }\"\n @click=\"levelIdx === columnHeaderCells.length - 1 && toggleSort(idx)\"\n >\n <div class=\"vpg-header-content\">\n <span>{{ cell.label }}</span>\n <span v-if=\"levelIdx === columnHeaderCells.length - 1\" class=\"vpg-sort-indicator\" :class=\"{ active: sortTarget === idx }\">\n {{ sortTarget === idx ? (sortDirection === 'asc' ? '↑' : '↓') : '⇅' }}\n </span>\n </div>\n </th>\n <th\n v-if=\"pivotResult.rowTotals.length > 0 && levelIdx === 0\"\n class=\"vpg-total-header\"\n :rowspan=\"columnHeaderCells.length\"\n >\n Total\n </th>\n </tr>\n </thead>\n\n <tbody>\n <tr v-for=\"sortedIdx in sortedRowIndices\" :key=\"sortedIdx\" class=\"vpg-data-row\">\n <th\n v-for=\"(val, idx) in pivotResult.rowHeaders[sortedIdx]\"\n :key=\"`row-${sortedIdx}-${idx}`\"\n class=\"vpg-row-header-cell\"\n :style=\"{ width: `${rowHeaderColWidth}px`, minWidth: '80px', left: `${getRowHeaderLeftOffset(idx)}px` }\"\n >\n {{ val }}\n </th>\n\n <td\n v-for=\"(cell, colIdx) in pivotResult.data[sortedIdx]\"\n :key=\"colIdx\"\n class=\"vpg-data-cell\"\n :class=\"[\n isCellSelected(sortedRowIndices.indexOf(sortedIdx), colIdx) && 'selected',\n cell.value === null && 'vpg-is-null',\n ]\"\n :style=\"{ width: `${dataColWidth}px` }\"\n @mousedown=\"handleCellMouseDown(sortedRowIndices.indexOf(sortedIdx), colIdx, $event)\"\n @mouseenter=\"handleCellMouseEnter(sortedRowIndices.indexOf(sortedIdx), colIdx)\"\n >\n {{ cell.formattedValue }}\n </td>\n\n <td v-if=\"pivotResult.rowTotals[sortedIdx]\" class=\"vpg-data-cell vpg-total-cell\">\n {{ pivotResult.rowTotals[sortedIdx].formattedValue }}\n </td>\n </tr>\n\n <tr v-if=\"pivotResult.columnTotals.length > 0\" class=\"vpg-totals-row\">\n <th\n class=\"vpg-row-header-cell vpg-total-label\"\n :colspan=\"Math.max(rowFields.length, 1)\"\n :style=\"{ width: `${rowHeaderWidth}px` }\"\n >\n Total\n </th>\n <td\n v-for=\"(cell, colIdx) in pivotResult.columnTotals\"\n :key=\"colIdx\"\n class=\"vpg-data-cell vpg-total-cell\"\n :style=\"{ width: `${dataColWidth}px` }\"\n >\n {{ cell.formattedValue }}\n </td>\n <td v-if=\"pivotResult.rowTotals.length > 0\" class=\"vpg-data-cell vpg-grand-total-cell\">\n {{ pivotResult.grandTotal.formattedValue }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Footer -->\n <div v-if=\"isConfigured && pivotResult\" class=\"vpg-skeleton-footer\">\n <span class=\"vpg-footer-info\">{{ pivotResult.rowHeaders.length }} rows × {{ pivotResult.data[0]?.length || 0 }} columns</span>\n\n <div v-if=\"selectionStats && selectionStats.count > 1\" class=\"vpg-selection-stats\">\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Count:</span>\n <span class=\"vpg-stat-value\">{{ selectionStats.count }}</span>\n </span>\n <template v-if=\"selectionStats.numericCount > 0\">\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Sum:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.sum) }}</span>\n </span>\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Avg:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.avg) }}</span>\n </span>\n </template>\n </div>\n </div>\n </template>\n\n <!-- Watermark / Demo Banner -->\n <div v-if=\"showWatermark && canUsePivot\" class=\"vpg-watermark\" :class=\"{ 'vpg-demo-mode': isDemo }\">\n <template v-if=\"isDemo\">\n <span class=\"vpg-demo-badge\">DEMO</span>\n <span>Pro features unlocked for evaluation</span>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" rel=\"noopener\" class=\"vpg-get-pro\">\n Get Pro License →\n </a>\n </template>\n <template v-else>\n <a href=\"https://tiny-pivot.com\" target=\"_blank\" rel=\"noopener\">\n Powered by TinyPivot\n </a>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-pivot-skeleton {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.75rem;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.vpg-pivot-skeleton.vpg-is-dragging {\n box-shadow: 0 0 0 2px #10b981;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Header */\n.vpg-skeleton-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-skeleton-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-header-right {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.vpg-config-summary {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.vpg-summary-badge {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n font-weight: 600;\n border-radius: 0.25rem;\n}\n\n.vpg-summary-badge.vpg-rows {\n background: #e0e7ff;\n color: #4f46e5;\n}\n\n.vpg-summary-badge.vpg-cols {\n background: #ede9fe;\n color: #7c3aed;\n}\n\n.vpg-summary-badge.vpg-vals {\n background: #d1fae5;\n color: #059669;\n}\n\n/* Filter indicator */\n.vpg-filter-indicator {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n border: 1px solid #f59e0b;\n border-radius: 0.375rem;\n font-size: 0.6875rem;\n color: #92400e;\n box-shadow: 0 1px 2px rgba(245, 158, 11, 0.15);\n cursor: help;\n}\n\n.vpg-filter-icon {\n width: 0.875rem;\n height: 0.875rem;\n flex-shrink: 0;\n color: #d97706;\n}\n\n.vpg-filter-text {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n white-space: nowrap;\n}\n\n.vpg-filter-text strong {\n font-weight: 600;\n color: #78350f;\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-filter-count {\n color: #a16207;\n font-size: 0.625rem;\n}\n\n/* Filter tooltip */\n.vpg-filter-tooltip {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 220px;\n max-width: 320px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n z-index: 100;\n overflow: hidden;\n}\n\n.vpg-tooltip-header {\n padding: 0.5rem 0.75rem;\n font-size: 0.6875rem;\n font-weight: 700;\n color: #475569;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-tooltip-filter {\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid #f1f5f9;\n}\n\n.vpg-tooltip-filter:last-of-type {\n border-bottom: none;\n}\n\n.vpg-tooltip-column {\n font-size: 0.6875rem;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 0.375rem;\n}\n\n.vpg-tooltip-values {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n\n.vpg-tooltip-value {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n background: #fef3c7;\n color: #92400e;\n border-radius: 0.25rem;\n border: 1px solid #fde68a;\n}\n\n.vpg-tooltip-more {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n color: #64748b;\n font-style: italic;\n}\n\n.vpg-tooltip-summary {\n padding: 0.5rem 0.75rem;\n font-size: 0.625rem;\n color: #64748b;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n text-align: center;\n}\n\n.vpg-font-size-toggle {\n display: flex;\n background: white;\n border-radius: 0.25rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n}\n\n.vpg-font-size-btn {\n padding: 0.125rem 0.5rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-font-size-btn:hover {\n background: #f1f5f9;\n}\n\n.vpg-font-size-btn.active {\n background: #10b981;\n color: white;\n}\n\n/* Pro Required */\n.vpg-pro-required {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n}\n\n.vpg-pro-content {\n text-align: center;\n padding: 2rem;\n}\n\n.vpg-pro-icon {\n width: 3rem;\n height: 3rem;\n color: #d97706;\n margin: 0 auto 1rem;\n}\n\n.vpg-pro-content h3 {\n font-size: 1.25rem;\n font-weight: 600;\n color: #92400e;\n margin-bottom: 0.5rem;\n}\n\n.vpg-pro-content p {\n font-size: 0.875rem;\n color: #a16207;\n margin-bottom: 1rem;\n}\n\n.vpg-pro-link {\n display: inline-block;\n padding: 0.5rem 1rem;\n background: #f59e0b;\n color: white;\n font-weight: 500;\n border-radius: 0.375rem;\n text-decoration: none;\n transition: background 0.15s;\n}\n\n.vpg-pro-link:hover {\n background: #d97706;\n}\n\n/* Config Bar */\n.vpg-config-bar {\n display: flex;\n align-items: stretch;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-drop-zone {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n border-radius: 0.5rem;\n border: 2px dashed;\n transition: all 0.15s;\n}\n\n.vpg-drop-zone.vpg-row-zone {\n background: rgba(238, 242, 255, 0.5);\n border-color: #c7d2fe;\n}\n\n.vpg-drop-zone.vpg-column-zone {\n background: rgba(245, 243, 255, 0.5);\n border-color: #ddd6fe;\n flex: 1;\n}\n\n.vpg-drop-zone.vpg-value-zone {\n background: rgba(236, 253, 245, 0.5);\n border-color: #a7f3d0;\n}\n\n.vpg-drop-zone.vpg-drag-over {\n border-style: solid;\n box-shadow: 0 0 0 2px currentColor inset;\n}\n\n.vpg-drop-zone.vpg-row-zone.vpg-drag-over {\n background: #eef2ff;\n border-color: #818cf8;\n}\n\n.vpg-drop-zone.vpg-column-zone.vpg-drag-over {\n background: #f5f3ff;\n border-color: #a78bfa;\n}\n\n.vpg-drop-zone.vpg-value-zone.vpg-drag-over {\n background: #ecfdf5;\n border-color: #34d399;\n}\n\n.vpg-zone-header {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n flex-shrink: 0;\n}\n\n.vpg-zone-icon {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 700;\n border-radius: 0.25rem;\n}\n\n.vpg-zone-icon.vpg-row-icon {\n background: #c7d2fe;\n color: #4338ca;\n}\n\n.vpg-zone-icon.vpg-column-icon {\n background: #ddd6fe;\n color: #7c3aed;\n}\n\n.vpg-zone-icon.vpg-value-icon {\n background: #a7f3d0;\n color: #059669;\n}\n\n.vpg-zone-label {\n font-size: 0.625rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-row-zone .vpg-zone-label {\n color: #4f46e5;\n}\n\n.vpg-column-zone .vpg-zone-label {\n color: #7c3aed;\n}\n\n.vpg-value-zone .vpg-zone-label {\n color: #059669;\n}\n\n.vpg-zone-chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-zone-hint {\n font-size: 0.625rem;\n color: #94a3b8;\n font-style: italic;\n}\n\n.vpg-mini-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n font-weight: 500;\n max-width: 100%;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n cursor: grab;\n transition: all 0.15s ease;\n}\n\n.vpg-mini-chip:active {\n cursor: grabbing;\n}\n\n.vpg-drag-handle {\n opacity: 0.3;\n font-size: 0.625rem;\n letter-spacing: -0.1em;\n margin-right: 0.125rem;\n cursor: grab;\n flex-shrink: 0;\n}\n\n.vpg-mini-chip:hover .vpg-drag-handle {\n opacity: 0.6;\n}\n\n.vpg-mini-chip.vpg-chip-dragging {\n opacity: 0.4;\n transform: scale(0.95);\n}\n\n.vpg-mini-chip.vpg-chip-drop-target {\n transform: translateX(4px);\n box-shadow: -3px 0 0 0 currentColor, 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-mini-chip.vpg-row-chip {\n background: white;\n color: #4338ca;\n border: 1px solid #c7d2fe;\n}\n\n.vpg-mini-chip.vpg-column-chip {\n background: white;\n color: #7c3aed;\n border: 1px solid #ddd6fe;\n}\n\n.vpg-mini-chip.vpg-value-chip {\n background: white;\n color: #059669;\n border: 1px solid #a7f3d0;\n}\n\n.vpg-mini-chip.vpg-value-chip.vpg-calc-chip {\n background: #fdf4ff;\n color: #86198f;\n border-color: #f0abfc;\n}\n\n.vpg-mini-chip.vpg-value-chip.vpg-calc-chip .vpg-agg-symbol {\n background: #f0abfc;\n color: #86198f;\n}\n\n.vpg-mini-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.vpg-mini-remove {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n line-height: 1;\n opacity: 0.4;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-mini-remove:hover {\n opacity: 1;\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-agg-symbol {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n background: #d1fae5;\n color: #059669;\n border-radius: 0.25rem;\n flex-shrink: 0;\n}\n\n/* Placeholder */\n.vpg-placeholder {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #f8fafc, white, rgba(236, 253, 245, 0.3));\n border-top: 1px solid #f1f5f9;\n}\n\n.vpg-placeholder-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n text-align: center;\n padding: 2rem;\n}\n\n.vpg-placeholder-icon {\n width: 4rem;\n height: 4rem;\n color: #cbd5e1;\n}\n\n.vpg-placeholder-text {\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-placeholder-text strong {\n color: #334155;\n font-weight: 600;\n}\n\n/* Table */\n.vpg-table-container {\n flex: 1;\n overflow: auto;\n max-height: 100%;\n isolation: isolate;\n}\n\n.vpg-pivot-table {\n border-collapse: collapse;\n table-layout: fixed;\n min-width: max-content;\n}\n\n.vpg-pivot-table thead {\n position: sticky;\n top: 0;\n z-index: 30;\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);\n}\n\n.vpg-column-header-row {\n background: #f8fafc;\n}\n\n.vpg-column-header-row th {\n background: #f8fafc;\n}\n\n.vpg-row-header-label {\n position: sticky;\n /* left is set dynamically via inline style for multi-column row headers */\n z-index: 30;\n padding: 0.5rem 0.75rem;\n text-align: left;\n font-size: 0.625rem;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n background: #f8fafc;\n cursor: pointer;\n}\n\n.vpg-row-header-label + .vpg-row-header-label {\n border-left: 1px solid #e2e8f0;\n}\n\n.vpg-row-header-label:hover {\n background: #f1f5f9;\n}\n\n.vpg-column-header-cell {\n padding: 0.5rem 0.75rem;\n text-align: center;\n font-size: 0.6875rem;\n font-weight: 600;\n color: #334155;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n white-space: nowrap;\n background: #f8fafc;\n cursor: pointer;\n}\n\n.vpg-column-header-cell:hover {\n background: #f1f5f9;\n}\n\n.vpg-header-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n}\n\n.vpg-sort-indicator {\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n font-size: 0.75rem;\n}\n\n.vpg-sort-indicator.active {\n color: #4f46e5;\n font-weight: 700;\n}\n\n.vpg-total-header {\n padding: 0.5rem;\n text-align: center;\n font-size: 0.6875rem;\n font-weight: 700;\n color: #92400e;\n border-bottom: 1px solid #cbd5e1;\n border-left: 2px solid #f59e0b;\n background: #fde68a;\n vertical-align: middle;\n}\n\n.vpg-data-row:hover {\n background: #ecfdf5;\n}\n\n.vpg-data-row:nth-child(even) {\n background: #f8fafc;\n}\n\n.vpg-row-header-cell {\n position: sticky;\n /* left is set dynamically via inline style for multi-column row headers */\n padding: 0.5rem 0.75rem;\n text-align: left;\n font-size: 0.75rem;\n font-weight: 500;\n color: #334155;\n background: white;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n white-space: nowrap;\n z-index: 10;\n}\n\n.vpg-data-row:nth-child(even) .vpg-row-header-cell {\n background: #f8fafc;\n}\n\n/* Row header cells now render as separate columns */\n.vpg-row-header-cell + .vpg-row-header-cell {\n border-left: 1px solid #e2e8f0;\n}\n\n.vpg-data-cell {\n padding: 0.5rem 0.75rem;\n text-align: right;\n font-size: 0.75rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: #334155;\n font-variant-numeric: tabular-nums;\n border-bottom: 1px solid #f1f5f9;\n border-right: 1px solid #f8fafc;\n cursor: cell;\n white-space: nowrap;\n}\n\n.vpg-data-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(16, 185, 129, 0.4);\n}\n\n.vpg-data-cell.selected {\n background: #d1fae5;\n box-shadow: inset 0 0 0 2px #10b981;\n}\n\n.vpg-data-cell.vpg-is-null {\n color: #cbd5e1;\n}\n\n.vpg-data-cell.vpg-total-cell {\n background: #fef3c7;\n font-weight: 600;\n color: #92400e;\n}\n\n.vpg-data-cell.vpg-grand-total-cell {\n background: #fde68a;\n font-weight: 700;\n color: #92400e;\n}\n\n.vpg-totals-row {\n background: #fef9e7;\n}\n\n.vpg-total-label {\n font-weight: 700;\n color: #92400e;\n background: #fef3c7;\n}\n\n/* Font sizes */\n.vpg-pivot-skeleton.vpg-font-xs .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-xs .vpg-row-header-cell {\n font-size: 0.75rem;\n padding: 0.375rem 0.75rem;\n}\n\n.vpg-pivot-skeleton.vpg-font-sm .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-sm .vpg-row-header-cell {\n font-size: 0.875rem;\n padding: 0.5rem 1rem;\n}\n\n.vpg-pivot-skeleton.vpg-font-base .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-base .vpg-row-header-cell {\n font-size: 1rem;\n padding: 0.625rem 1rem;\n}\n\n/* Footer */\n.vpg-skeleton-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n font-size: 0.75rem;\n color: #64748b;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-skeleton-footer .vpg-footer-info {\n color: #94a3b8;\n}\n\n.vpg-skeleton-footer .vpg-selection-stats {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.125rem 0.5rem;\n background: rgba(16, 185, 129, 0.08);\n border: 1px solid rgba(16, 185, 129, 0.15);\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n}\n\n.vpg-skeleton-footer .vpg-stat {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-skeleton-footer .vpg-stat-label {\n color: #64748b;\n font-weight: 400;\n}\n\n.vpg-skeleton-footer .vpg-stat-value {\n color: #10b981;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n}\n\n.vpg-skeleton-footer .vpg-stat-divider {\n color: #cbd5e1;\n}\n\n/* Watermark */\n.vpg-watermark {\n padding: 0.375rem 1rem;\n background: #f1f5f9;\n border-top: 1px solid #e2e8f0;\n text-align: center;\n flex-shrink: 0;\n}\n\n.vpg-watermark a {\n font-size: 0.625rem;\n color: #94a3b8;\n text-decoration: none;\n transition: color 0.15s;\n}\n\n.vpg-watermark a:hover {\n color: #64748b;\n}\n\n/* Demo Mode Banner */\n.vpg-watermark.vpg-demo-mode {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 0.5rem 1rem;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n border-top: 1px solid #fcd34d;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-demo-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.5rem;\n background: #f59e0b;\n color: white;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n letter-spacing: 0.05em;\n}\n\n.vpg-get-pro {\n font-weight: 600;\n color: #d97706 !important;\n}\n\n.vpg-get-pro:hover {\n color: #b45309 !important;\n text-decoration: underline;\n}\n\n/* Scrollbar */\n.vpg-table-container::-webkit-scrollbar {\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.vpg-table-container::-webkit-scrollbar-track {\n background: #f1f5f9;\n}\n\n.vpg-table-container::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 9999px;\n}\n\n.vpg-table-container::-webkit-scrollbar-thumb:hover {\n background: #94a3b8;\n}\n\n.vpg-table-container::-webkit-scrollbar-corner {\n background: #f1f5f9;\n}\n\n/* Toast notification */\n.vpg-pivot-skeleton .vpg-toast {\n position: absolute;\n top: 1rem;\n right: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #10b981;\n color: white;\n border-radius: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n z-index: 100;\n}\n\n.vpg-toast-enter-active,\n.vpg-toast-leave-active {\n transition: all 0.2s ease;\n}\n\n.vpg-toast-enter-from,\n.vpg-toast-leave-to {\n opacity: 0;\n transform: translateY(-0.5rem);\n}\n</style>\n\n<style>\n/* Dark Mode - PivotSkeleton */\n.vpg-theme-dark .vpg-pivot-skeleton {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-skeleton-header {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-skeleton-title {\n color: #94a3b8 !important;\n}\n\n/* Config bar (drop zones container) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-config-bar {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zones {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone {\n background: #1e293b !important;\n border-color: #475569 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone:hover {\n border-color: #64748b !important;\n background: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone.vpg-zone-active {\n border-color: #10b981 !important;\n background: rgba(16, 185, 129, 0.2) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-label {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-row .vpg-zone-label { color: #a5b4fc !important; }\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-column .vpg-zone-label { color: #c4b5fd !important; }\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-value .vpg-zone-label { color: #6ee7b7 !important; }\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-hint {\n color: #64748b !important;\n}\n\n/* Mini chips in drop zones */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-row-chip {\n background: #312e81 !important;\n color: #a5b4fc !important;\n border-color: #4338ca !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-column-chip {\n background: #4c1d95 !important;\n color: #c4b5fd !important;\n border-color: #7c3aed !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip {\n background: #064e3b !important;\n color: #6ee7b7 !important;\n border-color: #10b981 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip.vpg-calc-chip {\n background: rgba(168, 85, 247, 0.2) !important;\n color: #c4b5fd !important;\n border-color: rgba(168, 85, 247, 0.4) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip.vpg-calc-chip .vpg-agg-symbol {\n background: rgba(168, 85, 247, 0.4);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drag-handle {\n opacity: 0.4;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip:hover .vpg-drag-handle {\n opacity: 0.7;\n}\n\n/* Font size toggle (S M L) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-toggle {\n background: #1e293b !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn:hover {\n background: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn.active {\n background: #10b981 !important;\n color: white !important;\n}\n\n/* Summary badges (1 row, 1 col, 1 val) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-rows {\n background: rgba(99, 102, 241, 0.2) !important;\n color: #a5b4fc !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-cols {\n background: rgba(139, 92, 246, 0.2) !important;\n color: #c4b5fd !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-vals {\n background: rgba(16, 185, 129, 0.2) !important;\n color: #6ee7b7 !important;\n}\n\n/* Filter indicator - dark mode */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-indicator {\n background: linear-gradient(135deg, rgba(245, 158, 11, 0.2) 0%, rgba(217, 119, 6, 0.25) 100%) !important;\n border-color: #d97706 !important;\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-icon {\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-text strong {\n color: #fcd34d !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-count {\n color: #fbbf24 !important;\n}\n\n/* Filter tooltip - dark mode */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-tooltip {\n background: #1e293b !important;\n border-color: #475569 !important;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.3);\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-header {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-filter {\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-column {\n color: #e2e8f0 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-value {\n background: rgba(245, 158, 11, 0.2) !important;\n color: #fbbf24 !important;\n border-color: rgba(245, 158, 11, 0.4) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-more {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-summary {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-table {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-table thead {\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.3);\n}\n\n.vpg-theme-dark .vpg-column-header-row {\n background: #0f172a !important;\n}\n\n.vpg-theme-dark .vpg-column-header-row th {\n background: #0f172a !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-column-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-corner-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-label {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #e2e8f0 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-label:hover,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-column-header-cell:hover {\n background: #1e293b !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-cell {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell {\n background: #1e293b;\n border-color: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(52, 211, 153, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.selected {\n background: rgba(16, 185, 129, 0.2);\n box-shadow: inset 0 0 0 2px #34d399;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:nth-child(even) .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:nth-child(even) .vpg-data-cell {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:hover .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:hover .vpg-data-cell {\n background: #334155;\n}\n\n/* Total header column */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-total-header {\n background: #451a03 !important;\n color: #fbbf24 !important;\n border-color: #334155 !important;\n}\n\n/* Total cells in rows - consistent color */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.vpg-total-cell {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n/* Grand total cell */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.vpg-grand-total-cell {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n/* Totals row - consistent color */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row {\n background: transparent !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row .vpg-data-cell {\n background: #451a03 !important;\n}\n\n/* Total label */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-total-label {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-empty-state {\n background: #0f172a;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer {\n background: #0f172a;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-footer-info {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-selection-stats {\n background: rgba(16, 185, 129, 0.1);\n border-color: rgba(16, 185, 129, 0.2);\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-value {\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-divider {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-demo-bar {\n background: rgba(245, 158, 11, 0.15);\n border-color: rgba(245, 158, 11, 0.3);\n color: #fbbf24;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-track {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-thumb {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-thumb:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-corner {\n background: #0f172a;\n}\n\n/* Dark mode - Placeholder */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder {\n background: linear-gradient(135deg, #1e293b, #0f172a, rgba(16, 185, 129, 0.05));\n border-top-color: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-icon {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-text {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-text strong {\n color: #e2e8f0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type {\n AIAnalystConfig,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIErrorEvent,\n AIQueryExecutedEvent,\n CalculatedField,\n ChartConfig,\n DateFormat,\n NumberFormat,\n} from '@smallwebco/tinypivot-core'\nimport { formatDate as coreFormatDate, formatNumber as coreFormatNumber, loadCalculatedFields, saveCalculatedFields } from '@smallwebco/tinypivot-core'\n/**\n * TinyPivot - Main DataGrid Component\n * Excel-like data grid with optional pivot table functionality\n */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useExcelGrid } from '../composables/useExcelGrid'\nimport {\n copyToClipboard,\n exportPivotToCSV,\n exportToCSV,\n formatSelectionForClipboard,\n} from '../composables/useGridFeatures'\nimport { useLicense } from '../composables/useLicense'\nimport { usePivotTable } from '../composables/usePivotTable'\nimport AIAnalyst from './AIAnalyst.vue'\nimport ChartBuilder from './ChartBuilder.vue'\nimport ColumnFilter from './ColumnFilter.vue'\nimport PivotConfig from './PivotConfig.vue'\nimport PivotSkeleton from './PivotSkeleton.vue'\n\nconst props = withDefaults(defineProps<{\n data: Record<string, unknown>[]\n loading?: boolean\n rowHeight?: number\n headerHeight?: number\n fontSize?: 'xs' | 'sm' | 'base'\n showPivot?: boolean\n // Feature props\n enableExport?: boolean\n enableSearch?: boolean\n enablePagination?: boolean\n pageSize?: number\n enableColumnResize?: boolean\n enableClipboard?: boolean\n theme?: 'light' | 'dark' | 'auto'\n stripedRows?: boolean\n exportFilename?: string\n enableVerticalResize?: boolean\n initialHeight?: number\n minHeight?: number\n maxHeight?: number\n /** AI Data Analyst configuration (Pro feature, disabled by default) */\n aiAnalyst?: AIAnalystConfig\n /** Number display format */\n numberFormat?: NumberFormat\n /** Date display format */\n dateFormat?: DateFormat\n}>(), {\n loading: false,\n rowHeight: 36,\n headerHeight: 40,\n fontSize: 'xs',\n showPivot: true,\n // Feature defaults\n enableExport: true,\n enableSearch: true,\n enablePagination: false,\n pageSize: 50,\n enableColumnResize: true,\n enableClipboard: true,\n theme: 'light',\n stripedRows: true,\n exportFilename: 'data-export.csv',\n enableVerticalResize: true,\n initialHeight: 600,\n minHeight: 300,\n maxHeight: 1200,\n aiAnalyst: undefined,\n numberFormat: 'us',\n dateFormat: 'iso',\n})\n\nconst emit = defineEmits<{\n (e: 'cellClick', payload: { row: number, col: number, value: unknown, rowData: Record<string, unknown> }): void\n (e: 'selectionChange', payload: { cells: Array<{ row: number, col: number }>, values: unknown[] }): void\n (e: 'export', payload: { rowCount: number, filename: string }): void\n (e: 'copy', payload: { text: string, cellCount: number }): void\n // AI Analyst events\n (e: 'aiDataLoaded', payload: AIDataLoadedEvent): void\n (e: 'aiConversationUpdate', payload: AIConversationUpdateEvent): void\n (e: 'aiQueryExecuted', payload: AIQueryExecutedEvent): void\n (e: 'aiError', payload: AIErrorEvent): void\n}>()\n\nconst { showWatermark, canUsePivot, canUseCharts, canUseAIAnalyst, isDemo, isPro } = useLicense()\n\n// Check if AI Analyst should be shown (enabled in config + licensed)\nconst showAIAnalyst = computed(() =>\n props.aiAnalyst?.enabled && canUseAIAnalyst.value,\n)\n\n// Theme handling\nconst currentTheme = computed(() => {\n if (props.theme === 'auto') {\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n }\n return props.theme\n})\n\n// Font size state\nconst currentFontSize = ref(props.fontSize)\n\n// Global search state\nconst globalSearchTerm = ref('')\nconst showSearchInput = ref(false)\n\n// Pagination state\nconst currentPage = ref(1)\n\n// Column resize state\nconst resizingColumnId = ref<string | null>(null)\nconst resizeStartX = ref(0)\nconst resizeStartWidth = ref(0)\n\n// Vertical resize state\nconst gridHeight = ref(props.initialHeight)\nconst isResizingVertically = ref(false)\nconst verticalResizeStartY = ref(0)\nconst verticalResizeStartHeight = ref(0)\n\n// Clipboard toast state\nconst showCopyToast = ref(false)\nconst copyToastMessage = ref('')\nconst fontSizeOptions = [\n { value: 'xs', label: 'S' },\n { value: 'sm', label: 'M' },\n { value: 'base', label: 'L' },\n] as const\n\n// AI Analyst component ref (for accessing loadFullData)\nconst aiAnalystRef = ref<InstanceType<typeof AIAnalyst> | null>(null)\n\n// AI-loaded data (replaces current data when AI loads results)\n// Must be defined before displayData and dataRef\nconst aiLoadedData = ref<Record<string, unknown>[] | null>(null)\n\n// Data to display - AI loaded data takes precedence\nconst displayData = computed(() => aiLoadedData.value || props.data)\n\n// Grid composable - uses displayData which may be AI-loaded or original props.data\nconst dataRef = computed(() => displayData.value)\nconst {\n table,\n columnKeys,\n filteredRowCount,\n totalRowCount,\n getColumnStats,\n hasActiveFilter,\n setColumnFilter,\n getColumnFilterValues,\n clearAllFilters,\n toggleSort,\n getSortDirection,\n columnFilters,\n activeFilters,\n // Numeric range filters\n setNumericRangeFilter,\n getNumericRangeFilter,\n // Date range filters\n setDateRangeFilter,\n getDateRangeFilter,\n} = useExcelGrid({ data: dataRef })\n\n// Filtered data for pivot table (respects column filters)\nconst filteredDataForPivot = computed(() => {\n const filteredRows = table.getFilteredRowModel().rows\n return filteredRows.map(row => row.original)\n})\n\n// Active filters info for display - use activeFilters from useExcelGrid\nconst activeFilterInfo = computed(() => {\n if (activeFilters.value.length === 0)\n return null\n return activeFilters.value.map((f) => {\n if (f.type === 'range' && f.range) {\n // Format range filter display\n const parts = []\n if (f.range.min !== null)\n parts.push(`≥ ${f.range.min}`)\n if (f.range.max !== null)\n parts.push(`≤ ${f.range.max}`)\n return {\n column: f.column,\n valueCount: 1,\n displayText: parts.join(' and '),\n isRange: true,\n }\n }\n if (f.type === 'dateRange' && f.dateRange) {\n // Format date range filter display\n const parts = []\n if (f.dateRange.min !== null)\n parts.push(`from ${coreFormatDate(f.dateRange.min, props.dateFormat)}`)\n if (f.dateRange.max !== null)\n parts.push(`to ${coreFormatDate(f.dateRange.max, props.dateFormat)}`)\n return {\n column: f.column,\n valueCount: 1,\n displayText: parts.join(' '),\n isRange: true,\n }\n }\n return {\n column: f.column,\n valueCount: f.values?.length || 0,\n values: f.values || [],\n isRange: false,\n }\n })\n})\n\n// Pivot table composable - uses filtered data\nconst {\n rowFields: pivotRowFields,\n columnFields: pivotColumnFields,\n valueFields: pivotValueFields,\n showRowTotals: pivotShowRowTotals,\n showColumnTotals: pivotShowColumnTotals,\n availableFields: pivotAvailableFields,\n isConfigured: pivotIsConfigured,\n pivotResult,\n addRowField,\n removeRowField,\n addColumnField,\n removeColumnField,\n addValueField,\n removeValueField,\n updateValueFieldAggregation,\n clearConfig: clearPivotConfig,\n autoSuggestConfig: _autoSuggestConfig,\n} = usePivotTable(filteredDataForPivot)\n\n// Filtered data based on global search\nconst searchFilteredData = computed(() => {\n if (!globalSearchTerm.value.trim() || !props.enableSearch) {\n return rows.value\n }\n const term = globalSearchTerm.value.toLowerCase().trim()\n return rows.value.filter((row) => {\n for (const col of columnKeys.value) {\n const value = row.original[col]\n if (value === null || value === undefined)\n continue\n if (String(value).toLowerCase().includes(term)) {\n return true\n }\n }\n return false\n })\n})\n\n// Paginated rows\nconst totalSearchedRows = computed(() => searchFilteredData.value.length)\nconst totalPages = computed(() => {\n if (!props.enablePagination)\n return 1\n return Math.max(1, Math.ceil(totalSearchedRows.value / props.pageSize))\n})\n\nconst paginatedRows = computed(() => {\n if (!props.enablePagination)\n return searchFilteredData.value\n const start = (currentPage.value - 1) * props.pageSize\n const end = start + props.pageSize\n return searchFilteredData.value.slice(start, end)\n})\n\nconst paginationStart = computed(() => {\n if (totalSearchedRows.value === 0)\n return 0\n return (currentPage.value - 1) * props.pageSize + 1\n})\n\nconst paginationEnd = computed(() =>\n Math.min(currentPage.value * props.pageSize, totalSearchedRows.value),\n)\n\nfunction nextPage() {\n if (currentPage.value < totalPages.value)\n currentPage.value++\n}\n\nfunction prevPage() {\n if (currentPage.value > 1)\n currentPage.value--\n}\n\n// Reset to page 1 when filters or search changes\nwatch([columnFilters, globalSearchTerm], () => {\n currentPage.value = 1\n})\n\n// Export functionality\nfunction handleExport() {\n if (viewMode.value === 'pivot') {\n handlePivotExport()\n return\n }\n\n const dataToExport = props.enableSearch && globalSearchTerm.value.trim()\n ? searchFilteredData.value.map(row => row.original)\n : rows.value.map(row => row.original)\n\n exportToCSV(dataToExport, columnKeys.value, {\n filename: props.exportFilename,\n includeHeaders: true,\n })\n\n emit('export', { rowCount: dataToExport.length, filename: props.exportFilename })\n}\n\nfunction handlePivotExport() {\n if (!pivotResult.value)\n return\n\n const pivotFilename = props.exportFilename.replace('.csv', '-pivot.csv')\n\n exportPivotToCSV(\n {\n headers: pivotResult.value.headers,\n rowHeaders: pivotResult.value.rowHeaders,\n data: pivotResult.value.data,\n rowTotals: pivotResult.value.rowTotals,\n columnTotals: pivotResult.value.columnTotals,\n grandTotal: pivotResult.value.grandTotal,\n showRowTotals: pivotShowRowTotals.value,\n showColumnTotals: pivotShowColumnTotals.value,\n },\n pivotRowFields.value,\n pivotColumnFields.value,\n pivotValueFields.value,\n { filename: pivotFilename },\n )\n\n const rowCount = pivotResult.value.rowHeaders.length\n emit('export', { rowCount, filename: pivotFilename })\n}\n\n// Column resize methods\nfunction startColumnResize(columnId: string, event: MouseEvent) {\n if (!props.enableColumnResize)\n return\n event.preventDefault()\n event.stopPropagation()\n\n resizingColumnId.value = columnId\n resizeStartX.value = event.clientX\n resizeStartWidth.value = columnWidths.value[columnId] || MIN_COL_WIDTH\n\n document.addEventListener('mousemove', handleResizeMove)\n document.addEventListener('mouseup', handleResizeEnd)\n}\n\nfunction handleResizeMove(event: MouseEvent) {\n if (!resizingColumnId.value)\n return\n const diff = event.clientX - resizeStartX.value\n const newWidth = Math.max(MIN_COL_WIDTH, Math.min(MAX_COL_WIDTH, resizeStartWidth.value + diff))\n columnWidths.value = {\n ...columnWidths.value,\n [resizingColumnId.value]: newWidth,\n }\n}\n\nfunction handleResizeEnd() {\n resizingColumnId.value = null\n document.removeEventListener('mousemove', handleResizeMove)\n document.removeEventListener('mouseup', handleResizeEnd)\n}\n\n// Vertical resize methods\nfunction startVerticalResize(event: MouseEvent) {\n if (!props.enableVerticalResize)\n return\n event.preventDefault()\n\n isResizingVertically.value = true\n verticalResizeStartY.value = event.clientY\n verticalResizeStartHeight.value = gridHeight.value\n\n document.addEventListener('mousemove', handleVerticalResizeMove)\n document.addEventListener('mouseup', handleVerticalResizeEnd)\n}\n\nfunction handleVerticalResizeMove(event: MouseEvent) {\n if (!isResizingVertically.value)\n return\n const diff = event.clientY - verticalResizeStartY.value\n const newHeight = Math.max(\n props.minHeight,\n Math.min(props.maxHeight, verticalResizeStartHeight.value + diff),\n )\n gridHeight.value = newHeight\n}\n\nfunction handleVerticalResizeEnd() {\n isResizingVertically.value = false\n document.removeEventListener('mousemove', handleVerticalResizeMove)\n document.removeEventListener('mouseup', handleVerticalResizeEnd)\n}\n\n// Clipboard methods\nfunction copySelectionToClipboard() {\n if (!selectionBounds.value || !props.enableClipboard)\n return\n\n const text = formatSelectionForClipboard(\n rows.value.map(r => r.original),\n columnKeys.value,\n selectionBounds.value,\n )\n\n copyToClipboard(\n text,\n () => {\n const cellCount\n = (selectionBounds.value!.maxRow - selectionBounds.value!.minRow + 1)\n * (selectionBounds.value!.maxCol - selectionBounds.value!.minCol + 1)\n copyToastMessage.value = `Copied ${cellCount} cell${cellCount > 1 ? 's' : ''}`\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n emit('copy', { text, cellCount })\n },\n (err) => {\n copyToastMessage.value = 'Copy failed'\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n console.error('Copy failed:', err)\n },\n )\n}\n\n// View mode\nconst viewMode = ref<'ai' | 'grid' | 'pivot' | 'chart'>('grid')\n\nfunction handleAIDataLoaded(payload: AIDataLoadedEvent) {\n aiLoadedData.value = payload.data\n // Don't auto-switch to grid - let user decide when to view results\n emit('aiDataLoaded', payload)\n}\n\n// Track if we're showing AI-shaped data (filtered/aggregated by AI queries)\nconst isShowingAIData = computed(() => aiLoadedData.value !== null)\n\n// Loading state for full data reset\nconst isLoadingFullData = ref(false)\n\n// Reset to full original dataset\n// If AI Analyst is enabled and has a selected data source, load full data from that source\n// Otherwise, just clear the AI loaded data to show original props.data\nasync function resetToFullData() {\n // If we have AI Analyst with a selected data source, load full data from it\n if (aiAnalystRef.value?.selectedDataSource) {\n isLoadingFullData.value = true\n try {\n const fullData = await aiAnalystRef.value.loadFullData()\n if (fullData && fullData.length > 0) {\n aiLoadedData.value = fullData\n }\n else {\n // Fall back to props.data if loading fails\n aiLoadedData.value = null\n }\n }\n catch (err) {\n console.warn('Failed to load full data:', err)\n aiLoadedData.value = null\n }\n finally {\n isLoadingFullData.value = false\n }\n }\n else {\n // No AI Analyst or no selected data source - just clear filters by resetting to props.data\n aiLoadedData.value = null\n }\n // Also clear any grid filters\n clearAllFilters()\n}\n\nfunction handleAIConversationUpdate(payload: AIConversationUpdateEvent) {\n emit('aiConversationUpdate', payload)\n}\n\nfunction handleAIQueryExecuted(payload: AIQueryExecutedEvent) {\n emit('aiQueryExecuted', payload)\n}\n\nfunction handleAIError(payload: AIErrorEvent) {\n emit('aiError', payload)\n}\n\nfunction handleAIViewResults(payload: { data: Record<string, unknown>[], query: string }) {\n aiLoadedData.value = payload.data\n viewMode.value = 'grid' // Switch to grid to show the results\n}\nconst chartConfig = ref<ChartConfig | null>(null)\n\nfunction handleChartConfigChange(config: ChartConfig) {\n chartConfig.value = config\n}\nconst showPivotConfig = ref(true)\nconst draggingField = ref<string | null>(null)\n\n// Calculated fields state (persisted to localStorage)\nconst calculatedFields = ref<CalculatedField[]>(loadCalculatedFields())\n\nfunction handleAddCalculatedField(field: CalculatedField) {\n // Generate ID if not present\n if (!field.id) {\n field.id = `calc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n }\n calculatedFields.value = [...calculatedFields.value, field]\n saveCalculatedFields(calculatedFields.value)\n}\n\nfunction handleRemoveCalculatedField(id: string) {\n calculatedFields.value = calculatedFields.value.filter(f => f.id !== id)\n saveCalculatedFields(calculatedFields.value)\n // Also remove from valueFields if it was assigned\n const calcFieldKey = `calc:${id}`\n const existing = pivotValueFields.value.find(v => v.field === calcFieldKey)\n if (existing) {\n removeValueField(calcFieldKey, existing.aggregation)\n }\n}\n\nfunction handleUpdateCalculatedField(field: CalculatedField) {\n calculatedFields.value = calculatedFields.value.map(f => f.id === field.id ? field : f)\n saveCalculatedFields(calculatedFields.value)\n}\n\nfunction handlePivotDragStart(field: string) {\n draggingField.value = field\n}\n\nfunction handlePivotDragEnd() {\n draggingField.value = null\n}\n\nfunction reorderRowFields(fields: string[]) {\n pivotRowFields.value = fields\n}\n\nfunction reorderColumnFields(fields: string[]) {\n pivotColumnFields.value = fields\n}\n\n// Container refs\nconst tableContainerRef = ref<HTMLDivElement>()\nconst tableBodyRef = ref<HTMLDivElement>()\n\n// Rows\nconst rows = computed(() => table.getRowModel().rows)\n\n// Column filter dropdown state\nconst activeFilterColumn = ref<string | null>(null)\nconst filterDropdownPosition = ref({ top: 0, left: 0, maxHeight: 400 })\n\n// Column widths\nconst columnWidths = ref<Record<string, number>>({})\nconst MIN_COL_WIDTH = 120\nconst MAX_COL_WIDTH = 350\n\nfunction calculateColumnWidths() {\n // Skip during SSR (no document available)\n if (typeof document === 'undefined')\n return\n\n if (displayData.value.length === 0)\n return\n\n const widths: Record<string, number> = {}\n const sampleSize = Math.min(100, displayData.value.length)\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx)\n return\n\n ctx.font = '13px system-ui, -apple-system, sans-serif'\n\n for (const key of columnKeys.value) {\n let maxWidth = ctx.measureText(key).width + 56\n\n for (let i = 0; i < sampleSize; i++) {\n const value = displayData.value[i][key]\n const text = value === null || value === undefined ? '' : String(value)\n const width = ctx.measureText(text).width + 28\n maxWidth = Math.max(maxWidth, width)\n }\n\n widths[key] = Math.min(Math.max(maxWidth, MIN_COL_WIDTH), MAX_COL_WIDTH)\n }\n\n columnWidths.value = widths\n}\n\nfunction openFilterDropdown(columnId: string, event: MouseEvent) {\n event.stopPropagation()\n const target = event.currentTarget as HTMLElement\n const headerCell = target.closest('.vpg-header-cell') as HTMLElement\n const rect = headerCell?.getBoundingClientRect() || target.getBoundingClientRect()\n\n const dropdownWidth = 280\n const padding = 12\n\n let left = rect.left\n if (left + dropdownWidth > window.innerWidth - padding) {\n left = window.innerWidth - dropdownWidth - padding\n }\n left = Math.max(padding, left)\n\n const spaceBelow = window.innerHeight - rect.bottom - padding\n const spaceAbove = rect.top - padding\n\n let top: number\n let maxHeight: number\n\n if (spaceBelow >= 300 || spaceBelow >= spaceAbove) {\n top = rect.bottom + 4\n maxHeight = Math.min(400, spaceBelow - 4)\n }\n else {\n maxHeight = Math.min(400, spaceAbove - 4)\n top = rect.top - maxHeight - 4\n }\n\n filterDropdownPosition.value = { top, left, maxHeight }\n activeFilterColumn.value = columnId\n}\n\nfunction closeFilterDropdown() {\n activeFilterColumn.value = null\n}\n\nfunction handleFilter(columnId: string, values: string[]) {\n setColumnFilter(columnId, values)\n}\n\nfunction handleRangeFilter(columnId: string, range: import('@smallwebco/tinypivot-core').NumericRange | null) {\n setNumericRangeFilter(columnId, range)\n}\n\nfunction handleDateRangeFilter(columnId: string, range: import('@smallwebco/tinypivot-core').DateRange | null) {\n setDateRangeFilter(columnId, range)\n}\n\nfunction handleSort(columnId: string, direction: 'asc' | 'desc' | null) {\n if (direction === null) {\n const current = getSortDirection(columnId)\n if (current) {\n toggleSort(columnId)\n if (getSortDirection(columnId)) {\n toggleSort(columnId)\n }\n }\n }\n else {\n const current = getSortDirection(columnId)\n if (current === null) {\n toggleSort(columnId)\n if (direction === 'desc' && getSortDirection(columnId) === 'asc') {\n toggleSort(columnId)\n }\n }\n else if (current !== direction) {\n toggleSort(columnId)\n }\n }\n}\n\nconst activeFilterCount = computed(() => columnFilters.value.length)\n\n// Selection state\nconst selectedCell = ref<{ row: number, col: number } | null>(null)\nconst selectionStart = ref<{ row: number, col: number } | null>(null)\nconst selectionEnd = ref<{ row: number, col: number } | null>(null)\nconst isSelecting = ref(false)\n\nfunction selectColumn(colIndex: number) {\n const maxRow = rows.value.length - 1\n if (maxRow < 0)\n return\n\n selectionStart.value = { row: 0, col: colIndex }\n selectionEnd.value = { row: maxRow, col: colIndex }\n selectedCell.value = { row: 0, col: colIndex }\n}\n\nfunction handleHeaderClick(colIndex: number, event: MouseEvent) {\n const target = event.target as HTMLElement\n if (target.closest('.vpg-dropdown-arrow')) {\n const colId = columnKeys.value[colIndex]\n openFilterDropdown(colId, event)\n }\n else {\n selectColumn(colIndex)\n }\n}\n\nconst selectionBounds = computed(() => {\n if (!selectionStart.value || !selectionEnd.value)\n return null\n return {\n minRow: Math.min(selectionStart.value.row, selectionEnd.value.row),\n maxRow: Math.max(selectionStart.value.row, selectionEnd.value.row),\n minCol: Math.min(selectionStart.value.col, selectionEnd.value.col),\n maxCol: Math.max(selectionStart.value.col, selectionEnd.value.col),\n }\n})\n\nfunction isCellInSelection(rowIndex: number, colIndex: number): boolean {\n if (!selectionBounds.value)\n return false\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n return rowIndex >= minRow && rowIndex <= maxRow && colIndex >= minCol && colIndex <= maxCol\n}\n\nconst selectionStats = computed(() => {\n if (!selectionBounds.value)\n return null\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n\n const values: number[] = []\n let count = 0\n\n for (let r = minRow; r <= maxRow; r++) {\n const row = rows.value[r]\n if (!row)\n continue\n\n for (let c = minCol; c <= maxCol; c++) {\n const colId = columnKeys.value[c]\n if (!colId)\n continue\n\n const value = row.original[colId]\n count++\n\n if (value !== null && value !== undefined && value !== '') {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value))\n if (!Number.isNaN(num)) {\n values.push(num)\n }\n }\n }\n }\n\n if (values.length === 0)\n return { count, sum: null, avg: null, numericCount: 0 }\n\n const sum = values.reduce((a, b) => a + b, 0)\n const avg = sum / values.length\n\n return { count, sum, avg, numericCount: values.length }\n})\n\nfunction formatStatValue(value: number | null): string {\n if (value === null)\n return '-'\n return coreFormatNumber(value, props.numberFormat)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n // Handle Ctrl+C / Cmd+C for clipboard\n if ((event.ctrlKey || event.metaKey) && event.key === 'c' && selectionBounds.value) {\n event.preventDefault()\n copySelectionToClipboard()\n return\n }\n\n // Handle Ctrl+F / Cmd+F for search\n if ((event.ctrlKey || event.metaKey) && event.key === 'f' && props.enableSearch) {\n event.preventDefault()\n showSearchInput.value = true\n nextTick(() => {\n const input = document.querySelector('.vpg-search-input') as HTMLInputElement\n input?.focus()\n })\n return\n }\n\n if (!selectedCell.value)\n return\n if (activeFilterColumn.value)\n return\n\n const { row, col } = selectedCell.value\n const displayRows = paginatedRows.value\n const maxRow = displayRows.length - 1\n const maxCol = columnKeys.value.length - 1\n\n function updateSelection(newRow: number, newCol: number) {\n if (event.shiftKey) {\n if (!selectionStart.value) {\n selectionStart.value = { row, col }\n }\n selectionEnd.value = { row: newRow, col: newCol }\n }\n else {\n selectionStart.value = { row: newRow, col: newCol }\n selectionEnd.value = { row: newRow, col: newCol }\n }\n selectedCell.value = { row: newRow, col: newCol }\n scrollCellIntoView(newRow, newCol)\n }\n\n switch (event.key) {\n case 'ArrowUp':\n event.preventDefault()\n if (row > 0)\n updateSelection(row - 1, col)\n break\n case 'ArrowDown':\n event.preventDefault()\n if (row < maxRow)\n updateSelection(row + 1, col)\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (col > 0)\n updateSelection(row, col - 1)\n break\n case 'ArrowRight':\n event.preventDefault()\n if (col < maxCol)\n updateSelection(row, col + 1)\n break\n case 'Escape':\n selectedCell.value = null\n selectionStart.value = null\n selectionEnd.value = null\n showSearchInput.value = false\n globalSearchTerm.value = ''\n break\n }\n}\n\nfunction scrollCellIntoView(rowIndex: number, colIndex: number) {\n nextTick(() => {\n const cell = tableBodyRef.value?.querySelector(\n `[data-row=\"${rowIndex}\"][data-col=\"${colIndex}\"]`,\n )\n cell?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n })\n}\n\nfunction handleMouseDown(rowIndex: number, colIndex: number, event: MouseEvent) {\n event.preventDefault()\n\n if (event.shiftKey && selectedCell.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n else {\n selectedCell.value = { row: rowIndex, col: colIndex }\n selectionStart.value = { row: rowIndex, col: colIndex }\n selectionEnd.value = { row: rowIndex, col: colIndex }\n isSelecting.value = true\n }\n\n // Emit event\n const row = rows.value[rowIndex]\n if (row) {\n const colId = columnKeys.value[colIndex]\n emit('cellClick', {\n row: rowIndex,\n col: colIndex,\n value: row.original[colId],\n rowData: row.original,\n })\n }\n}\n\nfunction handleMouseEnter(rowIndex: number, colIndex: number) {\n if (isSelecting.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n}\n\nfunction handleMouseUp() {\n isSelecting.value = false\n}\n\nfunction isCellSelected(rowIndex: number, colIndex: number): boolean {\n if (isCellInSelection(rowIndex, colIndex))\n return true\n return selectedCell.value?.row === rowIndex && selectedCell.value?.col === colIndex\n}\n\n// Format cell value\nconst noFormatPatterns = /^(?:.*_)?(?:id|code|year|month|quarter|day|week|date|zip|phone|fax|ssn|ein|npi|ndc|gpi|hcpcs|icd|cpt|rx|bin|pcn|group|member|claim|rx_number|script|fill)(?:_.*)?$/i\n\nfunction shouldFormatNumber(columnId: string): boolean {\n return !noFormatPatterns.test(columnId)\n}\n\nfunction formatCellValue(value: unknown, columnId: string): string {\n if (value === null || value === undefined)\n return ''\n if (value === '')\n return ''\n\n const stats = getColumnStats(columnId)\n\n if (stats.type === 'date') {\n return coreFormatDate(value, props.dateFormat)\n }\n\n if (stats.type === 'number') {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value))\n if (Number.isNaN(num))\n return String(value)\n\n if (shouldFormatNumber(columnId) && Math.abs(num) >= 1000) {\n return coreFormatNumber(num, props.numberFormat)\n }\n\n if (Number.isInteger(num)) {\n return String(num)\n }\n return coreFormatNumber(num, props.numberFormat, { maximumFractionDigits: 4 })\n }\n\n return String(value)\n}\n\nfunction handleTableScroll() {\n if (activeFilterColumn.value) {\n closeFilterDropdown()\n }\n}\n\nfunction handleWindowScroll(event: Event) {\n if (activeFilterColumn.value) {\n const target = event.target as HTMLElement\n if (target && target.closest?.('.vpg-filter-portal')) {\n return\n }\n closeFilterDropdown()\n }\n}\n\n// Initialize\nonMounted(() => {\n calculateColumnWidths()\n document.addEventListener('keydown', handleKeydown)\n document.addEventListener('mouseup', handleMouseUp)\n\n nextTick(() => {\n tableContainerRef.value?.addEventListener('scroll', handleTableScroll, { passive: true })\n })\n\n window.addEventListener('scroll', handleWindowScroll, { passive: true, capture: true })\n})\n\nonUnmounted(() => {\n document.removeEventListener('keydown', handleKeydown)\n document.removeEventListener('mouseup', handleMouseUp)\n tableContainerRef.value?.removeEventListener('scroll', handleTableScroll)\n window.removeEventListener('scroll', handleWindowScroll, { capture: true })\n})\n\n// Watch both props.data and aiLoadedData for recalculating column widths\nwatch([() => props.data, aiLoadedData], () => {\n nextTick(calculateColumnWidths)\n}, { immediate: true })\n\nconst totalTableWidth = computed(() => {\n return columnKeys.value.reduce((sum, key) => sum + (columnWidths.value[key] || MIN_COL_WIDTH), 0)\n})\n\nfunction handleContainerClick(event: MouseEvent) {\n if (activeFilterColumn.value) {\n const target = event.target as HTMLElement\n if (!target.closest('.vpg-filter-portal')) {\n closeFilterDropdown()\n }\n }\n}\n</script>\n\n<template>\n <div\n class=\"vpg-data-grid\"\n :class=\"[\n `vpg-font-${currentFontSize}`,\n `vpg-theme-${currentTheme}`,\n { 'vpg-striped': stripedRows },\n { 'vpg-resizing': resizingColumnId },\n { 'vpg-resizing-vertical': isResizingVertically },\n ]\"\n :style=\"{ height: `${gridHeight}px` }\"\n @click=\"handleContainerClick\"\n >\n <!-- Copy Toast -->\n <Transition name=\"vpg-toast\">\n <div v-if=\"showCopyToast\" class=\"vpg-toast\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n {{ copyToastMessage }}\n </div>\n </Transition>\n\n <!-- Toolbar -->\n <div class=\"vpg-toolbar\">\n <div class=\"vpg-toolbar-left\">\n <!-- View mode toggle -->\n <div v-if=\"showPivot\" class=\"vpg-view-toggle\">\n <!-- AI Analyst button (first, only if enabled) -->\n <button\n v-if=\"showAIAnalyst\"\n class=\"vpg-view-btn vpg-ai-btn\"\n :class=\"{ active: viewMode === 'ai' }\"\n @click=\"viewMode = 'ai'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n AI Analyst\n </button>\n <button\n v-else-if=\"aiAnalyst?.enabled && !canUseAIAnalyst\"\n class=\"vpg-view-btn vpg-ai-btn vpg-pro-feature\"\n title=\"AI Analyst (Pro feature)\"\n @click.prevent\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n AI Analyst\n <span class=\"vpg-pro-badge\">Pro</span>\n </button>\n <button\n class=\"vpg-view-btn\"\n :class=\"{ active: viewMode === 'grid' }\"\n @click=\"viewMode = 'grid'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n Grid\n </button>\n <button\n class=\"vpg-view-btn vpg-pivot-btn\"\n :class=\"{ active: viewMode === 'pivot' }\"\n @click=\"viewMode = 'pivot'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\" />\n </svg>\n Pivot\n </button>\n <button\n class=\"vpg-view-btn vpg-chart-btn\"\n :class=\"{ 'active': viewMode === 'chart', 'vpg-pro-feature': !canUseCharts }\"\n :title=\"canUseCharts ? 'Chart Builder' : 'Chart Builder (Pro feature)'\"\n @click=\"canUseCharts ? viewMode = 'chart' : null\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\" />\n </svg>\n Chart\n <span v-if=\"!canUseCharts\" class=\"vpg-pro-badge\">Pro</span>\n </button>\n </div>\n\n <!-- Grid mode controls -->\n <template v-if=\"viewMode === 'grid'\">\n <!-- Search input -->\n <div v-if=\"enableSearch\" class=\"vpg-search-container\">\n <button\n v-if=\"!showSearchInput\"\n class=\"vpg-icon-btn\"\n title=\"Search (Ctrl+F)\"\n @click=\"showSearchInput = true\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n </button>\n <div v-else class=\"vpg-search-box\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n v-model=\"globalSearchTerm\"\n type=\"text\"\n class=\"vpg-search-input\"\n placeholder=\"Search all columns...\"\n @keydown.escape=\"showSearchInput = false; globalSearchTerm = ''\"\n >\n <button\n v-if=\"globalSearchTerm\"\n class=\"vpg-search-clear\"\n @click=\"globalSearchTerm = ''\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"vpg-font-size-control\">\n <span class=\"vpg-label\">Size:</span>\n <div class=\"vpg-font-size-toggle\">\n <button\n v-for=\"opt in fontSizeOptions\"\n :key=\"opt.value\"\n class=\"vpg-font-size-btn\"\n :class=\"{ active: currentFontSize === opt.value }\"\n @click=\"currentFontSize = opt.value\"\n >\n {{ opt.label }}\n </button>\n </div>\n </div>\n\n <div v-if=\"activeFilterCount > 0\" class=\"vpg-filter-info\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n <span>{{ activeFilterCount }} filter{{ activeFilterCount > 1 ? 's' : '' }}</span>\n </div>\n\n <!-- Reset to full data button (when showing AI-filtered results) -->\n <button\n v-if=\"isShowingAIData\"\n class=\"vpg-reset-data-btn\"\n :class=\"{ 'vpg-loading-btn': isLoadingFullData }\"\n :disabled=\"isLoadingFullData\"\n title=\"Reset to full dataset\"\n @click=\"resetToFullData\"\n >\n <svg v-if=\"isLoadingFullData\" class=\"vpg-icon vpg-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <svg v-else class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <span>{{ isLoadingFullData ? 'Loading...' : 'Full Data' }}</span>\n </button>\n\n <div v-if=\"globalSearchTerm\" class=\"vpg-search-info\">\n <span>{{ totalSearchedRows }} match{{ totalSearchedRows !== 1 ? 'es' : '' }}</span>\n </div>\n </template>\n\n <!-- Pivot mode controls -->\n <template v-if=\"viewMode === 'pivot' && canUsePivot\">\n <button\n class=\"vpg-config-toggle\"\n :class=\"{ active: showPivotConfig }\"\n @click=\"showPivotConfig = !showPivotConfig\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4\" />\n </svg>\n {{ showPivotConfig ? 'Hide' : 'Show' }} Config\n </button>\n\n <div v-if=\"pivotIsConfigured\" class=\"vpg-pivot-status\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />\n </svg>\n <span>Pivot configured</span>\n </div>\n </template>\n </div>\n\n <div class=\"vpg-toolbar-right\">\n <button v-if=\"viewMode === 'grid' && activeFilterCount > 0\" class=\"vpg-clear-filters\" @click=\"clearAllFilters\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear Filters\n </button>\n\n <!-- Copy button -->\n <button\n v-if=\"enableClipboard && selectionBounds && viewMode === 'grid'\"\n class=\"vpg-icon-btn\"\n title=\"Copy selection (Ctrl+C)\"\n @click=\"copySelectionToClipboard\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n\n <!-- Export button - Grid export is free, Pivot export requires Pro -->\n <button\n v-if=\"enableExport && viewMode === 'grid'\"\n class=\"vpg-export-btn\"\n title=\"Export to CSV\"\n @click=\"handleExport\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Export\n </button>\n <button\n v-if=\"enableExport && viewMode === 'pivot' && pivotIsConfigured\"\n class=\"vpg-export-btn\"\n :class=\"{ 'vpg-export-btn-disabled': !isPro }\"\n :disabled=\"!isPro\"\n :title=\"isPro ? 'Export Pivot to CSV' : 'Export Pivot to CSV (Pro feature)'\"\n @click=\"isPro && handleExport()\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Export Pivot{{ !isPro ? ' (Pro)' : '' }}\n </button>\n </div>\n </div>\n\n <!-- AI Analyst View - use v-show to preserve state when switching tabs -->\n <div v-if=\"showAIAnalyst && aiAnalyst\" v-show=\"viewMode === 'ai'\" class=\"vpg-ai-view\">\n <AIAnalyst\n ref=\"aiAnalystRef\"\n :config=\"aiAnalyst\"\n :theme=\"currentTheme\"\n @data-loaded=\"handleAIDataLoaded\"\n @conversation-update=\"handleAIConversationUpdate\"\n @query-executed=\"handleAIQueryExecuted\"\n @error=\"handleAIError\"\n @view-results=\"handleAIViewResults\"\n />\n </div>\n\n <!-- Grid View -->\n <template v-if=\"viewMode === 'grid'\">\n <div ref=\"tableContainerRef\" class=\"vpg-grid-container\" tabindex=\"0\">\n <div v-if=\"loading\" class=\"vpg-loading\">\n <div class=\"vpg-spinner\" />\n <span>Loading data...</span>\n </div>\n\n <div v-else-if=\"displayData.length === 0\" class=\"vpg-empty\">\n <div class=\"vpg-empty-icon\">\n <svg class=\"vpg-icon-lg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n </div>\n <span>No data available</span>\n </div>\n\n <div v-else-if=\"filteredRowCount === 0\" class=\"vpg-empty\">\n <div class=\"vpg-empty-icon vpg-warning\">\n <svg class=\"vpg-icon-lg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n </div>\n <span>No matching records</span>\n <button class=\"vpg-clear-link\" @click=\"clearAllFilters\">\n Clear all filters\n </button>\n </div>\n\n <div v-else class=\"vpg-table-wrapper\">\n <table class=\"vpg-table\" :style=\"{ minWidth: `${totalTableWidth}px` }\">\n <thead>\n <tr>\n <th\n v-for=\"(colId, colIndex) in columnKeys\"\n :key=\"colId\"\n class=\"vpg-header-cell\"\n :class=\"{\n 'vpg-has-filter': hasActiveFilter(colId),\n 'vpg-is-sorted': getSortDirection(colId) !== null,\n 'vpg-is-active': activeFilterColumn === colId,\n }\"\n :style=\"{ width: `${columnWidths[colId] || MIN_COL_WIDTH}px`, minWidth: `${columnWidths[colId] || MIN_COL_WIDTH}px` }\"\n @click=\"handleHeaderClick(colIndex, $event)\"\n >\n <div class=\"vpg-header-content\">\n <span class=\"vpg-header-text\">{{ colId }}</span>\n <div class=\"vpg-header-icons\">\n <span v-if=\"getSortDirection(colId)\" class=\"vpg-sort-indicator\">\n <svg v-if=\"getSortDirection(colId) === 'asc'\" class=\"vpg-icon-sm\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z\" clip-rule=\"evenodd\" />\n </svg>\n <svg v-else class=\"vpg-icon-sm\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </span>\n <span v-if=\"hasActiveFilter(colId)\" class=\"vpg-filter-indicator\">\n <svg class=\"vpg-icon-xs\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n </span>\n <span class=\"vpg-dropdown-arrow\" title=\"Filter & Sort\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </span>\n </div>\n </div>\n <!-- Column resize handle -->\n <div\n v-if=\"enableColumnResize\"\n class=\"vpg-resize-handle\"\n @mousedown=\"startColumnResize(colId, $event)\"\n />\n </th>\n </tr>\n </thead>\n\n <tbody ref=\"tableBodyRef\">\n <tr\n v-for=\"(row, rowIndex) in paginatedRows\"\n :key=\"row.id\"\n class=\"vpg-row\"\n >\n <td\n v-for=\"(colId, colIndex) in columnKeys\"\n :key=\"colId\"\n class=\"vpg-cell\"\n :class=\"{\n 'vpg-selected': isCellSelected(rowIndex, colIndex),\n 'vpg-is-number': getColumnStats(colId).type === 'number',\n }\"\n :data-row=\"rowIndex\"\n :data-col=\"colIndex\"\n :style=\"{ width: `${columnWidths[colId] || MIN_COL_WIDTH}px`, minWidth: `${columnWidths[colId] || MIN_COL_WIDTH}px` }\"\n @mousedown=\"handleMouseDown(rowIndex, colIndex, $event)\"\n @mouseenter=\"handleMouseEnter(rowIndex, colIndex)\"\n >\n {{ formatCellValue(row.original[colId], colId) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </template>\n\n <!-- Pivot View -->\n <template v-else-if=\"viewMode === 'pivot'\">\n <div class=\"vpg-pivot-container\">\n <div v-if=\"showPivotConfig && canUsePivot\" class=\"vpg-pivot-config-panel\">\n <PivotConfig\n :available-fields=\"pivotAvailableFields\"\n :row-fields=\"pivotRowFields\"\n :column-fields=\"pivotColumnFields\"\n :value-fields=\"pivotValueFields\"\n :show-row-totals=\"pivotShowRowTotals\"\n :show-column-totals=\"pivotShowColumnTotals\"\n :calculated-fields=\"calculatedFields\"\n @update:show-row-totals=\"pivotShowRowTotals = $event\"\n @update:show-column-totals=\"pivotShowColumnTotals = $event\"\n @clear-config=\"clearPivotConfig\"\n @drag-start=\"handlePivotDragStart\"\n @drag-end=\"handlePivotDragEnd\"\n @update-aggregation=\"updateValueFieldAggregation\"\n @add-row-field=\"addRowField\"\n @remove-row-field=\"removeRowField\"\n @add-column-field=\"addColumnField\"\n @remove-column-field=\"removeColumnField\"\n @add-value-field=\"addValueField\"\n @remove-value-field=\"removeValueField\"\n @add-calculated-field=\"handleAddCalculatedField\"\n @remove-calculated-field=\"handleRemoveCalculatedField\"\n @update-calculated-field=\"handleUpdateCalculatedField\"\n />\n </div>\n\n <div class=\"vpg-pivot-main\" :class=\"{ 'vpg-full-width': !showPivotConfig }\">\n <PivotSkeleton\n :row-fields=\"pivotRowFields\"\n :column-fields=\"pivotColumnFields\"\n :value-fields=\"pivotValueFields\"\n :calculated-fields=\"calculatedFields\"\n :is-configured=\"pivotIsConfigured\"\n :dragging-field=\"draggingField\"\n :pivot-result=\"pivotResult\"\n :font-size=\"currentFontSize\"\n :active-filters=\"activeFilterInfo\"\n :total-row-count=\"totalRowCount\"\n :filtered-row-count=\"filteredRowCount\"\n @add-row-field=\"addRowField\"\n @remove-row-field=\"removeRowField\"\n @add-column-field=\"addColumnField\"\n @remove-column-field=\"removeColumnField\"\n @add-value-field=\"addValueField\"\n @remove-value-field=\"removeValueField\"\n @update-aggregation=\"updateValueFieldAggregation\"\n @reorder-row-fields=\"reorderRowFields\"\n @reorder-column-fields=\"reorderColumnFields\"\n />\n </div>\n </div>\n </template>\n\n <!-- Chart View -->\n <template v-else-if=\"viewMode === 'chart'\">\n <div class=\"vpg-chart-view\">\n <!-- Filter indicator for chart -->\n <div v-if=\"activeFilterInfo && activeFilterInfo.length > 0\" class=\"vpg-chart-filter-bar\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n <span>Chart showing {{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} records</span>\n <button class=\"vpg-chart-clear-filters\" @click=\"clearAllFilters\">\n Clear filters\n </button>\n </div>\n <ChartBuilder\n :data=\"filteredDataForPivot\"\n :theme=\"currentTheme\"\n @config-change=\"handleChartConfigChange\"\n />\n </div>\n </template>\n\n <!-- Footer -->\n <div class=\"vpg-footer\">\n <div class=\"vpg-footer-left\">\n <template v-if=\"viewMode === 'grid'\">\n <template v-if=\"enablePagination\">\n <span>{{ paginationStart.toLocaleString() }}-{{ paginationEnd.toLocaleString() }}</span>\n <span class=\"vpg-separator\">of</span>\n <span>{{ totalSearchedRows.toLocaleString() }}</span>\n <span v-if=\"totalSearchedRows !== totalRowCount\" class=\"vpg-filtered-note\">\n ({{ totalRowCount.toLocaleString() }} total)\n </span>\n </template>\n <template v-else-if=\"filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount\">\n <span>{{ totalRowCount.toLocaleString() }} records</span>\n </template>\n <template v-else>\n <span class=\"vpg-filtered-count\">{{ totalSearchedRows.toLocaleString() }}</span>\n <span class=\"vpg-separator\">of</span>\n <span>{{ totalRowCount.toLocaleString() }}</span>\n <span class=\"vpg-separator\">records</span>\n </template>\n </template>\n <template v-else-if=\"viewMode === 'pivot'\">\n <span class=\"vpg-pivot-label\">Pivot Table</span>\n <span class=\"vpg-separator\">•</span>\n <span>{{ totalRowCount.toLocaleString() }} source records</span>\n </template>\n <template v-else-if=\"viewMode === 'chart'\">\n <span class=\"vpg-chart-label\">Chart Builder</span>\n <span class=\"vpg-separator\">•</span>\n <span>{{ totalRowCount.toLocaleString() }} records</span>\n </template>\n </div>\n\n <!-- Pagination controls -->\n <div v-if=\"enablePagination && viewMode === 'grid' && totalPages > 1\" class=\"vpg-pagination\">\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === 1\"\n @click=\"currentPage = 1\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11 19l-7-7 7-7m8 14l-7-7 7-7\" />\n </svg>\n </button>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === 1\"\n @click=\"prevPage\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n <span class=\"vpg-page-info\">\n Page {{ currentPage }} of {{ totalPages }}\n </span>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === totalPages\"\n @click=\"nextPage\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === totalPages\"\n @click=\"currentPage = totalPages\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 5l7 7-7 7M5 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n\n <div v-if=\"viewMode === 'grid' && selectionStats && selectionStats.count > 1\" class=\"vpg-selection-stats\">\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Count:</span>\n <span class=\"vpg-stat-value\">{{ selectionStats.count }}</span>\n </span>\n <template v-if=\"selectionStats.numericCount > 0\">\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Sum:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.sum) }}</span>\n </span>\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Avg:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.avg) }}</span>\n </span>\n </template>\n </div>\n\n <div class=\"vpg-footer-right\">\n <div v-if=\"isDemo\" class=\"vpg-demo-banner\">\n <span class=\"vpg-demo-badge\">DEMO</span>\n <span>Pro features enabled</span>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" rel=\"noopener\">Get License →</a>\n </div>\n <span v-else-if=\"showWatermark\" class=\"vpg-watermark-inline\">\n <a href=\"https://tiny-pivot.com\" target=\"_blank\" rel=\"noopener\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" /><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" /><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" /><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" /></svg>\n Powered by TinyPivot\n </a>\n </span>\n </div>\n </div>\n\n <!-- Vertical Resize Handle -->\n <div\n v-if=\"enableVerticalResize\"\n class=\"vpg-vertical-resize-handle\"\n @mousedown=\"startVerticalResize\"\n >\n <div class=\"vpg-resize-grip\">\n <span />\n <span />\n <span />\n </div>\n </div>\n\n <!-- Filter Dropdown Portal -->\n <Teleport to=\"body\">\n <div\n v-if=\"activeFilterColumn\"\n class=\"vpg-filter-portal\"\n :style=\"{\n position: 'fixed',\n top: `${filterDropdownPosition.top}px`,\n left: `${filterDropdownPosition.left}px`,\n maxHeight: `${filterDropdownPosition.maxHeight}px`,\n zIndex: 9999,\n }\"\n >\n <ColumnFilter\n :column-id=\"activeFilterColumn\"\n :column-name=\"activeFilterColumn\"\n :stats=\"getColumnStats(activeFilterColumn)\"\n :selected-values=\"getColumnFilterValues(activeFilterColumn)\"\n :sort-direction=\"getSortDirection(activeFilterColumn)\"\n :numeric-range=\"getNumericRangeFilter(activeFilterColumn)\"\n :date-range=\"getDateRangeFilter(activeFilterColumn)\"\n :number-format=\"numberFormat\"\n :date-format=\"dateFormat\"\n @filter=\"(values) => handleFilter(activeFilterColumn!, values)\"\n @range-filter=\"(range) => handleRangeFilter(activeFilterColumn!, range)\"\n @date-range-filter=\"(range) => handleDateRangeFilter(activeFilterColumn!, range)\"\n @sort=\"(dir) => handleSort(activeFilterColumn!, dir)\"\n @close=\"closeFilterDropdown\"\n />\n </div>\n </Teleport>\n </div>\n</template>\n\n<style scoped>\n.vpg-data-grid {\n display: flex;\n flex-direction: column;\n background: white;\n border-radius: 0.5rem;\n overflow: hidden;\n border: 1px solid #e2e8f0;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n margin-bottom: 1.5rem;\n position: relative;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-icon-sm {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-icon-lg {\n width: 3rem;\n height: 3rem;\n}\n\n/* Toolbar */\n.vpg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.vpg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-view-toggle {\n display: flex;\n background: white;\n border-radius: 0.5rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-view-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-view-btn:hover {\n background: #f8fafc;\n}\n\n.vpg-view-btn.active {\n background: #4f46e5;\n color: white;\n box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.1);\n}\n\n.vpg-view-btn.vpg-pivot-btn.active {\n background: #10b981;\n}\n\n.vpg-font-size-control {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-label {\n font-size: 0.75rem;\n color: #64748b;\n}\n\n.vpg-font-size-toggle {\n display: flex;\n background: white;\n border-radius: 0.25rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n}\n\n.vpg-font-size-btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-font-size-btn:hover {\n background: #f1f5f9;\n}\n\n.vpg-font-size-btn.active {\n background: #4f46e5;\n color: white;\n}\n\n.vpg-filter-info {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: #475569;\n}\n\n.vpg-filter-info svg {\n color: #4f46e5;\n}\n\n.vpg-reset-data-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 0.375rem;\n background: #fef3c7;\n border: 1px solid #fcd34d;\n color: #92400e;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-reset-data-btn:hover {\n background: #fde68a;\n border-color: #f59e0b;\n}\n\n.vpg-reset-data-btn svg {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-config-toggle {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 0.375rem;\n background: white;\n border: 1px solid #e2e8f0;\n color: #475569;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-config-toggle:hover {\n background: #f8fafc;\n}\n\n.vpg-config-toggle.active {\n background: #ecfdf5;\n border-color: #a7f3d0;\n color: #059669;\n}\n\n.vpg-pivot-status {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: #059669;\n}\n\n.vpg-clear-filters {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n font-weight: 500;\n color: #475569;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-clear-filters:hover {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n/* Grid Container */\n.vpg-grid-container {\n flex: 1;\n overflow: auto;\n position: relative;\n background: rgba(248, 250, 252, 0.3);\n isolation: isolate;\n}\n\n.vpg-grid-container:focus {\n outline: none;\n}\n\n.vpg-loading {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.95);\n z-index: 10;\n}\n\n.vpg-spinner {\n width: 2rem;\n height: 2rem;\n border: 2px solid #e2e8f0;\n border-top-color: #4f46e5;\n border-radius: 50%;\n animation: vpg-spin 1s linear infinite;\n}\n\n@keyframes vpg-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.vpg-loading span {\n margin-top: 0.5rem;\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 5rem;\n gap: 0.75rem;\n}\n\n.vpg-empty-icon {\n width: 5rem;\n height: 5rem;\n border-radius: 50%;\n background: #f1f5f9;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #cbd5e1;\n margin-bottom: 0.5rem;\n}\n\n.vpg-empty-icon.vpg-warning {\n background: #fef3c7;\n color: #fcd34d;\n}\n\n.vpg-empty span {\n color: #64748b;\n font-weight: 500;\n}\n\n.vpg-clear-link {\n color: #4f46e5;\n font-size: 0.875rem;\n font-weight: 500;\n margin-top: 0.25rem;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.vpg-clear-link:hover {\n text-decoration: underline;\n}\n\n.vpg-table-wrapper {\n min-height: 100%;\n}\n\n.vpg-table {\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n}\n\n.vpg-table thead {\n position: sticky;\n top: 0;\n z-index: 20;\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);\n}\n\n.vpg-header-cell {\n z-index: 10;\n padding: 0.5rem 0.75rem;\n text-align: left;\n cursor: pointer;\n user-select: none;\n background: #f8fafc;\n transition: all 0.15s;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #f1f5f9;\n}\n\n.vpg-header-cell:hover {\n background: #f1f5f9;\n}\n\n.vpg-header-cell:last-child {\n border-right: none;\n}\n\n.vpg-header-cell.vpg-has-filter {\n background: #eef2ff;\n}\n\n.vpg-header-cell.vpg-is-sorted {\n background: #eff6ff;\n}\n\n.vpg-header-cell.vpg-has-filter.vpg-is-sorted {\n background: #ede9fe;\n}\n\n.vpg-header-cell.vpg-is-active {\n background: #e0e7ff;\n box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.1);\n}\n\n.vpg-header-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.vpg-header-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vpg-header-icons {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n.vpg-sort-indicator {\n color: #3b82f6;\n}\n\n.vpg-filter-indicator {\n color: #4f46e5;\n}\n\n.vpg-dropdown-arrow {\n padding: 0.125rem;\n border-radius: 0.25rem;\n color: #cbd5e1;\n transition: all 0.15s;\n cursor: pointer;\n}\n\n.vpg-dropdown-arrow:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-header-cell:hover .vpg-dropdown-arrow {\n color: #94a3b8;\n}\n\n.vpg-row {\n transition: background 0.15s;\n}\n\n.vpg-row:nth-child(odd) {\n background: white;\n}\n\n.vpg-row:nth-child(even) {\n background: rgba(248, 250, 252, 0.5);\n}\n\n.vpg-row:hover {\n background: rgba(239, 246, 255, 0.4);\n}\n\n.vpg-cell {\n padding: 0.625rem 1rem;\n font-size: 0.875rem;\n color: #334155;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: cell;\n transition: all 0.15s;\n max-width: 350px;\n border-bottom: 1px solid #f1f5f9;\n border-right: 1px solid #f8fafc;\n}\n\n.vpg-cell:last-child {\n border-right: none;\n}\n\n.vpg-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(129, 140, 248, 0.4);\n}\n\n.vpg-cell.vpg-selected {\n background: rgba(224, 231, 255, 0.8);\n box-shadow: inset 0 0 0 2px #818cf8;\n}\n\n.vpg-cell.vpg-is-number {\n text-align: right;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: #334155;\n font-variant-numeric: tabular-nums;\n}\n\n/* Font size variations */\n.vpg-data-grid.vpg-font-xs .vpg-cell {\n font-size: 0.75rem;\n padding: 0.375rem 0.75rem;\n}\n\n.vpg-data-grid.vpg-font-xs .vpg-header-text {\n font-size: 0.625rem;\n}\n\n.vpg-data-grid.vpg-font-sm .vpg-cell {\n font-size: 0.875rem;\n padding: 0.5rem 1rem;\n}\n\n.vpg-data-grid.vpg-font-base .vpg-cell {\n font-size: 1rem;\n padding: 0.625rem 1rem;\n}\n\n.vpg-data-grid.vpg-font-base .vpg-header-text {\n font-size: 0.75rem;\n}\n\n/* Pivot Container */\n.vpg-pivot-container {\n display: flex;\n flex: 1;\n gap: 1rem;\n overflow: hidden;\n min-height: 0;\n padding: 1rem;\n}\n\n.vpg-pivot-config-panel {\n width: 14rem;\n flex-shrink: 0;\n overflow: hidden;\n}\n\n.vpg-pivot-main {\n flex: 1;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.vpg-pivot-main.vpg-full-width {\n width: 100%;\n}\n\n/* Footer */\n.vpg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: rgba(248, 250, 252, 0.8);\n border-top: 1px solid rgba(226, 232, 240, 0.8);\n font-size: 0.875rem;\n}\n\n.vpg-footer-left {\n display: flex;\n align-items: center;\n color: #64748b;\n}\n\n.vpg-filtered-count {\n color: #4f46e5;\n font-weight: 500;\n}\n\n.vpg-separator {\n color: #94a3b8;\n margin: 0 0.25rem;\n}\n\n.vpg-pivot-label {\n color: #10b981;\n font-weight: 500;\n}\n\n.vpg-footer-right {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.vpg-selection-stats {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.125rem 0.5rem;\n background: rgba(99, 102, 241, 0.08);\n border-radius: 0.25rem;\n border: 1px solid rgba(99, 102, 241, 0.15);\n}\n\n.vpg-stat {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-stat-label {\n font-size: 0.6875rem;\n color: #64748b;\n font-weight: 400;\n}\n\n.vpg-stat-value {\n font-size: 0.6875rem;\n color: #6366f1;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n}\n\n.vpg-stat-divider {\n color: #cbd5e1;\n}\n\n.vpg-watermark-inline a {\n font-size: 0.75rem;\n color: #94a3b8;\n text-decoration: none;\n transition: color 0.15s;\n}\n\n.vpg-watermark-inline a:hover {\n color: #64748b;\n}\n\n/* Demo Banner */\n.vpg-demo-banner {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.25rem 0.75rem;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n border: 1px solid #fcd34d;\n border-radius: 0.375rem;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-demo-badge {\n display: inline-flex;\n padding: 0.125rem 0.375rem;\n background: #f59e0b;\n color: white;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n letter-spacing: 0.05em;\n}\n\n.vpg-demo-banner a {\n font-weight: 600;\n color: #d97706;\n text-decoration: none;\n}\n\n.vpg-demo-banner a:hover {\n color: #b45309;\n text-decoration: underline;\n}\n\n/* Scrollbar */\n.vpg-grid-container::-webkit-scrollbar {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-grid-container::-webkit-scrollbar-track {\n background: rgba(241, 245, 249, 0.5);\n}\n\n.vpg-grid-container::-webkit-scrollbar-thumb {\n background: rgba(203, 213, 225, 0.8);\n border-radius: 9999px;\n}\n\n.vpg-grid-container::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.8);\n}\n\n.vpg-grid-container::-webkit-scrollbar-corner {\n background: rgba(241, 245, 249, 0.5);\n}\n\n/* Toast notification */\n.vpg-toast {\n position: absolute;\n top: 1rem;\n right: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #10b981;\n color: white;\n border-radius: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n z-index: 100;\n}\n\n.vpg-toast-enter-active,\n.vpg-toast-leave-active {\n transition: all 0.2s ease;\n}\n\n.vpg-toast-enter-from,\n.vpg-toast-leave-to {\n opacity: 0;\n transform: translateY(-0.5rem);\n}\n\n/* Search */\n.vpg-search-container {\n display: flex;\n align-items: center;\n}\n\n.vpg-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0.375rem;\n background: transparent;\n border: none;\n border-radius: 0.375rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-icon-btn:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-search-box {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.625rem;\n background: #f8fafc;\n border: 1px solid transparent;\n border-radius: 0.5rem;\n transition: all 0.15s ease;\n}\n\n.vpg-search-box:focus-within {\n background: white;\n border-color: #e2e8f0;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-search-icon {\n width: 1rem;\n height: 1rem;\n color: #94a3b8;\n flex-shrink: 0;\n}\n\n.vpg-search-input {\n border: none;\n outline: none;\n background: transparent;\n font-size: 0.8125rem;\n color: #334155;\n width: 200px;\n}\n\n.vpg-search-input:focus {\n outline: none;\n}\n\n.vpg-search-input::placeholder {\n color: #94a3b8;\n}\n\n.vpg-search-clear {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0.125rem;\n background: #f1f5f9;\n border: none;\n border-radius: 50%;\n color: #64748b;\n cursor: pointer;\n}\n\n.vpg-search-clear:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-search-info {\n font-size: 0.75rem;\n color: #64748b;\n font-style: italic;\n}\n\n/* Export button */\n.vpg-export-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #059669;\n background: #ecfdf5;\n border: 1px solid #a7f3d0;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-export-btn:hover:not(:disabled) {\n background: #d1fae5;\n border-color: #6ee7b7;\n}\n\n.vpg-export-btn-disabled,\n.vpg-export-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n background: #f1f5f9;\n border-color: #e2e8f0;\n color: #94a3b8;\n}\n\n/* Column resize handle */\n.vpg-resize-handle {\n position: absolute;\n right: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n background: transparent;\n transition: background 0.15s;\n}\n\n.vpg-resize-handle:hover {\n background: rgba(79, 70, 229, 0.3);\n}\n\n.vpg-header-cell {\n position: relative;\n}\n\n.vpg-data-grid.vpg-resizing {\n cursor: col-resize;\n user-select: none;\n}\n\n.vpg-data-grid.vpg-resizing .vpg-resize-handle {\n background: rgba(79, 70, 229, 0.3);\n}\n\n/* Vertical resize handle */\n.vpg-vertical-resize-handle {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 8px;\n cursor: row-resize;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.15s;\n}\n\n.vpg-vertical-resize-handle:hover {\n background: rgba(79, 70, 229, 0.1);\n}\n\n.vpg-vertical-resize-handle:hover .vpg-resize-grip span {\n background: rgba(79, 70, 229, 0.6);\n}\n\n.vpg-resize-grip {\n display: flex;\n gap: 2px;\n padding: 2px 8px;\n border-radius: 4px;\n}\n\n.vpg-resize-grip span {\n width: 16px;\n height: 2px;\n background: #cbd5e1;\n border-radius: 1px;\n transition: background 0.15s;\n}\n\n.vpg-data-grid.vpg-resizing-vertical {\n cursor: row-resize;\n user-select: none;\n}\n\n.vpg-data-grid.vpg-resizing-vertical .vpg-vertical-resize-handle {\n background: rgba(79, 70, 229, 0.15);\n}\n\n.vpg-data-grid.vpg-resizing-vertical .vpg-resize-grip span {\n background: rgba(79, 70, 229, 0.8);\n}\n\n/* Pagination */\n.vpg-pagination {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-page-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n color: #475569;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-page-btn:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n.vpg-page-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.vpg-page-info {\n font-size: 0.75rem;\n color: #64748b;\n padding: 0 0.5rem;\n}\n\n.vpg-filtered-note {\n font-size: 0.75rem;\n color: #94a3b8;\n margin-left: 0.25rem;\n}\n\n/* Dark theme */\n.vpg-data-grid.vpg-theme-dark {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-toolbar {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-view-toggle {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-view-btn {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-view-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-view-btn.active {\n background: #6366f1;\n color: white;\n}\n\n.vpg-theme-dark .vpg-view-btn.vpg-pivot-btn.active {\n background: #10b981;\n}\n\n.vpg-theme-dark .vpg-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-font-size-toggle {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-font-size-btn {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-font-size-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-grid-container {\n background: rgba(15, 23, 42, 0.5);\n}\n\n.vpg-theme-dark .vpg-header-cell {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-header-cell:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-header-text {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-dropdown-arrow {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-dropdown-arrow:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-row:nth-child(odd) {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-row:nth-child(even) {\n background: rgba(30, 41, 59, 0.7);\n}\n\n.vpg-theme-dark .vpg-row:hover {\n background: rgba(51, 65, 85, 0.5);\n}\n\n.vpg-theme-dark .vpg-cell {\n color: #e2e8f0;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(129, 140, 248, 0.5);\n}\n\n.vpg-theme-dark .vpg-cell.vpg-selected {\n background: rgba(99, 102, 241, 0.3);\n box-shadow: inset 0 0 0 2px #818cf8;\n}\n\n.vpg-theme-dark .vpg-footer {\n background: rgba(15, 23, 42, 0.8);\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-footer-left {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-selection-stats {\n background: rgba(99, 102, 241, 0.1);\n border-color: rgba(99, 102, 241, 0.2);\n}\n\n.vpg-theme-dark .vpg-stat-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-stat-value {\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-stat-divider {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-search-box {\n background: #334155;\n border-color: transparent;\n}\n\n.vpg-theme-dark .vpg-search-box:focus-within {\n background: #1e293b;\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-search-input {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-search-clear {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-search-clear:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-clear-filters {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-clear-filters:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-page-btn {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-page-btn:hover:not(:disabled) {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-export-btn {\n background: rgba(16, 185, 129, 0.2);\n border-color: rgba(16, 185, 129, 0.4);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-export-btn:hover:not(:disabled) {\n background: rgba(16, 185, 129, 0.3);\n}\n\n.vpg-theme-dark .vpg-export-btn-disabled,\n.vpg-theme-dark .vpg-export-btn:disabled {\n opacity: 0.5;\n background: #334155;\n border-color: #475569;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-config-toggle {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-config-toggle:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-config-toggle.active {\n background: rgba(16, 185, 129, 0.2);\n border-color: rgba(16, 185, 129, 0.4);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-pivot-status {\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-reset-data-btn {\n background: rgba(251, 191, 36, 0.15);\n border-color: rgba(251, 191, 36, 0.4);\n color: #fbbf24;\n}\n\n.vpg-theme-dark .vpg-reset-data-btn:hover {\n background: rgba(251, 191, 36, 0.25);\n border-color: rgba(251, 191, 36, 0.6);\n}\n\n.vpg-theme-dark .vpg-watermark-inline a {\n color: #94a3b8;\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-watermark-inline a:hover {\n color: #cbd5e1;\n background: linear-gradient(135deg, #334155 0%, #475569 100%);\n border-color: #64748b;\n}\n\n.vpg-theme-dark .vpg-resize-grip span {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-vertical-resize-handle:hover .vpg-resize-grip span {\n background: rgba(129, 140, 248, 0.6);\n}\n\n.vpg-theme-dark.vpg-resizing-vertical .vpg-resize-grip span {\n background: rgba(129, 140, 248, 0.8);\n}\n\n/* Striped rows (toggleable) */\n.vpg-data-grid:not(.vpg-striped) .vpg-row:nth-child(even) {\n background: inherit;\n}\n\n.vpg-theme-dark:not(.vpg-striped) .vpg-row:nth-child(odd),\n.vpg-theme-dark:not(.vpg-striped) .vpg-row:nth-child(even) {\n background: #1e293b;\n}\n\n/* AI Analyst View */\n.vpg-ai-view {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* AI Analyst Button */\n.vpg-view-btn.vpg-ai-btn.active {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n}\n\n.vpg-view-btn.vpg-ai-btn.vpg-pro-feature {\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n.vpg-pro-badge {\n display: inline-flex;\n padding: 0.0625rem 0.25rem;\n font-size: 0.5625rem;\n font-weight: 600;\n background: linear-gradient(135deg, #f59e0b 0%, #f97316 100%);\n color: white;\n border-radius: 0.25rem;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n/* Chart View */\n.vpg-chart-view {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-chart-filter-bar {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #fef3c7;\n border-bottom: 1px solid #fde68a;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-chart-clear-filters {\n margin-left: auto;\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #b45309;\n background: transparent;\n border: 1px solid #fcd34d;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-chart-clear-filters:hover {\n background: #fef3c7;\n}\n\n.vpg-chart-label {\n color: #f59e0b;\n font-weight: 500;\n}\n</style>\n"],"names":["DEMO_SCHEMAS","DEMO_SCENARIOS","findDemoResponse","dataSourceId","userMessage","scenario","lowerMessage","trigger","keyword","getDefaultDemoResponse","s","getDemoSchema","getInitialDemoData","buildSystemPrompt","dataSources","schemas","selectedSourceId","allSchemas","selectedSchema","selectedSource","ds","otherTables","formatDataSourcesList","formatSelectedSchemaContext","formatRelatedTablesContext","desc","source","schema","columnsWithDescriptions","col","override","_a","formatColumnsTable","tables","table","keyColumns","otherColumns","moreCount","moreText","columns","nullable","extractSQLFromResponse","response","sqlBlockRegex","match","sql","validateSQLSafety","upperSQL","dangerousKeywords","stripSQLFromContent","content","generateSessionId","generateMessageId","createConversation","sessionId","now","createUserMessage","createAssistantMessage","metadata","addMessageToConversation","conversation","message","setConversationDataSource","getMessagesForAPI","m","CHART_TYPES","CHART_AGGREGATIONS","CHART_COLORS","detectFieldRole","data","field","values","row","v","numericCount","dateCount","val","threshold","analyzeFieldsForChart","fields","result","role","uniqueSet","dataType","min","max","nums","n","formatFieldLabel","word","getChartTypeInfo","type","ct","isChartConfigValid","config","getChartGuidance","typeInfo","aggregateValues","aggregation","a","b","processChartData","xField","yField","yAggregation","seriesField","grouped","xValue","yValue","seriesValue","xGroup","categories","numA","numB","seriesNames","seriesName","series","seriesData","category","processChartDataForPie","entries","e","processChartDataForScatter","sizeField","_b","x","y","point","z","name","points","processChartDataForHeatmap","colorField","colorAggregation","allXCategories","colorValue","yGroup","sortedXCategories","yCategory","xCategory","aggregatedValue","createDefaultChartConfig","escapeCSV","value","delimiter","str","exportToCSV","options","filename","includeHeaders","rows","csvContent","downloadFile","exportPivotToCSV","pivotData","rowFields","_columnFields","valueFields","headers","rowHeaders","rowTotals","columnTotals","grandTotal","showRowTotals","showColumnTotals","rowHeaderColCount","level","headerRow","i","vf","rowIdx","csvRow","rowHeader","rowData","cell","totalsRow","mimeType","blob","url","link","copyToClipboard","text","onSuccess","onError","formatSelectionForClipboard","selectionBounds","minRow","maxRow","minCol","maxCol","lines","r","c","colId","FREE_LICENSE","INVALID_LICENSE","DEMO_LICENSE","PUBLIC_KEY_PEM","base64ToUint8Array","base64","standardBase64","binaryString","bytes","derToRaw","der","offset","rLen","sLen","padR","padS","raw","verifySignatureNoble","rawSig","msgBytes","spkiBytes","p256","rawPublicKey","hashSecretNoble","secret","sha256","hash","subtleCryptoCache","getSubtleCrypto","subtle","insecureContextWarned","warnInsecureContext","importPublicKey","pemContents","binaryKey","getSpkiBytes","verifySignature","typeCode","signature","expiry","payload","msgData","derSig","publicKey","validateLicenseKey","key","lastDashIdx","expiryStr","withoutPrefix","secondDashIdx","year","month","day","expiresAt","configureLicenseSecret","_secret","DEMO_SECRET_HASH","hashSecret","hashBuffer","getDemoLicenseInfo","getFreeLicenseInfo","canUsePivot","info","canUseCharts","canUseAIAnalyst","isPro","shouldShowWatermark","isDemo","logProRequired","feature","detectColumnType","nonNullValues","sample","numberCount","booleanCount","detectFieldType","isNumeric","getColumnUniqueValues","columnKey","maxValues","nullCount","numericMin","numericMax","dateMin","dateMax","num","dateObj","isoStr","uniqueValues","columnType","formatCellValue","numberFormat","dateFormat","formatNumber","formatDate","format","maxDigits","date","parseDateInput","input","trimmed","parts","d","getDatePlaceholder","makeKey","f","parseKey","calculateMedian","sorted","mid","calculateStdDev","mean","avgSquaredDiff","aggregate","fn","customFn","allFieldValues","sum","formatAggregatedValue","getAggregationLabel","customLabel","getAggregationSymbol","customSymbol","AGGREGATION_OPTIONS","formatCalculatedValue","formatAs","decimals","parseSimpleFormula","formula","matches","keywords","validateSimpleFormula","availableFields","referencedFields","lowerFields","testExpr","escaped","evaluateSimpleFormula","fieldNames","expression","actualField","computeAvailableFields","getUnassignedFields","columnFields","assigned","isPivotConfigured","computePivotResult","calculatedFields","calcFieldMap","cf","allDataFieldNames","rowKeySet","colKeySet","dataMap","rowKey","colKey","colMap","valueArrays","calcId","calcDef","rowKeys","colKeys","grandTotals","_i","total","getValueFieldLabel","repeatCount","valueLabels","_colKey","columnTotalsMap","rowAllValues","rawValues","fi","colTotals","vfIdx","gtValue","aggValue","formattedValue","colRawValues","allRawValues","vals","STORAGE_KEY_PREFIX","generateStorageKey","savePivotConfig","loadPivotConfig","stored","isConfigValidForFields","availableFieldNames","available","CALC_FIELDS_KEY","saveCalculatedFields","loadCalculatedFields","isNumericRange","isDateRange","useAIAnalyst","onDataLoaded","onConversationUpdate","onQueryExecuted","storageKey","loadFromStorage","parsed","saveToStorage","conv","replacer","_key","ref","isLoading","error","lastLoadedData","discoveredDataSources","isLoadingTables","effectiveDataSources","computed","selectedDataSource","selectedDataSourceInfo","messages","hasMessages","fetchTables","t","fetchAllSchemas","err","onMounted","selectDataSource","dataSource","systemMessage","demoSchema","initialData","fetchSchema","fetchSampleData","emitConversationUpdate","sendMessage","handleDemoResponse","assistantMessage","aiResponse","callAIEndpoint","sqlQuery","validation","errorMessage","aiMessage","executeQuery","errorMsg","userInput","resolve","demoTrigger","defaultResponse","systemPrompt","apiMessages","messageId","startTime","duration","updatedMessages","msg","truncatedNote","successMessage","loadFullData","clearConversation","exportConversation","importConversation","props","__props","emit","__emit","__expose","inputText","searchQuery","messagesContainerRef","selectedMessageId","showSqlPanel","filteredDataSources","q","currentSchema","previewData","fullPreviewData","previewColumns","selectedQuery","_c","watch","nextTick","latestWithData","handleSubmit","handleKeydown","event","handleViewResults","selectMessage","toggleSqlPanel","handleClearConversation","handleChangeDataSource","getColumnTypeIcon","getMessageContent","autoResizeTextarea","textarea","hasQueryResult","_createElementBlock","_normalizeClass","_unref","_openBlock","_hoisted_11","_createElementVNode","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_toDisplayString","_hoisted_16","_cache","_hoisted_17","_Fragment","_renderList","_hoisted_18","$event","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_d","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","idx","_hoisted_51","_createTextVNode","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","show","validationError","insertField","insertOperator","op","save","validationResult","_createBlock","_Teleport","_hoisted_6","VueApexCharts","defineAsyncComponent","chartConfig","fieldInfos","dimensions","measures","draggingField","dragOverZone","showChartTypeSelector","guidance","chartIsValid","selectedChartType","zoneLabels","isScatterType","isHeatmapType","handleDragStart","handleDragEnd","handleDragOver","zone","handleDragLeave","handleDrop","chartField","removeField","selectChartType","updateAggregation","updated","chartOptions","isDark","baseOptions","getApexChartType","formatValue","w","chartSeries","chartLabels","chartOptionsWithCategories","dec","getChartIcon","icons","_hoisted_19","agg","_hoisted_28","_hoisted_29","_hoisted_39","_Suspense","_e","_f","localMinText","localMaxText","minError","maxError","initFromRange","range","formattedMin","formattedMax","isFilterActive","handleMinInput","emitChange","handleMaxInput","clearFilter","setFullRange","newRange","localMin","localMax","step","minPercent","maxPercent","handleMinSlider","target","handleMaxSlider","_normalizeStyle","dropdownRef","searchInputRef","isNumericColumn","isDateColumn","filterMode","localRange","localDateRange","localSelected","hasBlankValues","filteredValues","query","allValues","ascLabel","descLabel","ascTitle","descTitle","toggleValue","selectAll","clearAll","applyFilter","sortAscending","sortDescending","handleRangeChange","applyRangeFilter","clearRangeFilter","handleDateRangeChange","applyDateRangeFilter","clearDateRangeFilter","setFilterMode","mode","handleClickOutside","onUnmounted","newValues","_createVNode","NumericRangeFilter","DateRangeFilter","multiSelectFilter","columnId","filterValue","cellValue","dateStr","cellString","useExcelGrid","enableSorting","enableFiltering","sorting","columnFilters","columnVisibility","globalFilter","columnStatsCache","columnKeys","getColumnStats","cacheKey","clearStatsCache","columnDefs","stats","useVueTable","updater","getCoreRowModel","getSortedRowModel","getFilteredRowModel","filteredRowCount","totalRowCount","activeFilters","hasActiveFilter","column","setColumnFilter","setNumericRangeFilter","getNumericRangeFilter","setDateRangeFilter","getDateRangeFilter","clearAllFilters","getColumnFilterValues","toggleSort","current","getSortDirection","sort","coreExportToCSV","coreExportPivotToCSV","coreCopyToClipboard","coreFormatSelection","usePagination","pageSize","currentPage","totalPages","paginatedData","start","end","startIndex","endIndex","goToPage","page","nextPage","prevPage","firstPage","lastPage","setPageSize","size","useGlobalSearch","searchTerm","caseSensitive","filteredData","term","clearSearch","useRowSelection","selectedRowIndices","selectedRows","allSelected","someSelected","toggleRow","index","selectRow","deselectRow","_","deselectAll","toggleAll","isSelected","selectRange","useColumnResize","initialWidths","minWidth","maxWidth","columnWidths","isResizing","resizingColumn","startResize","startX","startWidth","handleMouseMove","diff","newWidth","handleMouseUp","resetColumnWidth","resetAllWidths","licenseKey","demoMode","licenseInfo","validationPromise","setLicenseKey","enableDemoMode","demoLicense","coreConfigureLicenseSecret","useLicense","coreIsPro","coreCanUsePivot","canUseAdvancedAggregations","canUsePercentageMode","coreCanUseCharts","coreCanUseAIAnalyst","showWatermark","coreShouldShowWatermark","requirePro","usePivotTable","currentStorageKey","unassignedFields","isConfigured","pivotResult","addRowField","removeRowField","addColumnField","removeColumnField","addValueField","removeValueField","updateValueFieldAggregation","oldAgg","newAgg","clearConfig","moveField","from","to","items","removed","autoSuggestConfig","categoricalFields","numericFields","addCalculatedField","existing","removeCalculatedField","id","newData","newKeys","savedConfig","currentConfig","aggregationOptions","aggregationRequiresPro","isAggregationAvailable","showCalcModal","editingCalcField","numericFieldNames","openCalcModal","handleSaveCalcField","handleTotalsToggle","checked","calculatedFieldsAsStats","calc","allAvailableFields","assignedFields","rowSet","colSet","valueMap","valSet","assignedCount","fieldSearch","filteredUnassignedFields","search","fieldName","displayName","getFieldIcon","isCalculated","getFieldDisplayName","handleAggregationChange","currentAgg","toggleRowColumn","currentAssignment","assignedTo","valueConfig","_withModifiers","CalculatedFieldModal","getValueFieldDisplayName","calcField","isCalculatedField","dragOverArea","reorderDragSource","reorderDropTarget","currentFontSize","fontSizeOptions","hasActiveFilters","filterSummary","filterTooltipDetails","maxDisplay","displayValues","remaining","showFilterTooltip","sortDirection","sortTarget","sortedRowIndices","indices","cmp","aHeader","bHeader","colIdx","aVal","bVal","columnHeaderCells","cells","colspan","selectedCell","selectionStart","selectionEnd","isSelecting","showCopyToast","copyToastMessage","handleCellMouseDown","rowIndex","colIndex","handleCellMouseEnter","isCellSelected","copySelectionToClipboard","sortedIdx","rowValues","cellCount","selectionStats","count","avg","formatStatValue","area","existingValue","handleChipDragStart","handleChipDragEnd","handleChipDragOver","handleChipDragLeave","handleChipDrop","targetIndex","sourceIndex","movedField","isChipDragSource","isChipDropTarget","rowHeaderWidth","dataColWidth","rowHeaderColWidth","numCols","getRowHeaderLeftOffset","fieldIdx","_Transition","filter","opt","levelIdx","_hoisted_52","_hoisted_53","_hoisted_54","_hoisted_55","_hoisted_56","_hoisted_57","_hoisted_58","_hoisted_59","MIN_COL_WIDTH","MAX_COL_WIDTH","showAIAnalyst","currentTheme","globalSearchTerm","showSearchInput","resizingColumnId","resizeStartX","resizeStartWidth","gridHeight","isResizingVertically","verticalResizeStartY","verticalResizeStartHeight","aiAnalystRef","aiLoadedData","displayData","dataRef","filteredDataForPivot","activeFilterInfo","coreFormatDate","pivotRowFields","pivotColumnFields","pivotValueFields","pivotShowRowTotals","pivotShowColumnTotals","pivotAvailableFields","pivotIsConfigured","clearPivotConfig","_autoSuggestConfig","searchFilteredData","totalSearchedRows","paginatedRows","paginationStart","paginationEnd","handleExport","viewMode","handlePivotExport","dataToExport","pivotFilename","rowCount","startColumnResize","handleResizeMove","handleResizeEnd","startVerticalResize","handleVerticalResizeMove","handleVerticalResizeEnd","newHeight","handleAIDataLoaded","isShowingAIData","isLoadingFullData","resetToFullData","fullData","handleAIConversationUpdate","handleAIQueryExecuted","handleAIError","handleAIViewResults","handleChartConfigChange","showPivotConfig","handleAddCalculatedField","handleRemoveCalculatedField","calcFieldKey","handleUpdateCalculatedField","handlePivotDragStart","handlePivotDragEnd","reorderRowFields","reorderColumnFields","tableContainerRef","tableBodyRef","activeFilterColumn","filterDropdownPosition","calculateColumnWidths","widths","sampleSize","ctx","width","openFilterDropdown","headerCell","rect","dropdownWidth","padding","left","spaceBelow","spaceAbove","top","maxHeight","closeFilterDropdown","handleFilter","handleRangeFilter","handleDateRangeFilter","handleSort","direction","activeFilterCount","selectColumn","handleHeaderClick","isCellInSelection","coreFormatNumber","updateSelection","newRow","newCol","scrollCellIntoView","handleMouseDown","handleMouseEnter","noFormatPatterns","shouldFormatNumber","handleTableScroll","handleWindowScroll","totalTableWidth","handleContainerClick","_withKeys","args","_withDirectives","AIAnalyst","PivotConfig","PivotSkeleton","ChartBuilder","ColumnFilter","dir"],"mappings":"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"}
1
+ {"version":3,"file":"tinypivot-vue.js","sources":["../../core/dist/ai/demo.js","../../core/dist/ai/prompts.js","../../core/dist/ai/session.js","../../core/dist/chart/index.js","../../core/dist/export/index.js","../../core/dist/license/index.js","../../core/dist/utils/index.js","../../core/dist/pivot/index.js","../../core/dist/types/index.js","../src/composables/useAIAnalyst.ts","../src/components/AIAnalyst.vue","../src/components/CalculatedFieldModal.vue","../src/components/ChartBuilder.vue","../src/components/DateRangeFilter.vue","../src/components/NumericRangeFilter.vue","../src/components/ColumnFilter.vue","../src/composables/useExcelGrid.ts","../src/composables/useGridFeatures.ts","../src/composables/useLicense.ts","../src/composables/usePivotTable.ts","../src/components/PivotConfig.vue","../src/components/PivotSkeleton.vue","../src/components/DataGrid.vue"],"sourcesContent":["/**\n * Demo data sources for the public demo\n */\nexport const DEMO_DATA_SOURCES = [\n {\n id: 'sales',\n table: 'sales_transactions',\n name: 'Sales Transactions',\n description: 'E-commerce sales data from 2022-2024 including orders, revenue, and customer information',\n },\n {\n id: 'customers',\n table: 'customers',\n name: 'Customer Data',\n description: 'Customer profiles including demographics, segments, and lifetime value',\n },\n {\n id: 'products',\n table: 'products',\n name: 'Product Catalog',\n description: 'Product information including categories, pricing, and inventory',\n },\n];\n/**\n * Demo schemas for the data sources\n */\nexport const DEMO_SCHEMAS = new Map([\n ['sales', {\n table: 'sales_transactions',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Transaction ID' },\n { name: 'date', type: 'date', nullable: false, description: 'Transaction date' },\n { name: 'customer_id', type: 'number', nullable: false, description: 'Customer reference' },\n { name: 'product_id', type: 'number', nullable: false, description: 'Product reference' },\n { name: 'quantity', type: 'number', nullable: false, description: 'Units sold' },\n { name: 'revenue', type: 'number', nullable: false, description: 'Total sale amount in USD' },\n { name: 'region', type: 'string', nullable: false, description: 'Sales region (North, South, East, West)' },\n { name: 'channel', type: 'string', nullable: false, description: 'Sales channel (Online, Retail, Wholesale)' },\n ],\n }],\n ['customers', {\n table: 'customers',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Customer ID' },\n { name: 'name', type: 'string', nullable: false, description: 'Customer name' },\n { name: 'email', type: 'string', nullable: false, description: 'Email address' },\n { name: 'segment', type: 'string', nullable: false, description: 'Customer segment (Enterprise, SMB, Consumer)' },\n { name: 'country', type: 'string', nullable: false, description: 'Country' },\n { name: 'created_at', type: 'date', nullable: false, description: 'Account creation date' },\n { name: 'lifetime_value', type: 'number', nullable: true, description: 'Total lifetime spend in USD' },\n ],\n }],\n ['products', {\n table: 'products',\n columns: [\n { name: 'id', type: 'number', nullable: false, description: 'Product ID' },\n { name: 'name', type: 'string', nullable: false, description: 'Product name' },\n { name: 'category', type: 'string', nullable: false, description: 'Product category' },\n { name: 'price', type: 'number', nullable: false, description: 'Unit price in USD' },\n { name: 'cost', type: 'number', nullable: false, description: 'Unit cost in USD' },\n { name: 'stock', type: 'number', nullable: false, description: 'Current inventory' },\n ],\n }],\n]);\n/**\n * Demo scenarios with canned responses\n */\nexport const DEMO_SCENARIOS = [\n {\n dataSourceId: 'sales',\n initialData: [\n { id: 1, date: '2024-12-01', customer_id: 1001, product_id: 101, quantity: 2, revenue: 599.98, region: 'West', channel: 'Online' },\n { id: 2, date: '2024-12-01', customer_id: 1042, product_id: 203, quantity: 1, revenue: 849.99, region: 'North', channel: 'Retail' },\n { id: 3, date: '2024-12-02', customer_id: 1015, product_id: 105, quantity: 5, revenue: 149.95, region: 'East', channel: 'Online' },\n { id: 4, date: '2024-12-02', customer_id: 1088, product_id: 302, quantity: 1, revenue: 1299.00, region: 'West', channel: 'Wholesale' },\n { id: 5, date: '2024-12-03', customer_id: 1023, product_id: 118, quantity: 3, revenue: 89.97, region: 'South', channel: 'Online' },\n { id: 6, date: '2024-12-03', customer_id: 1056, product_id: 209, quantity: 2, revenue: 459.98, region: 'North', channel: 'Retail' },\n { id: 7, date: '2024-12-04', customer_id: 1077, product_id: 115, quantity: 1, revenue: 199.99, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-04', customer_id: 1034, product_id: 301, quantity: 4, revenue: 2199.96, region: 'West', channel: 'Wholesale' },\n { id: 9, date: '2024-12-05', customer_id: 1091, product_id: 122, quantity: 2, revenue: 339.98, region: 'South', channel: 'Retail' },\n { id: 10, date: '2024-12-05', customer_id: 1012, product_id: 207, quantity: 1, revenue: 749.99, region: 'North', channel: 'Online' },\n ],\n defaultResponse: `I can help you explore the sales transactions data. Here are some things you can ask me:\n\n- \"Show me total revenue by region\"\n- \"What are the top selling products?\"\n- \"Show me sales trends over time\"\n- \"Which sales channel performs best?\"\n- \"Show me sales with customer names\" (JOIN example)\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['revenue', 'region'],\n response: `I'll query the sales table to show total revenue broken down by region.\n\nHere's my approach:\n1. **regional_summary**: Group all transactions by region and calculate totals\n\n\\`\\`\\`sql\n-- Calculate revenue and transaction counts for each region\nWITH regional_summary AS (\n SELECT \n region,\n SUM(revenue) as total_revenue,\n COUNT(*) as transaction_count\n FROM sales_transactions\n GROUP BY region\n)\n-- Return regions sorted by revenue (highest first)\nSELECT * FROM regional_summary\nORDER BY total_revenue DESC\n\\`\\`\\`\n\nThe results show revenue performance across all four regions. The data is now loaded in the grid - you can use the Pivot or Chart views to visualize it further.`,\n query: 'WITH regional_summary AS (SELECT region, SUM(revenue) as total_revenue, COUNT(*) as transaction_count FROM sales_transactions GROUP BY region) SELECT * FROM regional_summary ORDER BY total_revenue DESC',\n mockData: [\n { region: 'West', total_revenue: 1250000, transaction_count: 3420 },\n { region: 'North', total_revenue: 980000, transaction_count: 2890 },\n { region: 'East', total_revenue: 875000, transaction_count: 2650 },\n { region: 'South', total_revenue: 720000, transaction_count: 2140 },\n ],\n },\n {\n keywords: ['top', 'product', 'best', 'selling'],\n response: `I'll find the top selling products by revenue.\n\nHere's my approach:\n1. **product_totals**: Sum up revenue and units for each product\n2. **ranked_products**: Take only the top 10 performers\n\n\\`\\`\\`sql\n-- Aggregate sales by product\nWITH product_totals AS (\n SELECT \n product_id,\n SUM(revenue) as total_revenue,\n SUM(quantity) as units_sold\n FROM sales_transactions\n GROUP BY product_id\n),\n-- Rank and limit to top performers\nranked_products AS (\n SELECT * FROM product_totals\n ORDER BY total_revenue DESC\n LIMIT 10\n)\nSELECT * FROM ranked_products\n\\`\\`\\`\n\nHere are the top 10 products by revenue. You might want to join this with the Products table to see product names.`,\n query: 'WITH product_totals AS (SELECT product_id, SUM(revenue) as total_revenue, SUM(quantity) as units_sold FROM sales_transactions GROUP BY product_id), ranked_products AS (SELECT * FROM product_totals ORDER BY total_revenue DESC LIMIT 10) SELECT * FROM ranked_products',\n mockData: [\n { product_id: 101, total_revenue: 425000, units_sold: 1250 },\n { product_id: 203, total_revenue: 380000, units_sold: 890 },\n { product_id: 105, total_revenue: 315000, units_sold: 2100 },\n { product_id: 302, total_revenue: 290000, units_sold: 560 },\n { product_id: 118, total_revenue: 245000, units_sold: 1800 },\n { product_id: 209, total_revenue: 220000, units_sold: 750 },\n { product_id: 115, total_revenue: 195000, units_sold: 1400 },\n { product_id: 301, total_revenue: 180000, units_sold: 320 },\n { product_id: 122, total_revenue: 165000, units_sold: 980 },\n { product_id: 207, total_revenue: 155000, units_sold: 620 },\n ],\n },\n {\n keywords: ['trend', 'time', 'month', 'over time'],\n response: `I'll show you the sales trends over time, grouped by month.\n\nHere's my approach:\n1. **monthly_metrics**: Truncate dates to month and aggregate revenue/transactions\n\n\\`\\`\\`sql\n-- Group transactions by month and calculate totals\nWITH monthly_metrics AS (\n SELECT \n DATE_TRUNC('month', date) as month,\n SUM(revenue) as monthly_revenue,\n COUNT(*) as transactions\n FROM sales_transactions\n GROUP BY DATE_TRUNC('month', date)\n)\n-- Return in chronological order\nSELECT * FROM monthly_metrics\nORDER BY month\n\\`\\`\\`\n\nThe data shows monthly revenue trends. Try using the Chart view with a Line chart to visualize this trend!`,\n query: 'WITH monthly_metrics AS (SELECT DATE_TRUNC(\\'month\\', date) as month, SUM(revenue) as monthly_revenue, COUNT(*) as transactions FROM sales_transactions GROUP BY DATE_TRUNC(\\'month\\', date)) SELECT * FROM monthly_metrics ORDER BY month',\n mockData: [\n { month: '2024-01-01', monthly_revenue: 285000, transactions: 820 },\n { month: '2024-02-01', monthly_revenue: 310000, transactions: 890 },\n { month: '2024-03-01', monthly_revenue: 345000, transactions: 950 },\n { month: '2024-04-01', monthly_revenue: 320000, transactions: 910 },\n { month: '2024-05-01', monthly_revenue: 380000, transactions: 1050 },\n { month: '2024-06-01', monthly_revenue: 410000, transactions: 1120 },\n { month: '2024-07-01', monthly_revenue: 395000, transactions: 1080 },\n { month: '2024-08-01', monthly_revenue: 425000, transactions: 1150 },\n { month: '2024-09-01', monthly_revenue: 390000, transactions: 1060 },\n { month: '2024-10-01', monthly_revenue: 445000, transactions: 1200 },\n { month: '2024-11-01', monthly_revenue: 520000, transactions: 1380 },\n { month: '2024-12-01', monthly_revenue: 480000, transactions: 1290 },\n ],\n },\n {\n keywords: ['channel', 'online', 'retail', 'wholesale'],\n response: `I'll compare performance across sales channels.\n\nHere's my approach:\n1. **channel_metrics**: Calculate total revenue, transaction count, and average order value per channel\n\n\\`\\`\\`sql\n-- Aggregate key metrics by sales channel\nWITH channel_metrics AS (\n SELECT \n channel,\n SUM(revenue) as total_revenue,\n COUNT(*) as transactions,\n AVG(revenue) as avg_order_value\n FROM sales_transactions\n GROUP BY channel\n)\n-- Return sorted by total revenue\nSELECT * FROM channel_metrics\nORDER BY total_revenue DESC\n\\`\\`\\`\n\nThis shows revenue and average order value by channel. Online has the highest volume while Wholesale has the highest average order value.`,\n query: 'WITH channel_metrics AS (SELECT channel, SUM(revenue) as total_revenue, COUNT(*) as transactions, AVG(revenue) as avg_order_value FROM sales_transactions GROUP BY channel) SELECT * FROM channel_metrics ORDER BY total_revenue DESC',\n mockData: [\n { channel: 'Online', total_revenue: 1850000, transactions: 6500, avg_order_value: 284.62 },\n { channel: 'Retail', total_revenue: 1200000, transactions: 3800, avg_order_value: 315.79 },\n { channel: 'Wholesale', total_revenue: 775000, transactions: 800, avg_order_value: 968.75 },\n ],\n },\n {\n keywords: ['customer name', 'with customer', 'join customer', 'customer info'],\n response: `I'll join the sales data with customers to show you sales with customer names.\n\nHere's my approach:\n1. **JOIN**: Link sales_transactions with customers table on customer_id\n\n\\`\\`\\`sql\n-- Join sales with customer information\nSELECT \n s.id,\n s.date,\n c.name as customer_name,\n c.segment,\n s.revenue,\n s.quantity,\n s.region,\n s.channel\nFROM sales_transactions s\nJOIN customers c ON s.customer_id = c.id\nORDER BY s.date DESC\n\\`\\`\\`\n\nHere are the sales records enriched with customer names and segments. You can now filter or pivot by customer segment!`,\n query: 'SELECT s.id, s.date, c.name as customer_name, c.segment, s.revenue, s.quantity, s.region, s.channel FROM sales_transactions s JOIN customers c ON s.customer_id = c.id ORDER BY s.date DESC',\n mockData: [\n { id: 1, date: '2024-12-05', customer_name: 'Acme Corporation', segment: 'Enterprise', revenue: 2499.99, quantity: 5, region: 'West', channel: 'Wholesale' },\n { id: 2, date: '2024-12-05', customer_name: 'Jane Smith', segment: 'Consumer', revenue: 149.99, quantity: 2, region: 'North', channel: 'Online' },\n { id: 3, date: '2024-12-04', customer_name: 'TechStart Inc', segment: 'SMB', revenue: 899.97, quantity: 3, region: 'East', channel: 'Retail' },\n { id: 4, date: '2024-12-04', customer_name: 'Global Industries', segment: 'Enterprise', revenue: 4599.99, quantity: 10, region: 'West', channel: 'Wholesale' },\n { id: 5, date: '2024-12-03', customer_name: 'John Doe', segment: 'Consumer', revenue: 79.99, quantity: 1, region: 'South', channel: 'Online' },\n { id: 6, date: '2024-12-03', customer_name: 'Nordic Solutions', segment: 'Enterprise', revenue: 1899.99, quantity: 4, region: 'North', channel: 'Retail' },\n { id: 7, date: '2024-12-02', customer_name: 'Boutique Shop', segment: 'SMB', revenue: 449.97, quantity: 3, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-02', customer_name: 'Maria Garcia', segment: 'Consumer', revenue: 129.99, quantity: 1, region: 'South', channel: 'Online' },\n { id: 9, date: '2024-12-01', customer_name: 'Local Crafts Co', segment: 'SMB', revenue: 679.98, quantity: 2, region: 'West', channel: 'Retail' },\n { id: 10, date: '2024-12-01', customer_name: 'Alex Johnson', segment: 'Consumer', revenue: 59.99, quantity: 1, region: 'North', channel: 'Online' },\n ],\n },\n {\n keywords: ['product name', 'with product', 'join product', 'product info', 'product detail'],\n response: `I'll join the sales data with products to show you sales with product details.\n\nHere's my approach:\n1. **JOIN**: Link sales_transactions with products table on product_id\n\n\\`\\`\\`sql\n-- Join sales with product information\nSELECT \n s.id,\n s.date,\n p.name as product_name,\n p.category,\n s.quantity,\n s.revenue,\n s.region,\n s.channel\nFROM sales_transactions s\nJOIN products p ON s.product_id = p.id\nORDER BY s.revenue DESC\n\\`\\`\\`\n\nHere are the sales records enriched with product names and categories. Try pivoting by category to see which product types sell best!`,\n query: 'SELECT s.id, s.date, p.name as product_name, p.category, s.quantity, s.revenue, s.region, s.channel FROM sales_transactions s JOIN products p ON s.product_id = p.id ORDER BY s.revenue DESC',\n mockData: [\n { id: 1, date: '2024-12-04', product_name: 'Standing Desk Frame', category: 'Home & Garden', quantity: 3, revenue: 1049.97, region: 'West', channel: 'Wholesale' },\n { id: 2, date: '2024-12-05', product_name: 'Bluetooth Headphones', category: 'Electronics', quantity: 4, revenue: 599.96, region: 'North', channel: 'Retail' },\n { id: 3, date: '2024-12-03', product_name: 'Running Shoes Elite', category: 'Sports', quantity: 3, revenue: 389.97, region: 'East', channel: 'Online' },\n { id: 4, date: '2024-12-02', product_name: 'Wireless Mouse Pro', category: 'Electronics', quantity: 4, revenue: 319.96, region: 'South', channel: 'Online' },\n { id: 5, date: '2024-12-05', product_name: 'Denim Jeans Classic', category: 'Clothing', quantity: 3, revenue: 209.97, region: 'West', channel: 'Retail' },\n { id: 6, date: '2024-12-01', product_name: 'Garden Tool Set', category: 'Home & Garden', quantity: 2, revenue: 179.98, region: 'North', channel: 'Online' },\n { id: 7, date: '2024-12-04', product_name: 'Yoga Mat Premium', category: 'Sports', quantity: 3, revenue: 137.97, region: 'East', channel: 'Online' },\n { id: 8, date: '2024-12-03', product_name: 'Cotton T-Shirt Basic', category: 'Clothing', quantity: 5, revenue: 124.95, region: 'South', channel: 'Online' },\n { id: 9, date: '2024-12-02', product_name: 'Clean Code', category: 'Books', quantity: 2, revenue: 69.98, region: 'West', channel: 'Online' },\n { id: 10, date: '2024-12-01', product_name: 'JavaScript: The Good Parts', category: 'Books', quantity: 2, revenue: 59.98, region: 'North', channel: 'Online' },\n ],\n },\n ],\n },\n {\n dataSourceId: 'customers',\n initialData: [\n { id: 1001, name: 'Acme Corporation', email: 'contact@acme.com', segment: 'Enterprise', country: 'United States', created_at: '2022-03-15', lifetime_value: 45000 },\n { id: 1002, name: 'Jane Smith', email: 'jane.smith@email.com', segment: 'Consumer', country: 'United Kingdom', created_at: '2023-06-22', lifetime_value: 850 },\n { id: 1003, name: 'TechStart Inc', email: 'info@techstart.io', segment: 'SMB', country: 'Germany', created_at: '2023-01-10', lifetime_value: 3200 },\n { id: 1004, name: 'Global Industries', email: 'sales@globalind.com', segment: 'Enterprise', country: 'United States', created_at: '2021-11-08', lifetime_value: 78500 },\n { id: 1005, name: 'John Doe', email: 'johndoe@gmail.com', segment: 'Consumer', country: 'Canada', created_at: '2024-02-14', lifetime_value: 320 },\n { id: 1006, name: 'Boutique Shop', email: 'hello@boutique.fr', segment: 'SMB', country: 'France', created_at: '2023-08-30', lifetime_value: 1800 },\n { id: 1007, name: 'Maria Garcia', email: 'maria.g@outlook.com', segment: 'Consumer', country: 'Spain', created_at: '2024-05-19', lifetime_value: 450 },\n { id: 1008, name: 'Nordic Solutions', email: 'contact@nordic.se', segment: 'Enterprise', country: 'Sweden', created_at: '2022-07-03', lifetime_value: 32000 },\n { id: 1009, name: 'Local Crafts Co', email: 'orders@localcrafts.au', segment: 'SMB', country: 'Australia', created_at: '2023-11-25', lifetime_value: 2100 },\n { id: 1010, name: 'Alex Johnson', email: 'alex.j@proton.me', segment: 'Consumer', country: 'United States', created_at: '2024-09-02', lifetime_value: 180 },\n ],\n defaultResponse: `I can help you explore the customer data. Here are some things you can ask me:\n\n- \"Show me customers by segment\"\n- \"What's the average lifetime value?\"\n- \"Which countries have the most customers?\"\n- \"Show me recent signups\"\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['segment', 'breakdown'],\n response: `I'll show you the customer breakdown by segment.\n\n\\`\\`\\`sql\nSELECT segment, COUNT(*) as customer_count, AVG(lifetime_value) as avg_ltv\nFROM customers\nGROUP BY segment\nORDER BY customer_count DESC\n\\`\\`\\`\n\nHere's the distribution across segments. Enterprise customers have the highest average lifetime value.`,\n query: 'SELECT segment, COUNT(*) as customer_count, AVG(lifetime_value) as avg_ltv FROM customers GROUP BY segment ORDER BY customer_count DESC',\n mockData: [\n { segment: 'Consumer', customer_count: 8500, avg_ltv: 450 },\n { segment: 'SMB', customer_count: 2800, avg_ltv: 2200 },\n { segment: 'Enterprise', customer_count: 450, avg_ltv: 18500 },\n ],\n },\n {\n keywords: ['lifetime', 'value', 'ltv'],\n response: `I'll calculate lifetime value statistics across the customer base.\n\n\\`\\`\\`sql\nSELECT \n COUNT(*) as total_customers,\n AVG(lifetime_value) as avg_ltv,\n MAX(lifetime_value) as max_ltv,\n MIN(lifetime_value) as min_ltv,\n SUM(lifetime_value) as total_ltv\nFROM customers\n\\`\\`\\`\n\nThe average customer lifetime value is $1,250 with significant variation between segments.`,\n query: 'SELECT COUNT(*) as total_customers, AVG(lifetime_value) as avg_ltv, MAX(lifetime_value) as max_ltv, MIN(lifetime_value) as min_ltv, SUM(lifetime_value) as total_ltv FROM customers',\n mockData: [\n { total_customers: 11750, avg_ltv: 1250, max_ltv: 85000, min_ltv: 25, total_ltv: 14687500 },\n ],\n },\n {\n keywords: ['country', 'countries', 'location'],\n response: `I'll show you the customer distribution by country.\n\n\\`\\`\\`sql\nSELECT country, COUNT(*) as customer_count, SUM(lifetime_value) as total_ltv\nFROM customers\nGROUP BY country\nORDER BY customer_count DESC\nLIMIT 10\n\\`\\`\\`\n\nHere are the top 10 countries by customer count.`,\n query: 'SELECT country, COUNT(*) as customer_count, SUM(lifetime_value) as total_ltv FROM customers GROUP BY country ORDER BY customer_count DESC LIMIT 10',\n mockData: [\n { country: 'United States', customer_count: 4200, total_ltv: 5800000 },\n { country: 'United Kingdom', customer_count: 1850, total_ltv: 2100000 },\n { country: 'Germany', customer_count: 1200, total_ltv: 1450000 },\n { country: 'Canada', customer_count: 980, total_ltv: 1100000 },\n { country: 'France', customer_count: 750, total_ltv: 890000 },\n { country: 'Australia', customer_count: 620, total_ltv: 720000 },\n { country: 'Japan', customer_count: 480, total_ltv: 650000 },\n { country: 'Netherlands', customer_count: 350, total_ltv: 420000 },\n { country: 'Spain', customer_count: 290, total_ltv: 340000 },\n { country: 'Italy', customer_count: 250, total_ltv: 280000 },\n ],\n },\n ],\n },\n {\n dataSourceId: 'products',\n initialData: [\n { id: 101, name: 'Wireless Mouse Pro', category: 'Electronics', price: 79.99, cost: 35.00, stock: 450 },\n { id: 102, name: 'Cotton T-Shirt Basic', category: 'Clothing', price: 24.99, cost: 8.50, stock: 1200 },\n { id: 103, name: 'Standing Desk Frame', category: 'Home & Garden', price: 349.99, cost: 180.00, stock: 85 },\n { id: 104, name: 'Running Shoes Elite', category: 'Sports', price: 129.99, cost: 55.00, stock: 320 },\n { id: 105, name: 'JavaScript: The Good Parts', category: 'Books', price: 29.99, cost: 10.00, stock: 580 },\n { id: 106, name: 'Bluetooth Headphones', category: 'Electronics', price: 149.99, cost: 65.00, stock: 280 },\n { id: 107, name: 'Denim Jeans Classic', category: 'Clothing', price: 69.99, cost: 28.00, stock: 890 },\n { id: 108, name: 'Garden Tool Set', category: 'Home & Garden', price: 89.99, cost: 38.00, stock: 150 },\n { id: 109, name: 'Yoga Mat Premium', category: 'Sports', price: 45.99, cost: 18.00, stock: 420 },\n { id: 110, name: 'Clean Code', category: 'Books', price: 34.99, cost: 12.00, stock: 340 },\n ],\n defaultResponse: `I can help you explore the product catalog. Here are some things you can ask me:\n\n- \"Show me products by category\"\n- \"What are the profit margins?\"\n- \"Which products are low on stock?\"\n- \"Show me the price distribution\"\n\nWhat would you like to know?`,\n triggers: [\n {\n keywords: ['category', 'categories'],\n response: `I'll show you the product breakdown by category.\n\n\\`\\`\\`sql\nSELECT category, COUNT(*) as product_count, AVG(price) as avg_price, SUM(stock) as total_stock\nFROM products\nGROUP BY category\nORDER BY product_count DESC\n\\`\\`\\`\n\nHere's the distribution of products across categories.`,\n query: 'SELECT category, COUNT(*) as product_count, AVG(price) as avg_price, SUM(stock) as total_stock FROM products GROUP BY category ORDER BY product_count DESC',\n mockData: [\n { category: 'Electronics', product_count: 450, avg_price: 299.99, total_stock: 12500 },\n { category: 'Clothing', product_count: 380, avg_price: 59.99, total_stock: 28000 },\n { category: 'Home & Garden', product_count: 290, avg_price: 89.99, total_stock: 15000 },\n { category: 'Sports', product_count: 220, avg_price: 79.99, total_stock: 9500 },\n { category: 'Books', product_count: 180, avg_price: 24.99, total_stock: 22000 },\n ],\n },\n {\n keywords: ['margin', 'profit', 'cost'],\n response: `I'll calculate the profit margins by category.\n\n\\`\\`\\`sql\nSELECT category, AVG(price) as avg_price, AVG(cost) as avg_cost, AVG(price - cost) as avg_margin, AVG((price - cost) / price * 100) as margin_percent\nFROM products\nGROUP BY category\nORDER BY margin_percent DESC\n\\`\\`\\`\n\nHere are the profit margins. Electronics has the highest absolute margin while Books has the best percentage margin.`,\n query: 'SELECT category, AVG(price) as avg_price, AVG(cost) as avg_cost, AVG(price - cost) as avg_margin, AVG((price - cost) / price * 100) as margin_percent FROM products GROUP BY category ORDER BY margin_percent DESC',\n mockData: [\n { category: 'Books', avg_price: 24.99, avg_cost: 8.50, avg_margin: 16.49, margin_percent: 65.99 },\n { category: 'Clothing', avg_price: 59.99, avg_cost: 22.00, avg_margin: 37.99, margin_percent: 63.33 },\n { category: 'Home & Garden', avg_price: 89.99, avg_cost: 38.00, avg_margin: 51.99, margin_percent: 57.77 },\n { category: 'Sports', avg_price: 79.99, avg_cost: 35.00, avg_margin: 44.99, margin_percent: 56.24 },\n { category: 'Electronics', avg_price: 299.99, avg_cost: 180.00, avg_margin: 119.99, margin_percent: 40.00 },\n ],\n },\n {\n keywords: ['stock', 'inventory', 'low'],\n response: `I'll find products with low stock levels.\n\n\\`\\`\\`sql\nSELECT name, category, stock, price\nFROM products\nWHERE stock < 50\nORDER BY stock ASC\nLIMIT 20\n\\`\\`\\`\n\nThese products are running low on inventory and may need restocking soon.`,\n query: 'SELECT name, category, stock, price FROM products WHERE stock < 50 ORDER BY stock ASC LIMIT 20',\n mockData: [\n { name: 'Premium Headphones Pro', category: 'Electronics', stock: 5, price: 349.99 },\n { name: 'Vintage Leather Jacket', category: 'Clothing', stock: 8, price: 299.99 },\n { name: 'Smart Home Hub', category: 'Electronics', stock: 12, price: 199.99 },\n { name: 'Designer Sunglasses', category: 'Clothing', stock: 15, price: 189.99 },\n { name: 'Ergonomic Office Chair', category: 'Home & Garden', stock: 18, price: 449.99 },\n { name: 'Wireless Earbuds Elite', category: 'Electronics', stock: 22, price: 179.99 },\n { name: 'Cashmere Sweater', category: 'Clothing', stock: 25, price: 249.99 },\n { name: 'Smart Watch Series X', category: 'Electronics', stock: 28, price: 399.99 },\n { name: 'Premium Yoga Mat', category: 'Sports', stock: 32, price: 89.99 },\n { name: 'Espresso Machine Pro', category: 'Home & Garden', stock: 35, price: 599.99 },\n ],\n },\n ],\n },\n];\n/**\n * Find a matching demo response for a user message\n */\nexport function findDemoResponse(dataSourceId, userMessage) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n if (!scenario) {\n return null;\n }\n const lowerMessage = userMessage.toLowerCase();\n for (const trigger of scenario.triggers) {\n const hasMatch = trigger.keywords.some(keyword => lowerMessage.includes(keyword.toLowerCase()));\n if (hasMatch) {\n return trigger;\n }\n }\n return null;\n}\n/**\n * Get the default response for a data source when no trigger matches\n */\nexport function getDefaultDemoResponse(dataSourceId) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n return scenario?.defaultResponse || 'Please select a data source to get started.';\n}\n/**\n * Get demo schema for a data source\n */\nexport function getDemoSchema(dataSourceId) {\n return DEMO_SCHEMAS.get(dataSourceId);\n}\n/**\n * Get initial sample data for a data source (shown when first selected)\n */\nexport function getInitialDemoData(dataSourceId) {\n const scenario = DEMO_SCENARIOS.find(s => s.dataSourceId === dataSourceId);\n return scenario?.initialData;\n}\n//# sourceMappingURL=demo.js.map","/**\n * Build the system prompt for the AI Data Analyst\n * @param dataSources - List of available data sources\n * @param schemas - Map of table schemas (selected table schema)\n * @param selectedSourceId - Currently selected data source ID\n * @param allSchemas - Optional: ALL table schemas for enabling JOINs\n */\nexport function buildSystemPrompt(dataSources, schemas, selectedSourceId, allSchemas) {\n const selectedSchema = selectedSourceId ? schemas.get(selectedSourceId) : undefined;\n const selectedSource = selectedSourceId\n ? dataSources.find(ds => ds.id === selectedSourceId)\n : undefined;\n // Filter out the selected table from allSchemas to get \"other tables\"\n const otherTables = allSchemas?.filter(s => s.table !== selectedSchema?.table) || [];\n return `You are a data analyst assistant. Your job is to translate user questions into SQL queries and return data results.\n\n## CRITICAL: ALWAYS GENERATE A SQL QUERY\n**Every response MUST include a SQL query.** The user is here to explore data - they expect to see results.\n- If the user asks a question → Generate a query to answer it\n- If the user says \"show me\" or \"what are\" → Generate a query\n- If the user asks for trends/patterns → Generate an aggregation query\n- If the question is vague → Make reasonable assumptions and generate a query anyway\n- If you're unsure what they want → Generate a sensible default query (like top 10 rows with key columns)\n\n**NEVER respond with only text. ALWAYS include a SQL query in your response.**\n\n## Available Data Sources\n${formatDataSourcesList(dataSources)}\n\n${selectedSource && selectedSchema ? formatSelectedSchemaContext(selectedSource, selectedSchema) : '## No Data Source Selected\\nPlease ask the user to select a data source first.'}\n\n${otherTables.length > 0 ? formatRelatedTablesContext(otherTables) : ''}\n\n## Query Rules\n1. **READ-ONLY**: ONLY use SELECT. NEVER use INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, or any write operations.\n2. **NO LIMIT**: Do NOT add LIMIT clauses unless the user explicitly asks for a limited number of results. Return all matching rows by default.\n3. **PRIMARY TABLE**: The main table is \\`${selectedSchema?.table || 'table_name'}\\`\n4. **JOINs ALLOWED**: You CAN JOIN with other tables listed in \"Related Tables\" when the user needs data from multiple tables.\n5. **BE SPECIFIC**: Select relevant columns, not SELECT * (unless showing sample data)\n\n## Query Format\nOutput queries in this EXACT format (the system auto-executes SQL blocks):\n\n\\`\\`\\`sql\nSELECT column1, column2 FROM ${selectedSchema?.table || 'table_name'} WHERE condition\n\\`\\`\\`\n\nFor JOINs (when user needs data from related tables):\n\\`\\`\\`sql\nSELECT p.column1, r.column2 \nFROM ${selectedSchema?.table || 'primary_table'} p\nJOIN related_table r ON p.foreign_key = r.id\nWHERE condition\n\\`\\`\\`\n\nFor complex analysis, use CTEs:\n\\`\\`\\`sql\nWITH summary AS (\n SELECT category, COUNT(*) as count\n FROM ${selectedSchema?.table || 'table_name'}\n GROUP BY category\n)\nSELECT * FROM summary ORDER BY count DESC\n\\`\\`\\`\n\n## Response Format\nKeep responses concise and insight-focused:\n1. **Start with the SQL query** in a code block (REQUIRED) - this will be extracted and hidden from the user\n2. **Then provide your insight/analysis** (2-3 sentences) explaining what the data shows\n3. **Optional**: Suggest 1-2 follow-up questions\n\n**IMPORTANT**: The SQL block is automatically extracted and shown separately. Your text response should focus on INSIGHTS about the data, not describing the query itself. Don't say \"I'm querying...\" or \"This query shows...\". Instead, provide the analytical insight directly.\n\nExample response:\n\"\\`\\`\\`sql\nSELECT department, AVG(salary) as avg_salary FROM employees GROUP BY department ORDER BY avg_salary DESC\n\\`\\`\\`\n\nEngineering and Product teams have the highest average salaries at $145K and $138K respectively, while Support and Operations are at the lower end around $75K. This 2x salary gap may indicate market-driven compensation or role complexity differences.\n\nWant to see how this breaks down by job level?\"\n\n## If Query Fails\n- Acknowledge the error briefly\n- Provide a corrected query immediately\n- Don't apologize excessively, just fix it`;\n}\n/**\n * Format the list of available data sources for the prompt\n */\nfunction formatDataSourcesList(dataSources) {\n if (dataSources.length === 0) {\n return 'No data sources configured.';\n }\n return dataSources\n .map((ds) => {\n const desc = ds.description ? `: ${ds.description}` : '';\n return `- **${ds.name}** (${ds.table})${desc}`;\n })\n .join('\\n');\n}\n/**\n * Format the schema context for the currently selected data source\n */\nfunction formatSelectedSchemaContext(source, schema) {\n // Filter out hidden columns\n const visibleColumns = schema.columns.filter((col) => {\n const override = source.columns?.find(c => c.name === col.name);\n return !override?.hidden;\n });\n // Merge descriptions from overrides\n const columnsWithDescriptions = visibleColumns.map((col) => {\n const override = source.columns?.find(c => c.name === col.name);\n return {\n ...col,\n description: override?.description || col.description,\n };\n });\n return `## Currently Selected: ${source.name}\nTable: \\`${schema.table}\\`\n${source.description ? `Description: ${source.description}` : ''}\n\n### Columns\n${formatColumnsTable(columnsWithDescriptions)}\n\n### Query Tips\n- Use column names exactly as shown above\n- The table name is \\`${schema.table}\\`\n- For text searches, use ILIKE for case-insensitive matching\n- For date columns, use standard SQL date functions`;\n}\n/**\n * Format the context for related tables that can be JOINed\n */\nfunction formatRelatedTablesContext(tables) {\n if (tables.length === 0)\n return '';\n const tablesSummary = tables.map((table) => {\n // Show table name and key columns (likely join keys)\n const keyColumns = table.columns\n .filter(col => col.name === 'id'\n || col.name.endsWith('_id')\n || col.name.startsWith('id_')\n || col.name === 'uuid')\n .map(col => `\\`${col.name}\\``)\n .join(', ');\n const otherColumns = table.columns\n .filter(col => col.name !== 'id'\n && !col.name.endsWith('_id')\n && !col.name.startsWith('id_')\n && col.name !== 'uuid')\n .slice(0, 5) // Show up to 5 other columns\n .map(col => `\\`${col.name}\\` (${col.type})`)\n .join(', ');\n const moreCount = table.columns.length - (keyColumns ? keyColumns.split(',').length : 0) - 5;\n const moreText = moreCount > 0 ? `, +${moreCount} more` : '';\n return `- **\\`${table.table}\\`**\n - Keys: ${keyColumns || 'none'}\n - Columns: ${otherColumns}${moreText}`;\n }).join('\\n');\n return `## Related Tables (Available for JOINs)\nYou can JOIN with these tables when the user needs additional data.\nLook for foreign key relationships (columns ending in \\`_id\\`).\n\n${tablesSummary}\n`;\n}\n/**\n * Format columns as a readable table for the prompt\n */\nfunction formatColumnsTable(columns) {\n return columns\n .map((col) => {\n const nullable = col.nullable ? 'nullable' : 'required';\n const desc = col.description ? ` - ${col.description}` : '';\n return `- \\`${col.name}\\` (${col.type}, ${nullable})${desc}`;\n })\n .join('\\n');\n}\n/**\n * Build a user message with additional context\n */\nexport function buildUserMessage(userInput, context) {\n let message = userInput;\n if (context?.previousQueryFailed && context.errorMessage) {\n message = `[Previous query failed: ${context.errorMessage}]\\n\\n${userInput}`;\n }\n return message;\n}\n/**\n * Extract SQL query from AI response\n * Returns the SQL if found, null otherwise\n */\nexport function extractSQLFromResponse(response) {\n // Match SQL code blocks\n const sqlBlockRegex = /```sql\\s*([\\s\\S]*?)```/i;\n const match = response.match(sqlBlockRegex);\n if (match && match[1]) {\n const sql = match[1].trim();\n // Validate it's a SELECT statement\n if (!sql.toUpperCase().startsWith('SELECT')) {\n return null;\n }\n return sql;\n }\n return null;\n}\n/**\n * Validate that a SQL query is safe (read-only)\n */\nexport function validateSQLSafety(sql) {\n const upperSQL = sql.toUpperCase().trim();\n // Must start with SELECT or WITH (for CTEs)\n if (!upperSQL.startsWith('SELECT') && !upperSQL.startsWith('WITH')) {\n return { valid: false, error: 'Only SELECT queries (including CTEs with WITH) are allowed' };\n }\n // If it starts with WITH, ensure it ends with a SELECT\n if (upperSQL.startsWith('WITH') && !upperSQL.includes('SELECT')) {\n return { valid: false, error: 'CTE queries must include a final SELECT statement' };\n }\n // Check for dangerous keywords\n const dangerousKeywords = [\n 'INSERT',\n 'UPDATE',\n 'DELETE',\n 'DROP',\n 'ALTER',\n 'TRUNCATE',\n 'CREATE',\n 'GRANT',\n 'REVOKE',\n 'EXEC',\n 'EXECUTE',\n 'INTO', // SELECT INTO\n ];\n for (const keyword of dangerousKeywords) {\n // Check for keyword as a whole word (not part of column name)\n const regex = new RegExp(`\\\\b${keyword}\\\\b`, 'i');\n if (regex.test(sql)) {\n return { valid: false, error: `Query contains forbidden keyword: ${keyword}` };\n }\n }\n // Check for multiple statements\n if (sql.includes(';')) {\n const statements = sql.split(';').filter(s => s.trim().length > 0);\n if (statements.length > 1) {\n return { valid: false, error: 'Multiple statements are not allowed' };\n }\n }\n return { valid: true };\n}\n/**\n * Build a summary message after query results are returned\n */\nexport function buildResultsSummary(rowCount, truncated, maxRows) {\n if (rowCount === 0) {\n return 'The query returned no results. You may want to adjust your filters or try a different approach.';\n }\n if (truncated) {\n return `Retrieved ${rowCount} rows (limited to ${maxRows}). There may be more data matching your query. Consider adding filters to narrow down the results.`;\n }\n return `Retrieved ${rowCount} row${rowCount === 1 ? '' : 's'}.`;\n}\n/**\n * Strip SQL code blocks from message content for display\n * The SQL is stored in metadata and shown via a button instead\n */\nexport function stripSQLFromContent(content) {\n // Remove SQL code blocks and any surrounding whitespace\n return content\n .replace(/```sql\\s*[\\s\\S]*?```\\s*/gi, '')\n .trim();\n}\n//# sourceMappingURL=prompts.js.map","/**\n * Generate a unique session ID\n */\nexport function generateSessionId() {\n return `tp-ai-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n}\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId() {\n return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n/**\n * Create a new empty conversation\n */\nexport function createConversation(sessionId) {\n const now = Date.now();\n return {\n id: sessionId || generateSessionId(),\n messages: [],\n dataSourceId: undefined,\n createdAt: now,\n updatedAt: now,\n };\n}\n/**\n * Create a user message\n */\nexport function createUserMessage(content) {\n return {\n id: generateMessageId(),\n role: 'user',\n content,\n timestamp: Date.now(),\n };\n}\n/**\n * Create an assistant message\n */\nexport function createAssistantMessage(content, metadata) {\n return {\n id: generateMessageId(),\n role: 'assistant',\n content,\n timestamp: Date.now(),\n metadata,\n };\n}\n/**\n * Create a system message\n */\nexport function createSystemMessage(content) {\n return {\n id: generateMessageId(),\n role: 'system',\n content,\n timestamp: Date.now(),\n };\n}\n/**\n * Add a message to a conversation (immutably)\n */\nexport function addMessageToConversation(conversation, message) {\n return {\n ...conversation,\n messages: [...conversation.messages, message],\n updatedAt: Date.now(),\n };\n}\n/**\n * Update the data source for a conversation\n */\nexport function setConversationDataSource(conversation, dataSourceId) {\n return {\n ...conversation,\n dataSourceId,\n updatedAt: Date.now(),\n };\n}\n/**\n * Serialize a conversation to JSON string for storage\n */\nexport function serializeConversation(conversation) {\n return JSON.stringify(conversation);\n}\n/**\n * Deserialize a conversation from JSON string\n */\nexport function deserializeConversation(json) {\n try {\n const parsed = JSON.parse(json);\n // Basic validation\n if (typeof parsed !== 'object'\n || !parsed.id\n || !Array.isArray(parsed.messages)) {\n return null;\n }\n return parsed;\n }\n catch {\n return null;\n }\n}\n/**\n * Get the messages formatted for the AI API\n * Excludes system messages and metadata\n */\nexport function getMessagesForAPI(conversation) {\n return conversation.messages\n .filter(m => m.role !== 'system')\n .map(m => ({\n role: m.role,\n content: m.content,\n }));\n}\n/**\n * Trim conversation to last N messages to manage context window\n */\nexport function trimConversation(conversation, maxMessages) {\n if (conversation.messages.length <= maxMessages) {\n return conversation;\n }\n return {\n ...conversation,\n messages: conversation.messages.slice(-maxMessages),\n updatedAt: Date.now(),\n };\n}\n/**\n * Get conversation statistics\n */\nexport function getConversationStats(conversation) {\n const messages = conversation.messages;\n const queriesExecuted = messages.filter(m => m.metadata?.query).length;\n const failedQueries = messages.filter(m => m.metadata?.error).length;\n return {\n messageCount: messages.length,\n userMessageCount: messages.filter(m => m.role === 'user').length,\n assistantMessageCount: messages.filter(m => m.role === 'assistant').length,\n queriesExecuted,\n successfulQueries: queriesExecuted - failedQueries,\n failedQueries,\n };\n}\n//# sourceMappingURL=session.js.map","/**\n * Chart type definitions with metadata\n */\nexport const CHART_TYPES = [\n {\n type: 'bar',\n label: 'Bar Chart',\n icon: 'bar',\n description: 'Compare values across categories',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a category to X-axis and a number to Y-axis',\n bestFor: ['Comparing categories', 'Ranking', 'Part-to-whole'],\n },\n {\n type: 'stackedBar',\n label: 'Stacked Bar',\n icon: 'stackedBar',\n description: 'Compare composition across categories',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a category to X-axis, a number to Y-axis, and a grouping field to Series',\n bestFor: ['Part-to-whole comparison', 'Composition over categories', 'Cumulative totals'],\n },\n {\n type: 'line',\n label: 'Line Chart',\n icon: 'line',\n description: 'Show trends over time or sequence',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Best with time/date on X-axis and numbers on Y-axis',\n bestFor: ['Trends over time', 'Continuous data', 'Multiple series'],\n },\n {\n type: 'area',\n label: 'Area Chart',\n icon: 'area',\n description: 'Show magnitude and trends',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Like line charts but emphasizes volume. Great for stacked comparisons.',\n bestFor: ['Cumulative totals', 'Part-to-whole over time', 'Volume trends'],\n },\n {\n type: 'pie',\n label: 'Pie Chart',\n icon: 'pie',\n description: 'Show proportions of a whole',\n requiredFields: ['dimension', 'measure'],\n optionalFields: [],\n guidance: 'Drag a category and a number. Best with 2-6 categories.',\n bestFor: ['Part-to-whole', 'Proportions', 'Simple distributions'],\n },\n {\n type: 'donut',\n label: 'Donut Chart',\n icon: 'donut',\n description: 'Proportions with center space for metrics',\n requiredFields: ['dimension', 'measure'],\n optionalFields: [],\n guidance: 'Like pie but allows showing a total in the center',\n bestFor: ['Part-to-whole', 'Showing total', 'Dashboard KPIs'],\n },\n {\n type: 'scatter',\n label: 'Scatter Plot',\n icon: 'scatter',\n description: 'Show relationships between two variables',\n requiredFields: ['measure', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Drag a number to X-axis and another number to Y-axis',\n bestFor: ['Correlation', 'Outlier detection', 'Distribution'],\n },\n {\n type: 'bubble',\n label: 'Bubble Chart',\n icon: 'bubble',\n description: 'Three-dimensional comparison',\n requiredFields: ['measure', 'measure'],\n optionalFields: ['measure', 'dimension'],\n guidance: 'Like scatter, plus drag a third number to Size for bubble size',\n bestFor: ['Multi-variable comparison', 'Weighted relationships'],\n },\n {\n type: 'heatmap',\n label: 'Heatmap',\n icon: 'heatmap',\n description: 'Visualize density or intensity',\n requiredFields: ['dimension', 'dimension', 'measure'],\n optionalFields: [],\n guidance: 'Drag two categories (X and Y) and a number to Color',\n bestFor: ['Patterns', 'Density', 'Cross-tabulation'],\n },\n {\n type: 'radar',\n label: 'Radar Chart',\n icon: 'radar',\n description: 'Compare multiple variables',\n requiredFields: ['dimension', 'measure'],\n optionalFields: ['dimension'],\n guidance: 'Best for comparing items across multiple metrics',\n bestFor: ['Multi-metric comparison', 'Performance profiles', 'Balanced scorecards'],\n },\n];\n/**\n * Aggregation options for measures\n */\nexport const CHART_AGGREGATIONS = [\n { value: 'sum', label: 'Sum', symbol: 'SUM' },\n { value: 'count', label: 'Count', symbol: 'COUNT' },\n { value: 'avg', label: 'Average', symbol: 'AVG' },\n { value: 'min', label: 'Minimum', symbol: 'MIN' },\n { value: 'max', label: 'Maximum', symbol: 'MAX' },\n { value: 'countDistinct', label: 'Count Distinct', symbol: 'DISTINCT' },\n];\n/**\n * Default color palette for charts (works in light and dark mode)\n */\nexport const CHART_COLORS = [\n '#6366f1', // indigo\n '#22c55e', // green\n '#f59e0b', // amber\n '#ef4444', // red\n '#8b5cf6', // violet\n '#06b6d4', // cyan\n '#ec4899', // pink\n '#14b8a6', // teal\n '#f97316', // orange\n '#3b82f6', // blue\n];\n/**\n * Detect the role of a field based on its data.\n *\n * When values are native JS `number` types (not numeric strings), they are\n * treated as measures regardless of cardinality — the consumer has already\n * signaled intent by providing typed numeric data.\n *\n * Pass `overrides` to explicitly set a field's role, bypassing auto-detection.\n */\nexport function detectFieldRole(data, field, overrides) {\n // Explicit override takes priority over any heuristic\n if (overrides?.[field]) {\n return overrides[field];\n }\n if (data.length === 0)\n return 'dimension';\n const sample = data.slice(0, 100);\n const values = sample.map(row => row[field]).filter(v => v !== null && v !== undefined);\n if (values.length === 0)\n return 'dimension';\n // Check if numeric\n let numericCount = 0;\n let jsNumberCount = 0;\n let dateCount = 0;\n for (const val of values) {\n if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '' && typeof val !== 'boolean')) {\n numericCount++;\n if (typeof val === 'number') {\n jsNumberCount++;\n }\n }\n if (val instanceof Date || (typeof val === 'string' && !Number.isNaN(Date.parse(val)) && val.includes('-'))) {\n dateCount++;\n }\n }\n const threshold = values.length * 0.8;\n // Temporal detection (date fields)\n if (dateCount >= threshold) {\n return 'temporal';\n }\n // Measure detection (numeric with sufficient cardinality OR native JS numbers)\n if (numericCount >= threshold) {\n // If every numeric value is a native JS number, the consumer has already\n // typed the data — trust it as a measure regardless of cardinality.\n const allJSNumbers = jsNumberCount >= numericCount;\n if (allJSNumbers) {\n return 'measure';\n }\n const uniqueCount = new Set(values.map(String)).size;\n // If high cardinality relative to count, it's a measure\n // If low cardinality (like \"1, 2, 3\" categories), treat as dimension\n if (uniqueCount > Math.min(values.length * 0.3, 20)) {\n return 'measure';\n }\n }\n return 'dimension';\n}\n/**\n * Analyze all fields in a dataset for chart building.\n *\n * Pass `overrides` to explicitly set field roles, bypassing auto-detection\n * for specific columns.\n */\nexport function analyzeFieldsForChart(data, overrides) {\n if (data.length === 0)\n return [];\n const fields = Object.keys(data[0]);\n const result = [];\n for (const field of fields) {\n const values = data.map(row => row[field]).filter(v => v !== null && v !== undefined);\n const role = detectFieldRole(data, field, overrides);\n const uniqueSet = new Set(values.map(String));\n let dataType = 'string';\n let min;\n let max;\n if (role === 'measure') {\n dataType = 'number';\n const nums = values.map(v => Number(v)).filter(n => !Number.isNaN(n));\n if (nums.length > 0) {\n min = Math.min(...nums);\n max = Math.max(...nums);\n }\n }\n else if (role === 'temporal') {\n dataType = 'date';\n }\n else {\n // Check for boolean\n const boolCount = values.filter(v => typeof v === 'boolean' || v === 'true' || v === 'false').length;\n if (boolCount >= values.length * 0.8) {\n dataType = 'boolean';\n }\n }\n result.push({\n field,\n label: formatFieldLabel(field),\n role,\n dataType,\n uniqueCount: uniqueSet.size,\n sampleValues: Array.from(uniqueSet).slice(0, 5),\n min,\n max,\n });\n }\n return result;\n}\n/**\n * Format field name as label\n */\nexport function formatFieldLabel(field) {\n return field\n .replace(/([A-Z])/g, ' $1')\n .replace(/[_-]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n .split(' ')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(' ');\n}\n/**\n * Get chart type info by type\n */\nexport function getChartTypeInfo(type) {\n return CHART_TYPES.find(ct => ct.type === type);\n}\n/**\n * Check if a chart configuration is valid/complete\n */\nexport function isChartConfigValid(config) {\n const typeInfo = getChartTypeInfo(config.type);\n if (!typeInfo)\n return false;\n // Check required fields based on chart type\n switch (config.type) {\n case 'bar':\n case 'stackedBar':\n case 'line':\n case 'area':\n case 'pie':\n case 'donut':\n case 'radar':\n return !!config.xAxis && !!config.yAxis;\n case 'scatter':\n // Scatter needs two numeric fields (X and Y)\n return !!config.xAxis && !!config.yAxis;\n case 'bubble':\n // Bubble needs two numeric fields (X and Y), size is optional\n return !!config.xAxis && !!config.yAxis;\n case 'heatmap':\n // Heatmap needs two categories (X and Y) plus a measure for color intensity\n return !!config.xAxis && !!config.yAxis && !!config.colorField;\n default:\n return false;\n }\n}\n/**\n * Get guidance message for current chart state\n */\nexport function getChartGuidance(config) {\n const typeInfo = getChartTypeInfo(config.type);\n if (!typeInfo)\n return 'Select a chart type to begin';\n if (!config.xAxis && !config.yAxis) {\n return typeInfo.guidance;\n }\n switch (config.type) {\n case 'bar':\n case 'line':\n case 'area':\n if (!config.xAxis)\n return 'Drag a category field to the X-axis';\n if (!config.yAxis)\n return 'Drag a number field to the Y-axis';\n if (!config.seriesField)\n return 'Optionally add a field to Color for grouped series';\n return 'Chart is ready! Adjust options as needed.';\n case 'stackedBar':\n if (!config.xAxis)\n return 'Drag a category field to the X-axis';\n if (!config.yAxis)\n return 'Drag a number field to the Y-axis';\n if (!config.seriesField)\n return 'Add a field to Series to define stacked segments';\n return 'Chart is ready! Each series is stacked within the bar.';\n case 'pie':\n case 'donut':\n if (!config.xAxis)\n return 'Drag a category field (slices)';\n if (!config.yAxis)\n return 'Drag a number field (values)';\n return 'Chart is ready!';\n case 'radar':\n if (!config.xAxis)\n return 'Drag a category field for axes';\n if (!config.yAxis)\n return 'Drag a number field for values';\n return 'Chart is ready!';\n case 'scatter':\n if (!config.xAxis)\n return 'Drag a number field to X-axis';\n if (!config.yAxis)\n return 'Drag a number field to Y-axis';\n if (!config.seriesField)\n return 'Optionally add a category to color points by group';\n return 'Tip: Filter data first for clearer visualizations';\n case 'bubble':\n if (!config.xAxis)\n return 'Drag a number field to X-axis';\n if (!config.yAxis)\n return 'Drag a number field to Y-axis';\n if (!config.sizeField)\n return 'Drag a number field to Size for bubble size';\n return 'Tip: Filter to fewer records for readable bubbles';\n case 'heatmap':\n if (!config.xAxis)\n return 'Drag a category field to X-axis';\n if (!config.yAxis)\n return 'Drag a category field to Y-axis';\n if (!config.colorField)\n return 'Drag a number field to Value for color intensity';\n return 'Chart is ready!';\n default:\n return typeInfo.guidance;\n }\n}\n/**\n * Apply aggregation to values\n */\nexport function aggregateValues(values, aggregation) {\n if (values.length === 0)\n return 0;\n switch (aggregation) {\n case 'sum':\n return values.reduce((a, b) => a + b, 0);\n case 'count':\n return values.length;\n case 'avg':\n return values.reduce((a, b) => a + b, 0) / values.length;\n case 'min':\n return Math.min(...values);\n case 'max':\n return Math.max(...values);\n case 'countDistinct':\n return new Set(values).size;\n default:\n return values.reduce((a, b) => a + b, 0);\n }\n}\n/**\n * Process raw data into chart-ready format\n */\nexport function processChartData(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { categories: [], series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const yAggregation = config.yAxis.aggregation || 'sum';\n const seriesField = config.seriesField?.field;\n // Group data by x-axis values\n const grouped = new Map();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = Number(row[yField]);\n const seriesValue = seriesField ? String(row[seriesField] ?? '(blank)') : '_default';\n if (Number.isNaN(yValue))\n continue;\n if (!grouped.has(xValue)) {\n grouped.set(xValue, new Map());\n }\n const xGroup = grouped.get(xValue);\n if (!xGroup.has(seriesValue)) {\n xGroup.set(seriesValue, []);\n }\n xGroup.get(seriesValue).push(yValue);\n }\n // Get sorted categories\n const categories = Array.from(grouped.keys()).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Get all series names\n const seriesNames = new Set();\n for (const xGroup of grouped.values()) {\n for (const seriesName of xGroup.keys()) {\n seriesNames.add(seriesName);\n }\n }\n // Build series data\n const series = [];\n for (const seriesName of seriesNames) {\n const seriesData = [];\n for (const category of categories) {\n const xGroup = grouped.get(category);\n const values = xGroup?.get(seriesName) || [];\n seriesData.push(aggregateValues(values, yAggregation));\n }\n series.push({\n name: seriesName === '_default'\n ? formatFieldLabel(yField)\n : seriesName,\n data: seriesData,\n });\n }\n return { categories, series };\n}\n/**\n * Process data for pie/donut charts\n */\nexport function processChartDataForPie(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { categories: [], series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const yAggregation = config.yAxis.aggregation || 'sum';\n // Group by category\n const grouped = new Map();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = Number(row[yField]);\n if (Number.isNaN(yValue))\n continue;\n if (!grouped.has(xValue)) {\n grouped.set(xValue, []);\n }\n grouped.get(xValue).push(yValue);\n }\n // Sort by aggregated value descending\n const entries = Array.from(grouped.entries())\n .map(([category, values]) => ({\n category,\n value: aggregateValues(values, yAggregation),\n }))\n .sort((a, b) => b.value - a.value);\n return {\n categories: entries.map(e => e.category),\n series: [{\n name: formatFieldLabel(yField),\n data: entries.map(e => e.value),\n }],\n };\n}\n/**\n * Process data for scatter/bubble charts\n * Returns grouped series when seriesField is provided for color-coding\n */\nexport function processChartDataForScatter(data, config) {\n if (!config.xAxis || !config.yAxis || data.length === 0) {\n return { series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const sizeField = config.sizeField?.field;\n const seriesField = config.seriesField?.field;\n // Group by series field if provided\n const grouped = new Map();\n for (const row of data) {\n const x = Number(row[xField]);\n const y = Number(row[yField]);\n if (Number.isNaN(x) || Number.isNaN(y))\n continue;\n const point = { x, y };\n if (sizeField) {\n const z = Number(row[sizeField]);\n if (!Number.isNaN(z)) {\n point.z = z;\n }\n }\n // Group by series field or use default\n const seriesName = seriesField\n ? String(row[seriesField] ?? '(blank)')\n : '_default';\n if (!grouped.has(seriesName)) {\n grouped.set(seriesName, []);\n }\n grouped.get(seriesName).push(point);\n }\n // Convert to series array\n const series = Array.from(grouped.entries()).map(([name, points]) => ({\n name: name === '_default' ? (config.yAxis?.label || 'Data') : name,\n data: points,\n }));\n return { series };\n}\n/**\n * Process data for heatmap charts\n * ApexCharts heatmaps need: series[] where each series is a Y category\n * containing data[] of {x: X category, y: value}\n */\nexport function processChartDataForHeatmap(data, config) {\n if (!config.xAxis || !config.yAxis || !config.colorField || data.length === 0) {\n return { series: [] };\n }\n const xField = config.xAxis.field;\n const yField = config.yAxis.field;\n const colorField = config.colorField.field;\n const colorAggregation = config.colorField.aggregation || 'sum';\n // Group data by Y category, then by X category\n // Structure: Map<yValue, Map<xValue, number[]>>\n const grouped = new Map();\n const allXCategories = new Set();\n for (const row of data) {\n const xValue = String(row[xField] ?? '(blank)');\n const yValue = String(row[yField] ?? '(blank)');\n const colorValue = Number(row[colorField]);\n if (Number.isNaN(colorValue))\n continue;\n allXCategories.add(xValue);\n if (!grouped.has(yValue)) {\n grouped.set(yValue, new Map());\n }\n const yGroup = grouped.get(yValue);\n if (!yGroup.has(xValue)) {\n yGroup.set(xValue, []);\n }\n yGroup.get(xValue).push(colorValue);\n }\n // Sort X categories\n const sortedXCategories = Array.from(allXCategories).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Sort Y categories (series names)\n const sortedYCategories = Array.from(grouped.keys()).sort((a, b) => {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n // Build series - each Y category becomes a series\n const series = sortedYCategories.map((yCategory) => {\n const yGroup = grouped.get(yCategory);\n const seriesData = sortedXCategories.map((xCategory) => {\n const values = yGroup.get(xCategory) || [];\n const aggregatedValue = values.length > 0 ? aggregateValues(values, colorAggregation) : 0;\n return { x: xCategory, y: aggregatedValue };\n });\n return {\n name: yCategory,\n data: seriesData,\n };\n });\n return { series };\n}\n/**\n * Create a default chart config\n */\nexport function createDefaultChartConfig() {\n return {\n type: 'bar',\n options: {\n showDataLabels: false,\n showLegend: true,\n legendPosition: 'top',\n animated: true,\n colors: CHART_COLORS,\n showGrid: true,\n enableZoom: false,\n stacked: false,\n },\n };\n}\n/**\n * Storage key for chart config\n */\nexport function generateChartStorageKey(prefix = 'tinypivot') {\n return `${prefix}_chart_config`;\n}\n/**\n * Save chart config to localStorage\n */\nexport function saveChartConfig(config, key) {\n try {\n localStorage.setItem(key || generateChartStorageKey(), JSON.stringify(config));\n }\n catch {\n // localStorage might be unavailable\n }\n}\n/**\n * Load chart config from localStorage\n */\nexport function loadChartConfig(key) {\n try {\n const stored = localStorage.getItem(key || generateChartStorageKey());\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // localStorage might be unavailable or invalid JSON\n }\n return null;\n}\n//# sourceMappingURL=index.js.map","/**\n * Escape CSV value\n */\nfunction escapeCSV(value, delimiter = ',') {\n if (value === null || value === undefined)\n return '';\n const str = String(value);\n if (str.includes(delimiter) || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n/**\n * CSV Export functionality\n */\nexport function exportToCSV(data, columns, options = {}) {\n const { filename = 'export.csv', includeHeaders = true, delimiter = ',' } = options;\n const rows = [];\n if (includeHeaders) {\n rows.push(columns.map(col => escapeCSV(col, delimiter)).join(delimiter));\n }\n for (const row of data) {\n const values = columns.map(col => escapeCSV(row[col], delimiter));\n rows.push(values.join(delimiter));\n }\n const csvContent = rows.join('\\n');\n downloadFile(csvContent, filename, 'text/csv;charset=utf-8;');\n}\n/**\n * Export pivot table to CSV\n */\nexport function exportPivotToCSV(pivotData, rowFields, _columnFields, valueFields, options = {}) {\n const { filename = 'pivot-export.csv', delimiter = ',' } = options;\n const rows = [];\n const { headers, rowHeaders, data, rowTotals, columnTotals, grandTotal, showRowTotals, showColumnTotals } = pivotData;\n // Calculate number of row header columns\n const rowHeaderColCount = rowFields.length || 1;\n // Build column headers\n if (headers.length > 0) {\n // Multi-level column headers\n for (let level = 0; level < headers.length; level++) {\n const headerRow = [];\n // Empty cells for row field columns\n for (let i = 0; i < rowHeaderColCount; i++) {\n headerRow.push(level === headers.length - 1 ? escapeCSV(rowFields[i] || '', delimiter) : '');\n }\n // Column header values\n for (const val of headers[level]) {\n headerRow.push(escapeCSV(val, delimiter));\n }\n // Row totals header\n if (showRowTotals && rowTotals && rowTotals.length > 0) {\n if (level === headers.length - 1) {\n for (const vf of valueFields) {\n headerRow.push(escapeCSV(`Total (${vf.aggregation})`, delimiter));\n }\n }\n else {\n for (let i = 0; i < valueFields.length; i++) {\n headerRow.push('');\n }\n }\n }\n rows.push(headerRow.join(delimiter));\n }\n }\n else {\n // Simple header with value fields only\n const headerRow = [];\n for (let i = 0; i < rowHeaderColCount; i++) {\n headerRow.push(escapeCSV(rowFields[i] || '', delimiter));\n }\n for (const vf of valueFields) {\n headerRow.push(escapeCSV(`${vf.field} (${vf.aggregation})`, delimiter));\n }\n if (showRowTotals && rowTotals && rowTotals.length > 0) {\n headerRow.push(escapeCSV('Total', delimiter));\n }\n rows.push(headerRow.join(delimiter));\n }\n // Build data rows\n for (let rowIdx = 0; rowIdx < rowHeaders.length; rowIdx++) {\n const csvRow = [];\n // Row headers\n const rowHeader = rowHeaders[rowIdx] || [];\n for (let i = 0; i < rowHeaderColCount; i++) {\n csvRow.push(escapeCSV(rowHeader[i] || '', delimiter));\n }\n // Data cells\n const rowData = data[rowIdx] || [];\n for (const cell of rowData) {\n csvRow.push(escapeCSV(cell?.formattedValue || '', delimiter));\n }\n // Row total\n if (showRowTotals && rowTotals && rowTotals[rowIdx]) {\n csvRow.push(escapeCSV(rowTotals[rowIdx].formattedValue || '', delimiter));\n }\n rows.push(csvRow.join(delimiter));\n }\n // Column totals row\n if (showColumnTotals && columnTotals && columnTotals.length > 0) {\n const totalsRow = [];\n // Label for totals row\n totalsRow.push(escapeCSV('Total', delimiter));\n for (let i = 1; i < rowHeaderColCount; i++) {\n totalsRow.push('');\n }\n // Column total values\n for (const cell of columnTotals) {\n totalsRow.push(escapeCSV(cell?.formattedValue || '', delimiter));\n }\n // Grand total\n if (showRowTotals && grandTotal) {\n totalsRow.push(escapeCSV(grandTotal.formattedValue || '', delimiter));\n }\n rows.push(totalsRow.join(delimiter));\n }\n const csvContent = rows.join('\\n');\n downloadFile(csvContent, filename, 'text/csv;charset=utf-8;');\n}\n/**\n * Download file helper\n */\nfunction downloadFile(content, filename, mimeType) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.style.display = 'none';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n}\n/**\n * Copy text to clipboard\n */\nexport function copyToClipboard(text, onSuccess, onError) {\n navigator.clipboard.writeText(text).then(onSuccess).catch(onError);\n}\n/**\n * Format selected cells for clipboard (tab-separated)\n */\nexport function formatSelectionForClipboard(rows, columns, selectionBounds) {\n const { minRow, maxRow, minCol, maxCol } = selectionBounds;\n const lines = [];\n for (let r = minRow; r <= maxRow; r++) {\n const row = rows[r];\n if (!row)\n continue;\n const values = [];\n for (let c = minCol; c <= maxCol; c++) {\n const colId = columns[c];\n if (!colId)\n continue;\n const value = row[colId];\n values.push(value === null || value === undefined ? '' : String(value));\n }\n lines.push(values.join('\\t'));\n }\n return lines.join('\\n');\n}\n//# sourceMappingURL=index.js.map","const FREE_LICENSE = {\n type: 'free',\n isValid: true,\n features: {\n pivot: true, // Free tier includes pivot with sum aggregation\n advancedAggregations: false, // Pro: all aggregations beyond sum\n percentageMode: false,\n sessionPersistence: false,\n noWatermark: false,\n charts: false, // Chart builder is Pro only\n aiAnalyst: false, // AI Data Analyst is Pro only\n },\n};\nconst INVALID_LICENSE = {\n type: 'free',\n isValid: false,\n features: {\n pivot: true, // Free tier includes pivot with sum aggregation\n advancedAggregations: false,\n percentageMode: false,\n sessionPersistence: false,\n noWatermark: false,\n charts: false,\n aiAnalyst: false,\n },\n};\nconst DEMO_LICENSE = {\n type: 'free',\n isValid: true,\n features: {\n pivot: true,\n advancedAggregations: true,\n percentageMode: true,\n sessionPersistence: true,\n noWatermark: false, // Still show watermark in demo\n charts: true, // Demo can use charts\n aiAnalyst: true, // Demo can use AI Analyst\n },\n};\n// Public key for license verification (ECDSA P-256)\n// This is safe to embed - it can only VERIFY signatures, not create them\nconst PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE436rfGofder4lfo4UHsRF2M88Gs0\nzLsikg2H9GMkL8hLGuOtnGMpVfLRlc7cD8FdkPBBRgiQ8UFnG8hm+nMIug==\n-----END PUBLIC KEY-----`;\n/**\n * Convert base64 (or URL-safe base64) to Uint8Array\n */\nfunction base64ToUint8Array(base64) {\n // Convert URL-safe base64 to standard base64\n let standardBase64 = base64.replace(/-/g, '+').replace(/_/g, '/');\n // Add padding if needed\n while (standardBase64.length % 4) {\n standardBase64 += '=';\n }\n const binaryString = atob(standardBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n/**\n * Convert DER-encoded ECDSA signature to raw format (r || s)\n * Web Crypto API expects raw format, but Node.js produces DER format\n */\nfunction derToRaw(der) {\n // DER format: 0x30 [length] 0x02 [r-length] [r] 0x02 [s-length] [s]\n if (der[0] !== 0x30) {\n throw new Error('Invalid DER signature');\n }\n let offset = 2; // Skip 0x30 and length byte\n // Read r\n if (der[offset] !== 0x02)\n throw new Error('Invalid DER signature');\n offset++;\n const rLen = der[offset];\n offset++;\n let r = der.slice(offset, offset + rLen);\n offset += rLen;\n // Read s\n if (der[offset] !== 0x02)\n throw new Error('Invalid DER signature');\n offset++;\n const sLen = der[offset];\n offset++;\n let s = der.slice(offset, offset + sLen);\n // For P-256, r and s should each be 32 bytes\n // Remove leading zero padding if present (used for positive sign in DER)\n if (r.length === 33 && r[0] === 0)\n r = r.slice(1);\n if (s.length === 33 && s[0] === 0)\n s = s.slice(1);\n // Pad to 32 bytes if shorter\n const padR = new Uint8Array(32);\n const padS = new Uint8Array(32);\n padR.set(r, 32 - r.length);\n padS.set(s, 32 - s.length);\n // Concatenate r || s\n const raw = new Uint8Array(64);\n raw.set(padR, 0);\n raw.set(padS, 32);\n return raw;\n}\n/**\n * ECDSA P-256 verification via @noble/curves (pure JS fallback)\n * Used when SubtleCrypto is unavailable (e.g. browser on plain HTTP)\n */\nasync function verifySignatureNoble(rawSig, msgBytes, spkiBytes) {\n const { p256 } = await import('@noble/curves/p256');\n // SPKI for P-256 has a fixed 26-byte header; raw key starts at offset 26\n const rawPublicKey = spkiBytes.slice(26);\n // prehash: true makes noble SHA-256 hash the message before verifying,\n // matching Web Crypto's { name: 'ECDSA', hash: 'SHA-256' } behavior\n return p256.verify(rawSig, msgBytes, rawPublicKey, { prehash: true });\n}\n/**\n * SHA-256 hashing via @noble/hashes (pure JS fallback)\n * Used when SubtleCrypto is unavailable (e.g. browser on plain HTTP)\n */\nasync function hashSecretNoble(secret) {\n const { sha256 } = await import('@noble/hashes/sha256');\n const data = new TextEncoder().encode(secret);\n const hash = sha256(data);\n return Array.from(hash).map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();\n}\n/**\n * Cached SubtleCrypto instance (undefined = not yet checked)\n */\nlet subtleCryptoCache;\n/**\n * Get a SubtleCrypto instance, falling back to Node.js webcrypto for SSR\n */\nasync function getSubtleCrypto() {\n if (subtleCryptoCache !== undefined)\n return subtleCryptoCache;\n if (globalThis.crypto?.subtle) {\n subtleCryptoCache = globalThis.crypto.subtle;\n return subtleCryptoCache;\n }\n try {\n // Node.js / SSR fallback\n const nodeCrypto = await import('node:crypto');\n const subtle = nodeCrypto.webcrypto?.subtle;\n if (subtle) {\n subtleCryptoCache = subtle;\n return subtleCryptoCache;\n }\n }\n catch { }\n subtleCryptoCache = null;\n return null;\n}\n/**\n * @internal\n */\nexport function _resetCryptoState(forcedValue) {\n // undefined = re-detect on next call, null = force \"no crypto available\"\n subtleCryptoCache = forcedValue;\n insecureContextWarned = false;\n}\nlet insecureContextWarned = false;\n/**\n * Log a one-time info message when crypto.subtle is unavailable (plain HTTP)\n * Not a blocker since @noble/curves provides a pure JS fallback.\n */\nfunction warnInsecureContext() {\n if (insecureContextWarned)\n return;\n insecureContextWarned = true;\n console.info('[TinyPivot] crypto.subtle is not available — using pure JS crypto fallback.\\n'\n + 'This typically happens when serving over plain HTTP. For best performance, consider:\\n'\n + ' 1. Serve your app over HTTPS (recommended for production)\\n'\n + ' 2. Access via localhost (e.g. http://localhost:3000)\\n'\n + ' 3. Use a self-signed certificate for internal IPs');\n}\n/**\n * Import the public key for verification\n */\nasync function importPublicKey() {\n try {\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n return null;\n }\n // Convert PEM to binary\n const pemContents = PUBLIC_KEY_PEM\n .replace('-----BEGIN PUBLIC KEY-----', '')\n .replace('-----END PUBLIC KEY-----', '')\n .replace(/\\s/g, '');\n const binaryKey = base64ToUint8Array(pemContents);\n return await subtle.importKey('spki', new Uint8Array(binaryKey).buffer, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);\n }\n catch {\n return null;\n }\n}\n/**\n * Get SPKI bytes from the embedded PEM public key\n */\nfunction getSpkiBytes() {\n const pemContents = PUBLIC_KEY_PEM\n .replace('-----BEGIN PUBLIC KEY-----', '')\n .replace('-----END PUBLIC KEY-----', '')\n .replace(/\\s/g, '');\n return base64ToUint8Array(pemContents);\n}\n/**\n * ECDSA P-256 signature verification\n * Verifies that the license was signed with our private key\n * Falls back to @noble/curves when SubtleCrypto is unavailable\n */\nasync function verifySignature(typeCode, signature, expiry) {\n const payload = `TP-${typeCode}-${expiry}`;\n const encoder = new TextEncoder();\n const msgData = encoder.encode(payload);\n const derSig = base64ToUint8Array(signature);\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n // Fall back to @noble/curves pure JS implementation\n warnInsecureContext();\n try {\n const rawSig = derToRaw(derSig);\n const spkiBytes = getSpkiBytes();\n return await verifySignatureNoble(rawSig, msgData, spkiBytes);\n }\n catch {\n return false;\n }\n }\n try {\n const rawSig = derToRaw(derSig);\n const publicKey = await importPublicKey();\n if (!publicKey)\n return false;\n return await subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, publicKey, new Uint8Array(rawSig).buffer, msgData);\n }\n catch {\n return false;\n }\n}\n/**\n * Validate a license key and extract info\n *\n * Note: Licenses are PERPETUAL - the expiry date indicates update eligibility,\n * not when features stop working. All Pro features remain active forever.\n */\nexport async function validateLicenseKey(key) {\n // Free tier - no key needed\n if (!key || key === '') {\n return FREE_LICENSE;\n }\n // License key format: TP-{TYPE}-{SIGNATURE}-{EXPIRY}\n // Example: TP-PRO1-base64signature-20251231\n // Note: signature uses URL-safe base64 which can contain dashes\n // So we parse from known positions: prefix (TP), type (4 chars), expiry (8 chars at end)\n if (!key.startsWith('TP-')) {\n return INVALID_LICENSE;\n }\n // Extract expiry (last 8 characters after final dash)\n const lastDashIdx = key.lastIndexOf('-');\n if (lastDashIdx === -1 || key.length - lastDashIdx !== 9) {\n return INVALID_LICENSE;\n }\n const expiryStr = key.slice(lastDashIdx + 1);\n // Extract type code (between first and second dash)\n const withoutPrefix = key.slice(3); // Remove \"TP-\"\n const secondDashIdx = withoutPrefix.indexOf('-');\n if (secondDashIdx === -1) {\n return INVALID_LICENSE;\n }\n const typeCode = withoutPrefix.slice(0, secondDashIdx);\n // Extract signature (everything between type and expiry)\n const signature = withoutPrefix.slice(secondDashIdx + 1, withoutPrefix.lastIndexOf('-'));\n // Verify cryptographic signature\n const isValidSignature = await verifySignature(typeCode, signature, expiryStr);\n if (!isValidSignature) {\n return INVALID_LICENSE;\n }\n // Parse expiry date (for update eligibility tracking, NOT feature expiration)\n const year = Number.parseInt(expiryStr.slice(0, 4));\n const month = Number.parseInt(expiryStr.slice(4, 6)) - 1;\n const day = Number.parseInt(expiryStr.slice(6, 8));\n const expiresAt = new Date(year, month, day);\n // Determine license type\n let type = 'free';\n if (typeCode === 'PRO1')\n type = 'pro-single';\n else if (typeCode === 'PROU')\n type = 'pro-unlimited';\n else if (typeCode === 'PROT')\n type = 'pro-team';\n // PERPETUAL LICENSE: Features never expire, only update eligibility does\n // The expiresAt date is retained for informational purposes only\n return {\n type,\n isValid: true,\n expiresAt,\n features: {\n pivot: type !== 'free',\n advancedAggregations: type !== 'free',\n percentageMode: type !== 'free',\n sessionPersistence: type !== 'free',\n noWatermark: type !== 'free',\n charts: type !== 'free',\n aiAnalyst: type !== 'free',\n },\n };\n}\n/**\n * @deprecated No longer needed - license verification now uses asymmetric cryptography.\n * Kept for backwards compatibility but does nothing.\n */\nexport function configureLicenseSecret(_secret) {\n // No-op: Asymmetric verification doesn't need a shared secret\n console.warn('[TinyPivot] configureLicenseSecret() is deprecated and no longer needed.');\n}\n// Hardcoded SHA-256 hash of the demo secret\nconst DEMO_SECRET_HASH = 'A48AA0618518D3E62F31FCFCA2DD2B86E7FE0863E2F90756FB0A960AE7A51583';\n/**\n * Hash a string using SHA-256 (async for Web Crypto API)\n */\nasync function hashSecret(secret) {\n try {\n const subtle = await getSubtleCrypto();\n if (!subtle) {\n // Fall back to @noble/hashes pure JS implementation\n warnInsecureContext();\n return await hashSecretNoble(secret);\n }\n const encoder = new TextEncoder();\n const data = encoder.encode(secret);\n const hashBuffer = await subtle.digest('SHA-256', data);\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();\n }\n catch {\n return '';\n }\n}\n/**\n * Validate demo secret and return demo license info if valid\n * Returns null if secret is invalid\n */\nexport async function getDemoLicenseInfo(secret) {\n if (!secret) {\n return null;\n }\n const hash = await hashSecret(secret);\n if (hash !== DEMO_SECRET_HASH) {\n return null;\n }\n return DEMO_LICENSE;\n}\n/**\n * Get free license info\n */\nexport function getFreeLicenseInfo() {\n return FREE_LICENSE;\n}\n/**\n * Check if license allows pivot feature\n */\nexport function canUsePivot(info) {\n return info.features.pivot;\n}\n/**\n * Check if license allows chart builder feature\n */\nexport function canUseCharts(info) {\n return info.features.charts;\n}\n/**\n * Check if license allows AI Data Analyst feature\n */\nexport function canUseAIAnalyst(info) {\n return info.features.aiAnalyst;\n}\n/**\n * Check if license is pro (any tier)\n */\nexport function isPro(info) {\n return info.isValid && info.type !== 'free';\n}\n/**\n * Check if watermark should be shown\n */\nexport function shouldShowWatermark(info, isDemo) {\n return isDemo || !info.features.noWatermark;\n}\n/**\n * Log pro requirement warning\n */\nexport function logProRequired(feature) {\n console.warn(`[TinyPivot] \"${feature}\" requires a Pro license. `\n + `Visit https://tiny-pivot.com/#pricing to upgrade.`);\n}\n//# sourceMappingURL=index.js.map","/**\n * Detect column data type from values\n */\nexport function detectColumnType(values) {\n const nonNullValues = values.filter(v => v !== null && v !== undefined && v !== '');\n if (nonNullValues.length === 0)\n return 'string';\n const sample = nonNullValues.slice(0, 100);\n let numberCount = 0;\n let dateCount = 0;\n let booleanCount = 0;\n for (const val of sample) {\n if (typeof val === 'boolean') {\n booleanCount++;\n }\n else if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '')) {\n numberCount++;\n }\n else if (val instanceof Date || !Number.isNaN(Date.parse(String(val)))) {\n dateCount++;\n }\n }\n const threshold = sample.length * 0.8;\n if (booleanCount >= threshold)\n return 'boolean';\n if (numberCount >= threshold)\n return 'number';\n if (dateCount >= threshold)\n return 'date';\n return 'string';\n}\n/**\n * Detect field type from sample data (for pivot)\n */\nexport function detectFieldType(data, field) {\n const values = data.map(row => row[field]).filter(v => v !== null && v !== undefined && v !== '');\n const sample = values.slice(0, 100);\n let numberCount = 0;\n const uniqueSet = new Set();\n for (const val of sample) {\n uniqueSet.add(String(val));\n if (typeof val === 'number' || (!Number.isNaN(Number(val)) && val !== '')) {\n numberCount++;\n }\n }\n const isNumeric = numberCount >= sample.length * 0.8;\n return {\n field,\n type: isNumeric ? 'number' : 'string',\n uniqueCount: uniqueSet.size,\n isNumeric,\n };\n}\n/**\n * Get unique values for a column (for Excel-style filter dropdown)\n * For numeric columns, also computes min and max values\n */\nexport function getColumnUniqueValues(data, columnKey, maxValues = 500) {\n const values = [];\n let nullCount = 0;\n let numericMin;\n let numericMax;\n let dateMin;\n let dateMax;\n for (const row of data) {\n const value = row[columnKey];\n if (value === null || value === undefined || value === '') {\n nullCount++;\n }\n else {\n values.push(value);\n // Track numeric min/max\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (!Number.isNaN(num)) {\n if (numericMin === undefined || num < numericMin)\n numericMin = num;\n if (numericMax === undefined || num > numericMax)\n numericMax = num;\n }\n // Track date min/max\n if (value instanceof Date || (typeof value === 'string' && !Number.isNaN(Date.parse(String(value))))) {\n const dateObj = value instanceof Date ? value : new Date(String(value));\n if (!Number.isNaN(dateObj.getTime())) {\n const isoStr = dateObj.toISOString().split('T')[0];\n if (dateMin === undefined || isoStr < dateMin)\n dateMin = isoStr;\n if (dateMax === undefined || isoStr > dateMax)\n dateMax = isoStr;\n }\n }\n }\n }\n // Get unique values\n const uniqueSet = new Set();\n for (const val of values) {\n uniqueSet.add(String(val));\n if (uniqueSet.size >= maxValues)\n break;\n }\n const uniqueValues = Array.from(uniqueSet).sort((a, b) => {\n // Natural sort for numbers\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b);\n });\n const columnType = detectColumnType(values);\n return {\n uniqueValues,\n totalCount: data.length,\n nullCount,\n type: columnType,\n // Only include min/max for numeric columns\n ...(columnType === 'number' && numericMin !== undefined && numericMax !== undefined\n ? { numericMin, numericMax }\n : {}),\n ...(columnType === 'date' && dateMin !== undefined && dateMax !== undefined\n ? { dateMin, dateMax }\n : {}),\n };\n}\n/**\n * Format cell value for display\n */\nexport function formatCellValue(value, type, numberFormat = 'us', dateFormat = 'iso') {\n if (value === null || value === undefined)\n return '';\n if (value === '')\n return '';\n switch (type) {\n case 'number': {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (Number.isNaN(num))\n return String(value);\n return formatNumber(num, numberFormat);\n }\n case 'date':\n return formatDate(value, dateFormat);\n case 'boolean':\n return value ? 'Yes' : 'No';\n default:\n return String(value);\n }\n}\n/**\n * Format number for display with appropriate precision\n */\nexport function formatNumber(value, format = 'us', options) {\n if (value === null)\n return '-';\n const maxDigits = options?.maximumFractionDigits ?? (Math.abs(value) >= 1000 ? 2 : 4);\n switch (format) {\n case 'eu':\n return value.toLocaleString('de-DE', { maximumFractionDigits: maxDigits });\n case 'plain':\n return Number.isInteger(value) ? String(value) : value.toFixed(Math.min(maxDigits, 20));\n case 'us':\n default:\n return value.toLocaleString('en-US', { maximumFractionDigits: maxDigits });\n }\n}\n/**\n * Format date according to the specified format preset\n */\nexport function formatDate(value, format = 'iso') {\n const date = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(date.getTime()))\n return String(value);\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, '0');\n const day = String(date.getUTCDate()).padStart(2, '0');\n switch (format) {\n case 'us':\n return `${month}/${day}/${year}`;\n case 'eu':\n return `${day}/${month}/${year}`;\n case 'iso':\n default:\n return `${year}-${month}-${day}`;\n }\n}\n/**\n * Parse a date string in the given format back to an ISO string (YYYY-MM-DD)\n * Returns null if parsing fails\n */\nexport function parseDateInput(input, format = 'iso') {\n const trimmed = input.trim();\n if (!trimmed)\n return null;\n let year, month, day;\n switch (format) {\n case 'us': {\n const parts = trimmed.split('/');\n if (parts.length !== 3)\n return null;\n month = Number.parseInt(parts[0], 10);\n day = Number.parseInt(parts[1], 10);\n year = Number.parseInt(parts[2], 10);\n break;\n }\n case 'eu': {\n const parts = trimmed.split('/');\n if (parts.length !== 3)\n return null;\n day = Number.parseInt(parts[0], 10);\n month = Number.parseInt(parts[1], 10);\n year = Number.parseInt(parts[2], 10);\n break;\n }\n case 'iso':\n default: {\n const parts = trimmed.split('-');\n if (parts.length !== 3)\n return null;\n year = Number.parseInt(parts[0], 10);\n month = Number.parseInt(parts[1], 10);\n day = Number.parseInt(parts[2], 10);\n break;\n }\n }\n if (Number.isNaN(year) || Number.isNaN(month) || Number.isNaN(day))\n return null;\n if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1)\n return null;\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day)\n return null;\n const m = String(month).padStart(2, '0');\n const d = String(day).padStart(2, '0');\n return `${year}-${m}-${d}`;\n}\n/**\n * Get the date format placeholder string\n */\nexport function getDatePlaceholder(format = 'iso') {\n switch (format) {\n case 'us': return 'MM/DD/YYYY';\n case 'eu': return 'DD/MM/YYYY';\n case 'iso':\n default: return 'YYYY-MM-DD';\n }\n}\n/**\n * Create a composite key from field values (for pivot grouping)\n */\nexport function makeKey(row, fields) {\n return fields.map(f => String(row[f] ?? '(blank)')).join('|||');\n}\n/**\n * Parse composite key back to values\n */\nexport function parseKey(key) {\n return key.split('|||');\n}\n/**\n * Natural sort comparator\n */\nexport function naturalSort(a, b) {\n const numA = Number.parseFloat(a);\n const numB = Number.parseFloat(b);\n if (!Number.isNaN(numA) && !Number.isNaN(numB)) {\n return numA - numB;\n }\n return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });\n}\n/**\n * Debounce function\n */\nexport function debounce(fn, delay) {\n let timeoutId = null;\n return (...args) => {\n if (timeoutId)\n clearTimeout(timeoutId);\n timeoutId = setTimeout(() => fn(...args), delay);\n };\n}\n/**\n * Clamp a number between min and max\n */\nexport function clamp(value, min, max) {\n return Math.max(min, Math.min(max, value));\n}\n//# sourceMappingURL=index.js.map","import { detectFieldType, formatNumber, makeKey, parseKey } from '../utils';\n/**\n * Calculate median of an array\n */\nfunction calculateMedian(values) {\n const sorted = [...values].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 !== 0\n ? sorted[mid]\n : (sorted[mid - 1] + sorted[mid]) / 2;\n}\n/**\n * Calculate standard deviation of an array\n */\nfunction calculateStdDev(values) {\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const squaredDiffs = values.map(v => (v - mean) ** 2);\n const avgSquaredDiff = squaredDiffs.reduce((a, b) => a + b, 0) / values.length;\n return Math.sqrt(avgSquaredDiff);\n}\n/**\n * Aggregate values based on function type\n * @param values - Array of values to aggregate\n * @param fn - Aggregation function to apply\n * @param grandTotal - Optional grand total for percentOfTotal calculation\n * @param customFn - Optional custom aggregation function\n * @param allFieldValues - Optional all field values for cross-field custom calculations\n */\nexport function aggregate(values, fn, grandTotal, customFn, allFieldValues) {\n if (values.length === 0 && fn !== 'custom')\n return null;\n switch (fn) {\n case 'sum':\n return values.reduce((a, b) => a + b, 0);\n case 'count':\n return values.length;\n case 'avg':\n return values.reduce((a, b) => a + b, 0) / values.length;\n case 'min':\n return Math.min(...values);\n case 'max':\n return Math.max(...values);\n case 'countDistinct':\n return new Set(values).size;\n case 'median':\n return calculateMedian(values);\n case 'stdDev':\n return calculateStdDev(values);\n case 'percentOfTotal': {\n const sum = values.reduce((a, b) => a + b, 0);\n if (grandTotal === undefined || grandTotal === 0)\n return null;\n return (sum / grandTotal) * 100;\n }\n case 'custom':\n if (customFn) {\n try {\n return customFn(values, allFieldValues);\n }\n catch {\n return null;\n }\n }\n return null;\n default:\n return values.reduce((a, b) => a + b, 0);\n }\n}\n/**\n * Format aggregated value for display\n */\nexport function formatAggregatedValue(value, fn, numberFormat = 'us') {\n if (value === null)\n return '-';\n if (fn === 'count' || fn === 'countDistinct') {\n return formatNumber(Math.round(value), numberFormat, { maximumFractionDigits: 0 });\n }\n if (fn === 'percentOfTotal') {\n return `${value.toFixed(1)}%`;\n }\n return formatNumber(value, numberFormat);\n}\n/**\n * Get aggregation function display label\n */\nexport function getAggregationLabel(fn, customLabel) {\n if (fn === 'custom' && customLabel)\n return customLabel;\n const labels = {\n sum: 'Sum',\n count: 'Count',\n avg: 'Average',\n min: 'Min',\n max: 'Max',\n countDistinct: 'Count Distinct',\n median: 'Median',\n stdDev: 'Std Dev',\n percentOfTotal: '% of Total',\n custom: 'Custom',\n };\n return labels[fn];\n}\n/**\n * Get aggregation function symbol\n */\nexport function getAggregationSymbol(fn, customSymbol) {\n if (fn === 'custom' && customSymbol)\n return customSymbol;\n const symbols = {\n sum: 'Σ',\n count: '#',\n avg: 'x̄',\n min: '↓',\n max: '↑',\n countDistinct: '◇',\n median: 'M̃',\n stdDev: 'σ',\n percentOfTotal: '%Σ',\n custom: 'ƒ',\n };\n return symbols[fn];\n}\n/**\n * Aggregation options for UI\n */\nexport const AGGREGATION_OPTIONS = [\n { value: 'sum', label: 'Sum', symbol: 'Σ' },\n { value: 'count', label: 'Count', symbol: '#' },\n { value: 'avg', label: 'Avg', symbol: 'x̄' },\n { value: 'min', label: 'Min', symbol: '↓' },\n { value: 'max', label: 'Max', symbol: '↑' },\n { value: 'countDistinct', label: 'Unique', symbol: '◇' },\n { value: 'median', label: 'Median', symbol: 'M̃' },\n { value: 'stdDev', label: 'Std Dev', symbol: 'σ' },\n { value: 'percentOfTotal', label: '% of Total', symbol: '%Σ' },\n];\n// ============================================\n// Calculated Fields & Formula Parsing\n// ============================================\n/**\n * Supported functions in calculated field formulas\n */\nexport const FORMULA_FUNCTIONS = ['SUM', 'AVG', 'MIN', 'MAX', 'COUNT', 'MEDIAN'];\n/**\n * Parse a formula and extract field references\n * e.g., \"SUM(revenue) / SUM(units)\" -> [{fn: 'SUM', field: 'revenue'}, {fn: 'SUM', field: 'units'}]\n */\nexport function parseFormula(formula) {\n const regex = /(SUM|AVG|MIN|MAX|COUNT|MEDIAN)\\s*\\(\\s*([^)]+)\\s*\\)/gi;\n const matches = [];\n let match;\n while ((match = regex.exec(formula)) !== null) {\n matches.push({\n fn: match[1].toUpperCase(),\n field: match[2].trim(),\n });\n }\n return matches;\n}\n/**\n * Evaluate a calculated field formula with aggregated values\n * @param formula - Formula string like \"SUM(revenue) / SUM(units) * 100\"\n * @param aggregatedValues - Map of \"FN(field)\" to aggregated value\n * @returns Calculated value or null if evaluation fails\n */\nexport function evaluateFormula(formula, aggregatedValues) {\n try {\n // Replace function calls with their values\n let expression = formula;\n for (const [key, value] of Object.entries(aggregatedValues)) {\n if (value === null)\n return null;\n // Escape special regex characters in key and replace\n const escaped = key.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n expression = expression.replace(new RegExp(escaped, 'gi'), String(value));\n }\n // Safety check - only allow numbers, operators, parentheses, and whitespace\n if (!/^[\\d\\s.+\\-*/()]+$/.test(expression)) {\n console.warn('Invalid formula expression:', expression);\n return null;\n }\n // Evaluate the expression\n // Using Function constructor for safe math evaluation\n const result = new Function(`return (${expression})`)();\n if (typeof result !== 'number' || !Number.isFinite(result)) {\n return null;\n }\n return result;\n }\n catch (error) {\n console.warn('Formula evaluation error:', error);\n return null;\n }\n}\n/**\n * Format calculated field value based on format type\n */\nexport function formatCalculatedValue(value, formatAs, decimals = 2, numberFormat = 'us') {\n if (value === null)\n return '-';\n switch (formatAs) {\n case 'percent':\n return `${value.toFixed(decimals)}%`;\n case 'currency':\n return `$${formatNumber(value, numberFormat, { maximumFractionDigits: decimals })}`;\n default:\n return formatNumber(value, numberFormat, { maximumFractionDigits: decimals });\n }\n}\n/**\n * Validate a calculated field formula\n * @returns Error message if invalid, null if valid\n */\nexport function validateFormula(formula, availableFields) {\n if (!formula.trim()) {\n return 'Formula cannot be empty';\n }\n const references = parseFormula(formula);\n if (references.length === 0) {\n return 'Formula must contain at least one function like SUM(field)';\n }\n // Case-insensitive field matching\n const lowerFields = availableFields.map(f => f.toLowerCase());\n for (const ref of references) {\n const fieldLower = ref.field.toLowerCase();\n if (!lowerFields.includes(fieldLower)) {\n return `Unknown field: ${ref.field}`;\n }\n }\n // Try to evaluate with dummy values to check syntax\n const dummyValues = {};\n for (const ref of references) {\n dummyValues[`${ref.fn}(${ref.field})`] = 1;\n }\n const result = evaluateFormula(formula, dummyValues);\n if (result === null) {\n return 'Invalid formula syntax';\n }\n return null;\n}\n/**\n * Parse a simple formula to extract field references (no aggregation functions)\n * e.g., \"sales / units\" -> [\"sales\", \"units\"]\n */\nexport function parseSimpleFormula(formula) {\n // Match word characters that could be field names (not operators or numbers)\n const matches = formula.match(/[a-z_]\\w*/gi) || [];\n // Filter out common keywords/operators\n const keywords = ['true', 'false', 'null', 'undefined'];\n return [...new Set(matches.filter(m => !keywords.includes(m.toLowerCase())))];\n}\n/**\n * Validate a simple formula (field math, no aggregation functions)\n */\nexport function validateSimpleFormula(formula, availableFields) {\n if (!formula.trim()) {\n return 'Formula is required';\n }\n const referencedFields = parseSimpleFormula(formula);\n if (referencedFields.length === 0) {\n return 'Formula must reference at least one field';\n }\n // Case-insensitive field matching\n const lowerFields = availableFields.map(f => f.toLowerCase());\n for (const field of referencedFields) {\n if (!lowerFields.includes(field.toLowerCase())) {\n return `Unknown field: ${field}`;\n }\n }\n // Test that the formula is valid JavaScript\n try {\n // Replace field names with dummy values\n let testExpr = formula;\n for (const field of referencedFields) {\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n testExpr = testExpr.replace(new RegExp(`\\\\b${escaped}\\\\b`, 'gi'), '1');\n }\n new Function(`return ${testExpr}`);\n }\n catch {\n return 'Invalid formula syntax';\n }\n return null;\n}\n/**\n * Evaluate a simple formula for a single row of data\n */\nexport function evaluateSimpleFormula(formula, row, fieldNames) {\n try {\n const referencedFields = parseSimpleFormula(formula);\n let expression = formula;\n for (const field of referencedFields) {\n // Find actual field name (case-insensitive)\n const actualField = fieldNames.find(f => f.toLowerCase() === field.toLowerCase()) || field;\n const value = row[actualField];\n if (value === null || value === undefined || value === '') {\n return null; // Can't compute if any referenced field is missing\n }\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value));\n if (Number.isNaN(num)) {\n return null;\n }\n // Replace field name with value\n const escaped = field.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n expression = expression.replace(new RegExp(`\\\\b${escaped}\\\\b`, 'gi'), String(num));\n }\n // Safety check - only allow numbers, operators, parentheses\n if (!/^[\\d\\s+\\-*/().]+$/.test(expression)) {\n return null;\n }\n const result = new Function(`return ${expression}`)();\n return typeof result === 'number' && Number.isFinite(result) ? result : null;\n }\n catch {\n return null;\n }\n}\n/**\n * Create common calculated field presets\n */\nexport const CALCULATED_FIELD_PRESETS = [\n {\n name: 'Profit Margin %',\n formula: 'SUM(profit) / SUM(revenue) * 100',\n formatAs: 'percent',\n description: 'Profit as percentage of revenue',\n },\n {\n name: 'Average Price',\n formula: 'SUM(revenue) / SUM(units)',\n formatAs: 'currency',\n description: 'Revenue per unit sold',\n },\n {\n name: 'Growth Rate',\n formula: '(SUM(current) - SUM(previous)) / SUM(previous) * 100',\n formatAs: 'percent',\n description: 'Percentage change between periods',\n },\n];\n/**\n * Compute available fields from data\n */\nexport function computeAvailableFields(data) {\n if (data.length === 0)\n return [];\n const keys = Object.keys(data[0]);\n return keys.map(field => detectFieldType(data, field));\n}\n/**\n * Get unassigned fields (not in row, column, or value fields)\n */\nexport function getUnassignedFields(availableFields, rowFields, columnFields, valueFields) {\n const assigned = new Set([\n ...rowFields,\n ...columnFields,\n ...valueFields.map(v => v.field),\n ]);\n return availableFields.filter(f => !assigned.has(f.field));\n}\n/**\n * Check if pivot is configured\n */\nexport function isPivotConfigured(config) {\n return (config.rowFields.length > 0 || config.columnFields.length > 0) && config.valueFields.length > 0;\n}\n/**\n * Build pivot result from data and config\n */\nexport function computePivotResult(data, config) {\n const { rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields } = config;\n if (!isPivotConfigured(config))\n return null;\n if (data.length === 0)\n return null;\n // Build a map of calculated field IDs to their definitions\n const calcFieldMap = new Map();\n if (calculatedFields) {\n for (const cf of calculatedFields) {\n calcFieldMap.set(cf.id, cf);\n }\n }\n // Get all field names from data for formula evaluation\n const allDataFieldNames = data.length > 0 ? Object.keys(data[0]) : [];\n // Collect unique row and column keys\n const rowKeySet = new Set();\n const colKeySet = new Set();\n // Group data by row and column keys\n // Each value field (regular or calculated) gets its own array of values\n const dataMap = new Map();\n for (const row of data) {\n const rowKey = rowFields.length > 0 ? makeKey(row, rowFields) : '__all__';\n const colKey = columnFields.length > 0 ? makeKey(row, columnFields) : '__all__';\n rowKeySet.add(rowKey);\n colKeySet.add(colKey);\n if (!dataMap.has(rowKey)) {\n dataMap.set(rowKey, new Map());\n }\n const colMap = dataMap.get(rowKey);\n if (!colMap.has(colKey)) {\n colMap.set(colKey, valueFields.map(() => []));\n }\n const valueArrays = colMap.get(colKey);\n // Collect values for each value field\n for (let i = 0; i < valueFields.length; i++) {\n const vf = valueFields[i];\n let num = null;\n if (vf.field.startsWith('calc:')) {\n // Calculated field - evaluate formula for this row\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n if (calcDef) {\n num = evaluateSimpleFormula(calcDef.formula, row, allDataFieldNames);\n }\n }\n else {\n // Regular field - get value directly\n const val = row[vf.field];\n if (val !== null && val !== undefined && val !== '') {\n num = typeof val === 'number' ? val : Number.parseFloat(String(val));\n if (Number.isNaN(num)) {\n num = (vf.aggregation === 'count' || vf.aggregation === 'countDistinct') ? 1 : null;\n }\n }\n }\n if (num !== null) {\n valueArrays[i].push(num);\n }\n }\n }\n // Sort keys\n const rowKeys = Array.from(rowKeySet).sort();\n const colKeys = Array.from(colKeySet).sort();\n // Pre-calculate grand totals for percentOfTotal calculations\n const grandTotals = valueFields.map((vf, _i) => {\n let total = 0;\n for (const row of data) {\n let num = null;\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n if (calcDef) {\n num = evaluateSimpleFormula(calcDef.formula, row, allDataFieldNames);\n }\n }\n else {\n const val = row[vf.field];\n if (val !== null && val !== undefined && val !== '') {\n num = typeof val === 'number' ? val : Number.parseFloat(String(val));\n if (Number.isNaN(num))\n num = null;\n }\n }\n if (num !== null)\n total += num;\n }\n return total;\n });\n // Helper to get value field display label\n function getValueFieldLabel(vf) {\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n const name = calcDef?.name || vf.field;\n return `${name} (${getAggregationLabel(vf.aggregation)})`;\n }\n return `${vf.label || vf.field} (${getAggregationLabel(vf.aggregation)})`;\n }\n // Build column headers\n // When there are multiple value fields, each column header must be repeated\n // for each value field so the headers align with the data columns\n const headers = [];\n if (columnFields.length > 0) {\n const repeatCount = valueFields.length > 1 ? valueFields.length : 1;\n for (let level = 0; level < columnFields.length; level++) {\n const headerRow = [];\n for (const colKey of colKeys) {\n const parts = parseKey(colKey);\n // Repeat header for each value field\n for (let i = 0; i < repeatCount; i++) {\n headerRow.push(parts[level] || '');\n }\n }\n headers.push(headerRow);\n }\n }\n // If multiple value fields, add value field labels as last header row\n if (valueFields.length > 1 || headers.length === 0) {\n const valueLabels = [];\n for (const _colKey of colKeys) {\n for (const vf of valueFields) {\n valueLabels.push(getValueFieldLabel(vf));\n }\n }\n if (colKeys.length === 1 && colKeys[0] === '__all__') {\n headers.push(valueFields.map(vf => getValueFieldLabel(vf)));\n }\n else {\n headers.push(valueLabels);\n }\n }\n // Build row headers\n const rowHeaders = rowKeys.map((key) => {\n if (key === '__all__')\n return ['Total'];\n return parseKey(key);\n });\n // Build data matrix\n const pivotData = [];\n const rowTotals = [];\n const columnTotalsMap = new Map(); // colKey -> raw values\n for (const rowKey of rowKeys) {\n const rowData = [];\n // Collect all raw values for this row (for row totals)\n const rowAllValues = valueFields.map(() => []);\n for (const colKey of colKeys) {\n const colMap = dataMap.get(rowKey);\n const rawValues = colMap?.get(colKey) || valueFields.map(() => []);\n // Accumulate for row totals\n for (let fi = 0; fi < rawValues.length; fi++) {\n rowAllValues[fi].push(...rawValues[fi]);\n }\n // Accumulate for column totals\n if (!columnTotalsMap.has(colKey)) {\n columnTotalsMap.set(colKey, valueFields.map(() => []));\n }\n const colTotals = columnTotalsMap.get(colKey);\n for (let fi = 0; fi < rawValues.length; fi++) {\n colTotals[fi].push(...rawValues[fi]);\n }\n // Compute cell for each value field\n for (let vfIdx = 0; vfIdx < valueFields.length; vfIdx++) {\n const vf = valueFields[vfIdx];\n const values = rawValues[vfIdx] || [];\n const gtValue = grandTotals[vfIdx];\n const aggValue = aggregate(values, vf.aggregation, gtValue);\n // Format based on whether it's a calculated field\n let formattedValue;\n if (vf.field.startsWith('calc:')) {\n const calcId = vf.field.replace('calc:', '');\n const calcDef = calcFieldMap.get(calcId);\n formattedValue = formatCalculatedValue(aggValue, calcDef?.formatAs || 'number', calcDef?.decimals ?? 2);\n }\n else {\n formattedValue = formatAggregatedValue(aggValue, vf.aggregation);\n }\n rowData.push({\n value: aggValue,\n count: values.length,\n formattedValue,\n });\n }\n }\n pivotData.push(rowData);\n // Compute row total (using first value field for now)\n if (showRowTotals && colKeys.length > 1) {\n if (valueFields.length > 0) {\n const vf = valueFields[0];\n const values = rowAllValues[0] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[0]);\n rowTotals.push({\n value: aggValue,\n count: values.length,\n formattedValue: formatAggregatedValue(aggValue, vf.aggregation),\n });\n }\n else {\n rowTotals.push({ value: null, count: 0, formattedValue: '-' });\n }\n }\n }\n // Calculate column totals\n const columnTotals = [];\n if (showColumnTotals && rowKeys.length > 1) {\n for (const colKey of colKeys) {\n const colRawValues = columnTotalsMap.get(colKey) || valueFields.map(() => []);\n for (let vfIdx = 0; vfIdx < valueFields.length; vfIdx++) {\n const vf = valueFields[vfIdx];\n const values = colRawValues[vfIdx] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[vfIdx]);\n columnTotals.push({\n value: aggValue,\n count: values.length,\n formattedValue: formatAggregatedValue(aggValue, vf.aggregation),\n });\n }\n }\n }\n // Grand total - collect all values across entire dataset\n const grandTotal = { value: null, count: 0, formattedValue: '-' };\n if (showRowTotals && showColumnTotals && valueFields.length > 0) {\n // Collect all raw values from the entire dataset\n const allRawValues = valueFields.map(() => []);\n for (const rowKey of rowKeys) {\n const colMap = dataMap.get(rowKey);\n if (colMap) {\n for (const colKey of colKeys) {\n const vals = colMap.get(colKey);\n if (vals) {\n for (let fi = 0; fi < vals.length; fi++) {\n allRawValues[fi].push(...vals[fi]);\n }\n }\n }\n }\n }\n const vf = valueFields[0];\n const values = allRawValues[0] || [];\n const aggValue = aggregate(values, vf.aggregation, grandTotals[0]);\n grandTotal.value = aggValue;\n grandTotal.count = values.length;\n grandTotal.formattedValue = formatAggregatedValue(aggValue, vf.aggregation);\n }\n return {\n headers,\n rowHeaders,\n data: pivotData,\n rowTotals,\n columnTotals,\n grandTotal,\n };\n}\n// Storage helpers for pivot config persistence\nconst STORAGE_KEY_PREFIX = 'vpg-pivot-';\n/**\n * Generate a storage key based on column names\n */\nexport function generateStorageKey(columns) {\n const sorted = [...columns].sort();\n const hash = sorted.join('|').substring(0, 100);\n return `${STORAGE_KEY_PREFIX}${hash}`;\n}\n/**\n * Save pivot config to sessionStorage\n */\nexport function savePivotConfig(key, config) {\n try {\n sessionStorage.setItem(key, JSON.stringify(config));\n }\n catch {\n // Ignore storage errors\n }\n}\n/**\n * Load pivot config from sessionStorage\n */\nexport function loadPivotConfig(key) {\n try {\n const stored = sessionStorage.getItem(key);\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // Ignore parse errors\n }\n return null;\n}\n/**\n * Check if config fields exist in available fields\n */\nexport function isConfigValidForFields(config, availableFieldNames) {\n const available = new Set(availableFieldNames);\n const allConfiguredFields = [\n ...config.rowFields,\n ...config.columnFields,\n ...config.valueFields.map(v => v.field),\n ];\n // Filter out calculated fields (they start with 'calc:')\n return allConfiguredFields\n .filter(f => !f.startsWith('calc:'))\n .every(f => available.has(f));\n}\n// Calculated Fields Storage\nconst CALC_FIELDS_KEY = 'vpg-calculated-fields';\n/**\n * Save calculated fields to localStorage (persists across sessions)\n */\nexport function saveCalculatedFields(fields) {\n try {\n localStorage.setItem(CALC_FIELDS_KEY, JSON.stringify(fields));\n }\n catch {\n // Ignore storage errors\n }\n}\n/**\n * Load calculated fields from localStorage\n */\nexport function loadCalculatedFields() {\n try {\n const stored = localStorage.getItem(CALC_FIELDS_KEY);\n if (stored) {\n return JSON.parse(stored);\n }\n }\n catch {\n // Ignore parse errors\n }\n return [];\n}\n/**\n * Add a calculated field to storage\n */\nexport function addCalculatedField(field) {\n const fields = loadCalculatedFields();\n const existing = fields.findIndex(f => f.id === field.id);\n if (existing >= 0) {\n fields[existing] = field;\n }\n else {\n fields.push(field);\n }\n saveCalculatedFields(fields);\n return fields;\n}\n/**\n * Remove a calculated field from storage\n */\nexport function removeCalculatedField(id) {\n const fields = loadCalculatedFields().filter(f => f.id !== id);\n saveCalculatedFields(fields);\n return fields;\n}\n//# sourceMappingURL=index.js.map","/**\n * TinyPivot Core - Type Definitions\n * Framework-agnostic types used across Vue and React packages\n */\n/** Type guard to check if filter value is a numeric range */\nexport function isNumericRange(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n if (!('min' in value) && !('max' in value))\n return false;\n const v = value;\n return (v.min === null || typeof v.min === 'number') && (v.max === null || typeof v.max === 'number');\n}\n/** Type guard to check if filter value is a date range */\nexport function isDateRange(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n if (!('min' in value) && !('max' in value))\n return false;\n const v = value;\n return (v.min === null || typeof v.min === 'string') && (v.max === null || typeof v.max === 'string');\n}\n//# sourceMappingURL=index.js.map","/**\n * TinyPivot Vue - AI Analyst Composable\n * Manages AI conversation state and data fetching\n */\nimport type {\n AIAnalystConfig,\n AIConversation,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIDataSource,\n AIErrorEvent,\n AIProxyResponse,\n AIQueryExecutedEvent,\n AITableSchema,\n ListTablesResponse,\n SchemaResponse,\n} from '@smallwebco/tinypivot-core'\nimport {\n addMessageToConversation,\n buildSystemPrompt,\n createAssistantMessage,\n createConversation,\n createUserMessage,\n extractSQLFromResponse,\n findDemoResponse,\n getDefaultDemoResponse,\n getDemoSchema,\n getInitialDemoData,\n getMessagesForAPI,\n setConversationDataSource,\n validateSQLSafety,\n} from '@smallwebco/tinypivot-core'\nimport { computed, onMounted, ref } from 'vue'\n\nexport interface UseAIAnalystOptions {\n config: AIAnalystConfig\n onDataLoaded?: (event: AIDataLoadedEvent) => void\n onConversationUpdate?: (event: AIConversationUpdateEvent) => void\n onQueryExecuted?: (event: AIQueryExecutedEvent) => void\n onError?: (event: AIErrorEvent) => void\n}\n\nexport function useAIAnalyst(options: UseAIAnalystOptions) {\n const { config, onDataLoaded, onConversationUpdate, onQueryExecuted, onError } = options\n\n // LocalStorage key for persistence\n const storageKey = config.persistToLocalStorage\n ? `tinypivot-ai-conversation-${config.sessionId || 'default'}`\n : null\n\n // Load initial conversation from localStorage if enabled\n function loadFromStorage(): AIConversation {\n if (storageKey && typeof window !== 'undefined') {\n try {\n const stored = localStorage.getItem(storageKey)\n if (stored) {\n const parsed = JSON.parse(stored)\n // Validate basic structure\n if (parsed.id && Array.isArray(parsed.messages)) {\n return parsed as AIConversation\n }\n }\n }\n catch (e) {\n console.warn('[TinyPivot] Failed to load conversation from localStorage:', e)\n }\n }\n return createConversation(config.sessionId)\n }\n\n // Save conversation to localStorage if enabled\n function saveToStorage(conv: AIConversation) {\n if (storageKey && typeof window !== 'undefined') {\n try {\n // Custom replacer to handle BigInt values (common in DuckDB results)\n const replacer = (_key: string, value: unknown) => {\n if (typeof value === 'bigint') {\n return Number(value)\n }\n return value\n }\n localStorage.setItem(storageKey, JSON.stringify(conv, replacer))\n }\n catch (e) {\n console.warn('[TinyPivot] Failed to save conversation to localStorage:', e)\n }\n }\n }\n\n // State\n const conversation = ref<AIConversation>(loadFromStorage())\n const schemas = ref<Map<string, AITableSchema>>(new Map())\n const allSchemas = ref<AITableSchema[]>([]) // All table schemas for JOINs\n const isLoading = ref(false)\n const error = ref<string | null>(null)\n const lastLoadedData = ref<Record<string, unknown>[] | null>(null)\n\n // Dynamic data sources (discovered from endpoint)\n const discoveredDataSources = ref<AIDataSource[]>([])\n const isLoadingTables = ref(false)\n\n // Get effective data sources (config or discovered)\n const effectiveDataSources = computed<AIDataSource[]>(() => {\n if (config.dataSources && config.dataSources.length > 0) {\n return config.dataSources\n }\n return discoveredDataSources.value\n })\n\n // Computed\n const selectedDataSource = computed(() => conversation.value.dataSourceId)\n const selectedDataSourceInfo = computed(() =>\n effectiveDataSources.value.find(ds => ds.id === conversation.value.dataSourceId),\n )\n const messages = computed(() => conversation.value.messages)\n const hasMessages = computed(() => conversation.value.messages.length > 0)\n\n /**\n * Fetch available tables from endpoint (auto-discovery mode)\n */\n async function fetchTables() {\n if (!config.endpoint)\n return\n\n isLoadingTables.value = true\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'list-tables' }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch tables: ${response.statusText}`)\n }\n\n const data: ListTablesResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n // Convert to AIDataSource format\n discoveredDataSources.value = data.tables.map((t: { name: string, description?: string }) => ({\n id: t.name,\n table: t.name,\n name: t.name.charAt(0).toUpperCase() + t.name.slice(1), // Capitalize\n description: t.description,\n }))\n\n // Fetch all schemas for JOIN support\n await fetchAllSchemas()\n }\n catch (err) {\n console.warn('[TinyPivot] Failed to fetch tables:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to fetch tables',\n type: 'network',\n })\n }\n finally {\n isLoadingTables.value = false\n }\n }\n\n /**\n * Fetch schemas for ALL tables at once (enables JOINs)\n */\n async function fetchAllSchemas() {\n if (!config.endpoint)\n return\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'get-all-schemas' }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch all schemas: ${response.statusText}`)\n }\n\n const data: SchemaResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n // Store all schemas for JOIN support\n allSchemas.value = data.schemas\n\n // Also populate the individual schemas map\n for (const schema of data.schemas) {\n schemas.value.set(schema.table, schema)\n }\n }\n catch (err) {\n // Schema fetch is optional - continue without it\n console.warn('[TinyPivot] Failed to fetch all schemas:', err)\n }\n }\n\n // Initialize: fetch tables if using endpoint\n onMounted(() => {\n if (config.endpoint && (!config.dataSources || config.dataSources.length === 0)) {\n fetchTables()\n }\n })\n\n /**\n * Select a data source and fetch its schema\n */\n async function selectDataSource(dataSourceId: string) {\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource) {\n error.value = `Data source \"${dataSourceId}\" not found`\n return\n }\n\n // Update conversation\n conversation.value = setConversationDataSource(conversation.value, dataSourceId)\n\n // Add system message about selection\n const systemMessage = createAssistantMessage(\n `I'm now connected to **${dataSource.name}**. ${dataSource.description || ''}\\n\\nWhat would you like to know about this data?`,\n )\n conversation.value = addMessageToConversation(conversation.value, systemMessage)\n\n // Load data source if custom loader is provided (demo mode)\n if (config.dataSourceLoader) {\n try {\n const { data, schema } = await config.dataSourceLoader(dataSourceId)\n if (schema) {\n schemas.value.set(dataSourceId, schema)\n }\n // Store the loaded data for the data source\n if (data && data.length > 0) {\n lastLoadedData.value = data\n onDataLoaded?.({\n data,\n query: `SELECT * FROM ${dataSource.table} LIMIT 100`,\n dataSourceId,\n rowCount: data.length,\n })\n }\n }\n catch (err) {\n console.warn('Failed to load data source:', err)\n }\n }\n // Fetch schema (demo mode uses mock schemas)\n else if (config.demoMode) {\n const demoSchema = getDemoSchema(dataSourceId)\n if (demoSchema) {\n schemas.value.set(dataSourceId, demoSchema)\n }\n // Load initial sample data for the preview\n const initialData = getInitialDemoData(dataSourceId)\n if (initialData) {\n lastLoadedData.value = initialData\n onDataLoaded?.({\n data: initialData,\n query: `SELECT * FROM ${dataSource.table} LIMIT 10`,\n dataSourceId,\n rowCount: initialData.length,\n })\n }\n }\n // Use endpoint for schema discovery and sample data\n else if (config.endpoint) {\n await fetchSchema(dataSource)\n await fetchSampleData(dataSource)\n }\n\n emitConversationUpdate()\n }\n\n /**\n * Fetch schema from the unified endpoint\n */\n async function fetchSchema(dataSource: AIDataSource) {\n if (!config.endpoint)\n return\n\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'get-schema',\n tables: [dataSource.table],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch schema: ${response.statusText}`)\n }\n\n const data: SchemaResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n if (data.schemas.length > 0) {\n schemas.value.set(dataSource.id, data.schemas[0])\n }\n }\n catch (err) {\n // Schema fetch is optional - continue without it\n console.warn('Failed to fetch schema:', err)\n }\n }\n\n /**\n * Fetch sample data (first 100 rows) from the unified endpoint\n */\n async function fetchSampleData(dataSource: AIDataSource) {\n if (!config.endpoint)\n return\n\n try {\n const sql = `SELECT * FROM ${dataSource.table} LIMIT 100`\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql,\n table: dataSource.table,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch sample data: ${response.statusText}`)\n }\n\n const result = await response.json()\n\n if (result.error) {\n throw new Error(result.error)\n }\n\n if (result.data && result.data.length > 0) {\n lastLoadedData.value = result.data\n onDataLoaded?.({\n data: result.data,\n query: sql,\n dataSourceId: dataSource.id,\n rowCount: result.data.length,\n })\n }\n }\n catch (err) {\n // Sample data fetch is optional - continue without it\n console.warn('Failed to fetch sample data:', err)\n }\n }\n\n /**\n * Send a message to the AI\n */\n async function sendMessage(content: string) {\n if (!content.trim())\n return\n if (isLoading.value)\n return\n\n error.value = null\n isLoading.value = true\n\n // Add user message\n const userMessage = createUserMessage(content)\n conversation.value = addMessageToConversation(conversation.value, userMessage)\n emitConversationUpdate()\n\n try {\n // Handle demo mode\n if (config.demoMode) {\n await handleDemoResponse(content)\n return\n }\n\n // Check if data source is selected\n if (!conversation.value.dataSourceId) {\n const assistantMessage = createAssistantMessage(\n 'Please select a data source first by clicking one of the options above.',\n )\n conversation.value = addMessageToConversation(conversation.value, assistantMessage)\n emitConversationUpdate()\n return\n }\n\n // Call AI endpoint\n const aiResponse = await callAIEndpoint(content)\n\n // Check if AI wants to run a query\n const sqlQuery = extractSQLFromResponse(aiResponse)\n\n if (sqlQuery) {\n // Validate SQL\n const validation = validateSQLSafety(sqlQuery)\n if (!validation.valid) {\n const errorMessage = createAssistantMessage(\n `I generated an invalid query: ${validation.error}. Let me try again with a corrected approach.`,\n { error: validation.error },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n return\n }\n\n // Add AI response with query - the executeQuery will update this message with data\n const aiMessage = createAssistantMessage(aiResponse, { query: sqlQuery })\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n\n // Execute query - this will update the last message's metadata with data\n await executeQuery(sqlQuery, aiMessage.id)\n }\n else {\n // Just add AI response\n const aiMessage = createAssistantMessage(aiResponse)\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n }\n }\n catch (err) {\n const errorMsg = err instanceof Error ? err.message : 'An error occurred'\n error.value = errorMsg\n\n const errorMessage = createAssistantMessage(\n `Sorry, I encountered an error: ${errorMsg}. Please try again.`,\n { error: errorMsg },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onError?.({\n message: errorMsg,\n type: 'ai',\n })\n }\n finally {\n isLoading.value = false\n }\n }\n\n /**\n * Handle demo mode responses (canned AI + mock data)\n */\n async function handleDemoResponse(userInput: string) {\n // Simulate loading delay\n await new Promise(resolve => setTimeout(resolve, 800))\n\n const dataSourceId = conversation.value.dataSourceId\n\n if (!dataSourceId) {\n const assistantMessage = createAssistantMessage(\n 'Please select a data source first by clicking one of the options above.',\n )\n conversation.value = addMessageToConversation(conversation.value, assistantMessage)\n emitConversationUpdate()\n isLoading.value = false\n return\n }\n\n // Find matching demo response\n const demoTrigger = findDemoResponse(dataSourceId, userInput)\n\n if (demoTrigger) {\n // Add AI response\n const aiMessage = createAssistantMessage(demoTrigger.response, {\n query: demoTrigger.query,\n rowCount: demoTrigger.mockData?.length,\n })\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n\n // Load mock data\n if (demoTrigger.mockData) {\n lastLoadedData.value = demoTrigger.mockData\n\n onDataLoaded?.({\n data: demoTrigger.mockData,\n query: demoTrigger.query || '',\n dataSourceId,\n rowCount: demoTrigger.mockData.length,\n })\n\n onQueryExecuted?.({\n query: demoTrigger.query || '',\n rowCount: demoTrigger.mockData.length,\n duration: 150, // Fake duration\n dataSourceId,\n success: true,\n })\n }\n }\n else {\n // Use default response\n const defaultResponse = getDefaultDemoResponse(dataSourceId)\n const aiMessage = createAssistantMessage(defaultResponse)\n conversation.value = addMessageToConversation(conversation.value, aiMessage)\n emitConversationUpdate()\n }\n\n isLoading.value = false\n }\n\n /**\n * Call the AI endpoint\n */\n async function callAIEndpoint(userInput: string): Promise<string> {\n if (!config.endpoint) {\n throw new Error('No endpoint configured. Set `endpoint` in AI analyst config.')\n }\n\n const dataSourceId = conversation.value.dataSourceId\n\n // Build system prompt using effective data sources\n // Pass allSchemas to enable JOINs with related tables\n const systemPrompt = buildSystemPrompt(\n effectiveDataSources.value,\n schemas.value,\n dataSourceId,\n allSchemas.value.length > 0 ? allSchemas.value : undefined,\n )\n\n // Get conversation messages for API\n const apiMessages = getMessagesForAPI(conversation.value)\n\n // Add system prompt and current user message\n const messages = [\n { role: 'user' as const, content: systemPrompt },\n { role: 'assistant' as const, content: 'I understand. I\\'m ready to help you analyze the data.' },\n ...apiMessages.slice(0, -1), // Exclude the just-added user message\n { role: 'user' as const, content: userInput },\n ]\n\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'chat', messages }),\n })\n\n if (!response.ok) {\n throw new Error(`AI request failed: ${response.statusText}`)\n }\n\n const data: AIProxyResponse = await response.json()\n\n if (data.error) {\n throw new Error(data.error)\n }\n\n return data.content\n }\n\n /**\n * Execute a SQL query and update the specified message with results\n * @param sql The SQL query to execute\n * @param messageId Optional message ID to update with results (instead of adding new message)\n */\n async function executeQuery(sql: string, messageId?: string) {\n const dataSourceId = conversation.value.dataSourceId\n if (!dataSourceId)\n return\n\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource)\n return\n\n const startTime = Date.now()\n\n try {\n let data: { data?: Record<string, unknown>[], rowCount?: number, truncated?: boolean, error?: string, success?: boolean }\n\n // Use custom query executor if provided (demo mode)\n if (config.queryExecutor) {\n const result = await config.queryExecutor(sql, dataSource.table)\n data = {\n data: result.data,\n rowCount: result.rowCount,\n truncated: result.truncated,\n error: result.error,\n success: !result.error,\n }\n }\n // Use unified endpoint\n else if (config.endpoint) {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql,\n table: dataSource.table,\n }),\n })\n\n data = await response.json()\n }\n else {\n throw new Error('No query executor or endpoint configured')\n }\n\n const duration = Date.now() - startTime\n\n if (!data.success || data.error) {\n // Add error message\n const errorMessage = createAssistantMessage(\n `The query failed: ${data.error || 'Unknown error'}. Would you like me to try a different approach?`,\n { error: data.error, query: sql },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onQueryExecuted?.({\n query: sql,\n rowCount: 0,\n duration,\n dataSourceId,\n success: false,\n error: data.error,\n })\n\n onError?.({\n message: data.error || 'Query failed',\n query: sql,\n type: 'query',\n })\n return\n }\n\n // Success - load data\n if (data.data) {\n lastLoadedData.value = data.data\n\n // Update the existing message with data, or add a new one if no messageId\n if (messageId) {\n // Find and update the existing message's metadata with the data\n const updatedMessages = conversation.value.messages.map((msg) => {\n if (msg.id === messageId) {\n return {\n ...msg,\n metadata: {\n ...msg.metadata,\n data: data.data,\n rowCount: data.rowCount,\n truncated: data.truncated,\n },\n }\n }\n return msg\n })\n conversation.value = {\n ...conversation.value,\n messages: updatedMessages,\n updatedAt: Date.now(),\n }\n }\n else {\n // Fallback: add a new message (shouldn't happen in normal flow)\n const truncatedNote = data.truncated\n ? ` (limited to ${config.maxRows || 10000} rows)`\n : ''\n const successMessage = createAssistantMessage(\n `Retrieved **${data.rowCount} rows**${truncatedNote}.`,\n { query: sql, rowCount: data.rowCount, data: data.data },\n )\n conversation.value = addMessageToConversation(conversation.value, successMessage)\n }\n emitConversationUpdate()\n\n onDataLoaded?.({\n data: data.data,\n query: sql,\n dataSourceId,\n rowCount: data.rowCount || data.data.length,\n })\n\n onQueryExecuted?.({\n query: sql,\n rowCount: data.rowCount || data.data.length,\n duration,\n dataSourceId,\n success: true,\n })\n }\n }\n catch (err) {\n const duration = Date.now() - startTime\n const errorMsg = err instanceof Error ? err.message : 'Query execution failed'\n\n const errorMessage = createAssistantMessage(\n `Failed to execute query: ${errorMsg}`,\n { error: errorMsg, query: sql },\n )\n conversation.value = addMessageToConversation(conversation.value, errorMessage)\n emitConversationUpdate()\n\n onQueryExecuted?.({\n query: sql,\n rowCount: 0,\n duration,\n dataSourceId,\n success: false,\n error: errorMsg,\n })\n\n onError?.({\n message: errorMsg,\n query: sql,\n type: 'network',\n })\n }\n }\n\n /**\n * Load full data for the currently selected data source\n * Returns the full dataset (not limited) for displaying in the grid\n */\n async function loadFullData(): Promise<Record<string, unknown>[] | null> {\n const dataSourceId = conversation.value.dataSourceId\n if (!dataSourceId) {\n return null\n }\n\n const dataSource = effectiveDataSources.value.find(ds => ds.id === dataSourceId)\n if (!dataSource) {\n return null\n }\n\n // Use custom data source loader if provided\n if (config.dataSourceLoader) {\n try {\n const { data } = await config.dataSourceLoader(dataSourceId)\n if (data && data.length > 0) {\n return data\n }\n }\n catch (err) {\n console.warn('Failed to load full data:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Use query executor to get all data\n if (config.queryExecutor) {\n try {\n const result = await config.queryExecutor(\n `SELECT * FROM ${dataSource.table}`,\n dataSource.table,\n )\n if (result.data && result.data.length > 0) {\n return result.data\n }\n }\n catch (err) {\n console.warn('Failed to load full data via query:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Use endpoint query action\n if (config.endpoint) {\n try {\n const response = await fetch(config.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n action: 'query',\n sql: `SELECT * FROM ${dataSource.table}`,\n table: dataSource.table,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to load data: ${response.statusText}`)\n }\n\n const data = await response.json()\n if (data.data && data.data.length > 0) {\n return data.data\n }\n }\n catch (err) {\n console.warn('Failed to load full data from endpoint:', err)\n onError?.({\n message: err instanceof Error ? err.message : 'Failed to load full data',\n type: 'network',\n })\n }\n return null\n }\n\n // Demo mode - get initial data\n if (config.demoMode) {\n const initialData = getInitialDemoData(dataSourceId)\n return initialData || null\n }\n\n return null\n }\n\n /**\n * Clear the conversation\n */\n function clearConversation() {\n conversation.value = createConversation(config.sessionId)\n error.value = null\n lastLoadedData.value = null\n emitConversationUpdate()\n }\n\n /**\n * Export conversation for persistence\n */\n function exportConversation(): AIConversation {\n return { ...conversation.value }\n }\n\n /**\n * Import a conversation\n */\n function importConversation(conv: AIConversation) {\n conversation.value = conv\n emitConversationUpdate()\n }\n\n /**\n * Emit conversation update event and persist to storage if enabled\n */\n function emitConversationUpdate() {\n saveToStorage(conversation.value)\n onConversationUpdate?.({ conversation: conversation.value })\n }\n\n return {\n // State\n conversation,\n messages,\n hasMessages,\n schemas,\n isLoading,\n isLoadingTables,\n error,\n lastLoadedData,\n selectedDataSource,\n selectedDataSourceInfo,\n /** Available data sources (either from config or auto-discovered) */\n dataSources: effectiveDataSources,\n\n // Actions\n selectDataSource,\n sendMessage,\n clearConversation,\n exportConversation,\n importConversation,\n /** Refresh table list from endpoint */\n fetchTables,\n /** Load full data for the currently selected data source */\n loadFullData,\n }\n}\n","<script setup lang=\"ts\">\n/**\n * TinyPivot - AI Data Analyst Component\n * Split-panel layout: 1/4 chat, 3/4 data preview\n * Each query step shows data visually with expandable SQL\n */\nimport type {\n AIAnalystConfig,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIErrorEvent,\n AIMessage,\n AIQueryExecutedEvent,\n AITableSchema,\n} from '@smallwebco/tinypivot-core'\nimport { stripSQLFromContent } from '@smallwebco/tinypivot-core'\nimport { computed, nextTick, ref, watch } from 'vue'\nimport { useAIAnalyst } from '../composables/useAIAnalyst'\n\nconst props = defineProps<{\n config: AIAnalystConfig\n theme?: 'light' | 'dark'\n}>()\n\nconst emit = defineEmits<{\n (e: 'dataLoaded', payload: AIDataLoadedEvent): void\n (e: 'conversationUpdate', payload: AIConversationUpdateEvent): void\n (e: 'queryExecuted', payload: AIQueryExecutedEvent): void\n (e: 'error', payload: AIErrorEvent): void\n (e: 'viewResults', payload: { data: Record<string, unknown>[], query: string }): void\n}>()\n\nconst {\n messages,\n hasMessages,\n isLoading,\n isLoadingTables,\n schemas,\n selectedDataSource,\n selectedDataSourceInfo,\n lastLoadedData,\n dataSources,\n selectDataSource,\n sendMessage,\n clearConversation,\n loadFullData,\n} = useAIAnalyst({\n config: props.config,\n onDataLoaded: payload => emit('dataLoaded', payload),\n onConversationUpdate: payload => emit('conversationUpdate', payload),\n onQueryExecuted: payload => emit('queryExecuted', payload),\n onError: payload => emit('error', payload),\n})\n\n// Expose loadFullData for parent component access\ndefineExpose({\n loadFullData,\n selectedDataSource,\n})\n\n// Input state\nconst inputText = ref('')\nconst searchQuery = ref('')\nconst messagesContainerRef = ref<HTMLDivElement>()\n\n// Track which message's data is being viewed (null = latest)\nconst selectedMessageId = ref<string | null>(null)\n\n// Track SQL panel visibility in the right pane\nconst showSqlPanel = ref(false)\n\n// Filter data sources by search\nconst filteredDataSources = computed(() => {\n if (!searchQuery.value.trim())\n return dataSources.value\n const q = searchQuery.value.toLowerCase()\n return dataSources.value.filter(ds =>\n ds.name.toLowerCase().includes(q)\n || ds.description?.toLowerCase().includes(q)\n || ds.table.toLowerCase().includes(q),\n )\n})\n\n// Get schema for selected data source\nconst currentSchema = computed((): AITableSchema | undefined => {\n if (!selectedDataSource.value)\n return undefined\n return schemas.value.get(selectedDataSource.value)\n})\n\n// Get data for the selected message (or latest)\nconst previewData = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n if (msg?.metadata?.data) {\n return msg.metadata.data.slice(0, 100)\n }\n }\n // Fall back to lastLoadedData\n if (!lastLoadedData.value)\n return []\n return lastLoadedData.value.slice(0, 100)\n})\n\n// Get full data for the selected message\nconst fullPreviewData = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n if (msg?.metadata?.data) {\n return msg.metadata.data\n }\n }\n return lastLoadedData.value || []\n})\n\n// Get column keys from preview data\nconst previewColumns = computed(() => {\n if (previewData.value.length > 0) {\n return Object.keys(previewData.value[0])\n }\n if (currentSchema.value) {\n return currentSchema.value.columns.map(c => c.name)\n }\n return []\n})\n\n// Get the selected message's query\nconst selectedQuery = computed(() => {\n if (selectedMessageId.value) {\n const msg = messages.value.find(m => m.id === selectedMessageId.value)\n return msg?.metadata?.query || ''\n }\n // Find the last message with data\n for (let i = messages.value.length - 1; i >= 0; i--) {\n if (messages.value[i].metadata?.data) {\n return messages.value[i].metadata?.query || ''\n }\n }\n return ''\n})\n\n// Scroll to bottom when messages change\nwatch(messages, () => {\n nextTick(() => {\n if (messagesContainerRef.value) {\n messagesContainerRef.value.scrollTop = messagesContainerRef.value.scrollHeight\n }\n })\n // Auto-select the latest message with data\n const latestWithData = [...messages.value].reverse().find(m => m.metadata?.data)\n if (latestWithData) {\n selectedMessageId.value = latestWithData.id\n }\n}, { deep: true })\n\nfunction handleSubmit() {\n if (!inputText.value.trim() || isLoading.value)\n return\n sendMessage(inputText.value)\n inputText.value = ''\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault()\n handleSubmit()\n }\n}\n\nfunction handleViewResults() {\n if (fullPreviewData.value.length > 0) {\n emit('viewResults', { data: fullPreviewData.value, query: selectedQuery.value })\n }\n}\n\nfunction selectMessage(messageId: string) {\n const msg = messages.value.find(m => m.id === messageId)\n if (msg?.metadata?.data) {\n selectedMessageId.value = messageId\n }\n}\n\nfunction toggleSqlPanel() {\n showSqlPanel.value = !showSqlPanel.value\n}\n\nfunction copyToClipboard(text: string) {\n if (typeof window !== 'undefined' && window.navigator?.clipboard) {\n window.navigator.clipboard.writeText(text)\n }\n}\n\nfunction handleClearConversation() {\n clearConversation()\n searchQuery.value = ''\n selectedMessageId.value = null\n showSqlPanel.value = false\n}\n\nfunction handleChangeDataSource() {\n clearConversation()\n searchQuery.value = ''\n selectedMessageId.value = null\n showSqlPanel.value = false\n}\n\nfunction getColumnTypeIcon(type: string): string {\n const t = type.toLowerCase()\n if (t.includes('int') || t.includes('float') || t.includes('decimal') || t.includes('number'))\n return '#'\n if (t.includes('date') || t.includes('time'))\n return 'D'\n if (t.includes('bool'))\n return '?'\n return 'T'\n}\n\nfunction formatCellValue(value: unknown): string {\n if (value === null || value === undefined)\n return ''\n if (typeof value === 'number') {\n if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n return String(value)\n }\n return String(value)\n}\n\nfunction getMessageContent(message: AIMessage): string {\n // Strip SQL blocks and clean up markdown formatting\n return stripSQLFromContent(message.content)\n .replace(/\\*\\*/g, '')\n .replace(/`([^`]+)`/g, '$1')\n .trim()\n}\n\nfunction autoResizeTextarea(event: Event) {\n const textarea = event.target as HTMLTextAreaElement\n textarea.style.height = 'auto'\n textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`\n}\n\nfunction hasQueryResult(message: AIMessage): boolean {\n return !!message.metadata?.data && message.metadata.data.length > 0\n}\n</script>\n\n<template>\n <div class=\"vpg-ai-analyst\" :class=\"{ 'vpg-theme-dark': theme === 'dark' }\">\n <!-- Data Source Picker (full width when no data source selected) -->\n <div v-if=\"!selectedDataSource\" class=\"vpg-ai-picker-fullscreen\">\n <div class=\"vpg-ai-picker-content\">\n <div class=\"vpg-ai-picker-header\">\n <div class=\"vpg-ai-icon-lg\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <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\" />\n <circle cx=\"7.5\" cy=\"14.5\" r=\"1.5\" fill=\"currentColor\" />\n <circle cx=\"16.5\" cy=\"14.5\" r=\"1.5\" fill=\"currentColor\" />\n </svg>\n </div>\n <h2>AI Data Analyst</h2>\n <p>Select a data source to start exploring with AI</p>\n </div>\n\n <!-- Empty state -->\n <template v-if=\"dataSources.length === 0 && !isLoadingTables\">\n <div class=\"vpg-ai-empty-state\">\n <p>No data sources configured.</p>\n <a\n href=\"https://tinypivot.com/docs/ai-analyst\"\n target=\"_blank\"\n rel=\"noopener\"\n class=\"vpg-ai-docs-link\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n <polyline points=\"15 3 21 3 21 9\" />\n <line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\" />\n </svg>\n View Documentation\n </a>\n </div>\n </template>\n\n <!-- Data source list -->\n <template v-else>\n <div class=\"vpg-ai-search\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n </svg>\n <input\n v-model=\"searchQuery\"\n type=\"text\"\n placeholder=\"Search data sources...\"\n class=\"vpg-ai-search-input\"\n >\n </div>\n\n <div class=\"vpg-ai-datasource-grid\">\n <button\n v-for=\"ds in filteredDataSources\"\n :key=\"ds.id\"\n class=\"vpg-ai-datasource-card\"\n @click=\"selectDataSource(ds.id)\"\n >\n <div class=\"vpg-ai-datasource-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\" />\n </svg>\n </div>\n <div class=\"vpg-ai-datasource-info\">\n <span class=\"vpg-ai-datasource-name\">{{ ds.name }}</span>\n <span v-if=\"ds.description\" class=\"vpg-ai-datasource-desc\">{{ ds.description }}</span>\n </div>\n </button>\n </div>\n\n <div v-if=\"filteredDataSources.length === 0\" class=\"vpg-ai-no-results\">\n No data sources match \"{{ searchQuery }}\"\n </div>\n </template>\n </div>\n </div>\n\n <!-- Split Layout: Chat (1/4) + Data Preview (3/4) -->\n <div v-else class=\"vpg-ai-split-layout\">\n <!-- Left Panel: Chat -->\n <div class=\"vpg-ai-chat-panel\">\n <!-- Chat Header -->\n <div class=\"vpg-ai-chat-header\">\n <button\n class=\"vpg-ai-back-btn\"\n title=\"Change data source\"\n @click=\"handleChangeDataSource\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n </button>\n <div class=\"vpg-ai-chat-title\">\n <span class=\"vpg-ai-chat-name\">{{ selectedDataSourceInfo?.name }}</span>\n </div>\n <button\n v-if=\"hasMessages\"\n class=\"vpg-ai-clear-btn\"\n title=\"Clear conversation\"\n @click=\"handleClearConversation\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n </button>\n </div>\n\n <!-- Messages -->\n <div ref=\"messagesContainerRef\" class=\"vpg-ai-messages\">\n <!-- Welcome message when no messages -->\n <div v-if=\"!hasMessages\" class=\"vpg-ai-welcome\">\n <p>Ask questions about your data</p>\n <div class=\"vpg-ai-suggestions\">\n <button @click=\"sendMessage('Show me a summary of the data')\">\n Summary\n </button>\n <button @click=\"sendMessage('Show me the top 10 records')\">\n Top 10\n </button>\n <button @click=\"sendMessage('What are the trends?')\">\n Trends\n </button>\n </div>\n </div>\n\n <!-- Message list -->\n <template v-for=\"message in messages\" :key=\"message.id\">\n <!-- User message -->\n <div\n v-if=\"message.role === 'user'\"\n class=\"vpg-ai-msg vpg-ai-msg-user\"\n >\n <span>{{ message.content }}</span>\n </div>\n\n <!-- Assistant message with query result -->\n <div\n v-else-if=\"hasQueryResult(message)\"\n class=\"vpg-ai-msg vpg-ai-msg-result\"\n :class=\"{ 'vpg-ai-msg-selected': selectedMessageId === message.id }\"\n @click=\"selectMessage(message.id)\"\n >\n <!-- Header with result badge and SQL button -->\n <div class=\"vpg-ai-result-header\">\n <div class=\"vpg-ai-result-badge\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\" />\n <polyline points=\"22 4 12 14.01 9 11.01\" />\n </svg>\n <span>{{ message.metadata?.rowCount?.toLocaleString() }} rows</span>\n </div>\n <!-- SQL toggle button - toggles right pane SQL panel -->\n <button\n v-if=\"message.metadata?.query\"\n class=\"vpg-ai-sql-toggle\"\n :class=\"{ 'vpg-ai-sql-expanded': showSqlPanel && selectedMessageId === message.id }\"\n title=\"View SQL query\"\n @click.stop=\"toggleSqlPanel()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </svg>\n <span>SQL</span>\n </button>\n </div>\n <!-- Full message content (insight from AI) -->\n <div class=\"vpg-ai-result-content\">\n {{ getMessageContent(message) }}\n </div>\n </div>\n\n <!-- Assistant message without data (text only) -->\n <div\n v-else-if=\"message.role === 'assistant'\"\n class=\"vpg-ai-msg vpg-ai-msg-assistant\"\n >\n <div class=\"vpg-ai-assistant-content\">\n {{ getMessageContent(message) }}\n </div>\n <!-- Error indicator -->\n <div v-if=\"message.metadata?.error\" class=\"vpg-ai-msg-error\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\" />\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\" />\n </svg>\n Error\n </div>\n </div>\n </template>\n\n <!-- Loading indicator -->\n <div v-if=\"isLoading\" class=\"vpg-ai-msg vpg-ai-msg-loading\">\n <div class=\"vpg-ai-typing\">\n <span /><span /><span />\n </div>\n </div>\n </div>\n\n <!-- Input Area with Controls -->\n <div class=\"vpg-ai-input-area\">\n <form class=\"vpg-ai-input-form\" @submit.prevent=\"handleSubmit\">\n <textarea\n v-model=\"inputText\"\n class=\"vpg-ai-input\"\n placeholder=\"Ask about your data...\"\n :disabled=\"isLoading\"\n rows=\"1\"\n @keydown=\"handleKeydown\"\n @input=\"autoResizeTextarea\"\n />\n <button\n type=\"submit\"\n class=\"vpg-ai-send-btn\"\n :disabled=\"!inputText.trim() || isLoading\"\n title=\"Send\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\n </svg>\n </button>\n </form>\n <!-- Action buttons and model info -->\n <div class=\"vpg-ai-input-footer\">\n <span v-if=\"config.aiModelName\" class=\"vpg-ai-model-name\">\n {{ config.aiModelName }}\n </span>\n <div class=\"vpg-ai-input-actions\">\n <button\n v-if=\"fullPreviewData.length > 0\"\n class=\"vpg-ai-action-btn vpg-ai-action-primary\"\n title=\"View in Grid tab\"\n @click=\"handleViewResults\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n View in Grid\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Right Panel: Data Scratchpad -->\n <div class=\"vpg-ai-preview-panel\">\n <!-- Header with schema -->\n <div class=\"vpg-ai-preview-header\">\n <div class=\"vpg-ai-preview-title-row\">\n <h3>{{ selectedDataSourceInfo?.name }}</h3>\n <div class=\"vpg-ai-preview-meta\">\n <span v-if=\"fullPreviewData.length > 0\" class=\"vpg-ai-preview-count\">\n {{ fullPreviewData.length.toLocaleString() }} rows\n </span>\n <button\n v-if=\"selectedQuery\"\n class=\"vpg-ai-preview-sql-btn\"\n :class=\"{ 'vpg-ai-sql-active': showSqlPanel }\"\n title=\"Toggle SQL query\"\n @click=\"toggleSqlPanel()\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </svg>\n SQL\n </button>\n <button\n v-if=\"fullPreviewData.length > 0\"\n class=\"vpg-ai-preview-view-btn\"\n title=\"View in Grid\"\n @click=\"handleViewResults\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\" />\n <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\" />\n </svg>\n View in Grid\n </button>\n </div>\n </div>\n <!-- Schema pills in preview header -->\n <div v-if=\"currentSchema\" class=\"vpg-ai-schema-bar\">\n <div\n v-for=\"col in currentSchema.columns\"\n :key=\"col.name\"\n class=\"vpg-ai-schema-chip\"\n :title=\"`${col.name} (${col.type})`\"\n >\n <span class=\"vpg-ai-chip-type\">{{ getColumnTypeIcon(col.type) }}</span>\n <span class=\"vpg-ai-chip-name\">{{ col.name }}</span>\n </div>\n </div>\n </div>\n\n <!-- SQL Panel (expandable, above the table) -->\n <div v-if=\"showSqlPanel && selectedQuery\" class=\"vpg-ai-sql-panel\">\n <div class=\"vpg-ai-sql-panel-header\">\n <span class=\"vpg-ai-sql-panel-title\">SQL Query</span>\n <div class=\"vpg-ai-sql-panel-actions\">\n <button\n class=\"vpg-ai-copy-btn\"\n title=\"Copy SQL\"\n @click=\"copyToClipboard(selectedQuery)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n </button>\n <button\n class=\"vpg-ai-sql-panel-close\"\n title=\"Close\"\n @click=\"showSqlPanel = false\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n </div>\n <pre class=\"vpg-ai-sql-panel-code\"><code>{{ selectedQuery }}</code></pre>\n </div>\n\n <!-- Loading state -->\n <div v-if=\"isLoading\" class=\"vpg-ai-preview-loading\">\n <div class=\"vpg-ai-preview-spinner\" />\n <span>Running query...</span>\n </div>\n\n <!-- No data yet - show schema only state -->\n <div v-else-if=\"previewData.length === 0 && currentSchema\" class=\"vpg-ai-preview-ready\">\n <div class=\"vpg-ai-preview-ready-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5\" />\n <path d=\"M3 12c0 1.66 4 3 9 3s9-1.34 9-3\" />\n </svg>\n </div>\n <p>Data source connected</p>\n <span>{{ currentSchema.columns.length }} columns available</span>\n <div class=\"vpg-ai-preview-hint\">\n Ask a question to explore the data\n </div>\n </div>\n\n <!-- No schema loaded yet -->\n <div v-else-if=\"previewData.length === 0\" class=\"vpg-ai-preview-empty\">\n <div class=\"vpg-ai-preview-empty-icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </div>\n <p>Loading data source...</p>\n </div>\n\n <!-- Data table -->\n <div v-else class=\"vpg-ai-preview-table-container\">\n <table class=\"vpg-ai-preview-table\">\n <thead>\n <tr>\n <th v-for=\"col in previewColumns\" :key=\"col\">\n {{ col }}\n </th>\n </tr>\n </thead>\n <tbody>\n <tr v-for=\"(row, idx) in previewData\" :key=\"idx\">\n <td v-for=\"col in previewColumns\" :key=\"col\">\n {{ formatCellValue(row[col]) }}\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"fullPreviewData.length > 100\" class=\"vpg-ai-preview-more\">\n Showing 100 of {{ fullPreviewData.length.toLocaleString() }} rows.\n <button @click=\"handleViewResults\">\n View all in Grid\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-ai-analyst {\n display: flex;\n flex-direction: column;\n height: 100%;\n background: #f8fafc;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n}\n\n/* Full-screen picker */\n.vpg-ai-picker-fullscreen {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n}\n\n.vpg-ai-picker-content {\n max-width: 600px;\n width: 100%;\n max-height: 100%;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n}\n\n.vpg-ai-picker-header {\n text-align: center;\n margin-bottom: 2rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-icon-lg {\n width: 4rem;\n height: 4rem;\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n border-radius: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n margin: 0 auto 1rem;\n}\n\n.vpg-ai-icon-lg svg {\n width: 2rem;\n height: 2rem;\n}\n\n.vpg-ai-picker-header h2 {\n margin: 0 0 0.5rem;\n font-size: 1.5rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-picker-header p {\n margin: 0;\n color: #64748b;\n}\n\n/* Search */\n.vpg-ai-search {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.75rem 1rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n margin-bottom: 1rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-search svg {\n width: 1.25rem;\n height: 1.25rem;\n color: #94a3b8;\n flex-shrink: 0;\n}\n\n.vpg-ai-search-input {\n flex: 1;\n border: none;\n outline: none;\n font-size: 0.9375rem;\n color: #1e293b;\n background: transparent;\n}\n\n.vpg-ai-search-input::placeholder {\n color: #94a3b8;\n}\n\n/* Data source grid */\n.vpg-ai-datasource-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));\n gap: 0.75rem;\n overflow-y: auto;\n max-height: 400px;\n padding-right: 0.25rem;\n}\n\n.vpg-ai-datasource-card {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 1rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n cursor: pointer;\n text-align: left;\n transition: all 0.15s;\n}\n\n.vpg-ai-datasource-card:hover {\n border-color: #6366f1;\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.15);\n}\n\n.vpg-ai-datasource-icon {\n width: 2.25rem;\n height: 2.25rem;\n background: #eef2ff;\n border-radius: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #6366f1;\n flex-shrink: 0;\n}\n\n.vpg-ai-datasource-icon svg {\n width: 1.125rem;\n height: 1.125rem;\n}\n\n.vpg-ai-datasource-info {\n flex: 1;\n min-width: 0;\n}\n\n.vpg-ai-datasource-name {\n display: block;\n font-size: 0.8125rem;\n font-weight: 600;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-datasource-desc {\n display: block;\n font-size: 0.6875rem;\n color: #64748b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-no-results,\n.vpg-ai-empty-state {\n text-align: center;\n padding: 2rem;\n color: #94a3b8;\n}\n\n.vpg-ai-docs-link {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.625rem 1rem;\n font-size: 0.875rem;\n color: #6366f1;\n background: #eef2ff;\n border-radius: 0.375rem;\n text-decoration: none;\n transition: all 0.15s;\n}\n\n.vpg-ai-docs-link:hover {\n background: #e0e7ff;\n}\n\n.vpg-ai-docs-link svg {\n width: 1rem;\n height: 1rem;\n}\n\n/* Split Layout */\n.vpg-ai-split-layout {\n flex: 1;\n display: flex;\n min-height: 0;\n}\n\n/* Chat Panel (1/4) */\n.vpg-ai-chat-panel {\n width: 300px;\n min-width: 260px;\n max-width: 360px;\n display: flex;\n flex-direction: column;\n background: white;\n border-right: 1px solid #e2e8f0;\n}\n\n.vpg-ai-chat-header {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.5rem 0.625rem;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-back-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-back-btn:hover {\n background: #f1f5f9;\n color: #1e293b;\n}\n\n.vpg-ai-back-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-ai-clear-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.5rem;\n height: 1.5rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-clear-btn:hover {\n background: #fef2f2;\n color: #dc2626;\n}\n\n.vpg-ai-clear-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-ai-chat-title {\n flex: 1;\n min-width: 0;\n}\n\n.vpg-ai-chat-name {\n display: block;\n font-size: 0.75rem;\n font-weight: 600;\n color: #1e293b;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Messages */\n.vpg-ai-messages {\n flex: 1;\n overflow-y: auto;\n padding: 0.75rem;\n padding-bottom: 1rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.vpg-ai-welcome {\n text-align: center;\n padding: 0.75rem 0;\n}\n\n.vpg-ai-welcome p {\n margin: 0 0 0.5rem;\n font-size: 0.75rem;\n color: #64748b;\n}\n\n.vpg-ai-suggestions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 0.25rem;\n}\n\n.vpg-ai-suggestions button {\n padding: 0.25rem 0.5rem;\n font-size: 0.625rem;\n color: #6366f1;\n background: #eef2ff;\n border: none;\n border-radius: 0.75rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-suggestions button:hover {\n background: #e0e7ff;\n}\n\n/* Message styles */\n.vpg-ai-msg {\n max-width: 100%;\n font-size: 0.75rem;\n line-height: 1.5;\n}\n\n.vpg-ai-msg-user {\n align-self: flex-end;\n background: #4f46e5;\n color: white;\n padding: 0.5rem 0.625rem;\n border-radius: 0.75rem 0.75rem 0.25rem 0.75rem;\n max-width: 90%;\n word-wrap: break-word;\n flex-shrink: 0;\n}\n\n.vpg-ai-msg-assistant {\n background: #f1f5f9;\n color: #334155;\n padding: 0.5rem 0.625rem;\n border-radius: 0.75rem 0.75rem 0.75rem 0.25rem;\n max-width: 100%;\n flex-shrink: 0;\n}\n\n.vpg-ai-assistant-content {\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.vpg-ai-msg-error {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n margin-top: 0.375rem;\n padding: 0.25rem 0.5rem;\n background: #fef2f2;\n color: #dc2626;\n font-size: 0.6875rem;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-msg-error svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Result message (clickable) */\n.vpg-ai-msg-result {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n cursor: pointer;\n transition: all 0.15s;\n padding: 0.5rem;\n flex-shrink: 0;\n}\n\n.vpg-ai-msg-result:hover {\n border-color: #c7d2fe;\n}\n\n.vpg-ai-msg-result.vpg-ai-msg-selected {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);\n}\n\n/* Result header with badge and SQL toggle */\n.vpg-ai-result-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.375rem;\n}\n\n/* Result badge */\n.vpg-ai-result-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n background: #ecfdf5;\n color: #059669;\n font-size: 0.625rem;\n font-weight: 600;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-result-badge svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* SQL toggle button */\n.vpg-ai-sql-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0.375rem;\n background: #f1f5f9;\n color: #64748b;\n font-size: 0.625rem;\n font-weight: 500;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-sql-toggle:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-sql-toggle.vpg-ai-sql-expanded {\n background: #eef2ff;\n color: #6366f1;\n border-color: #c7d2fe;\n}\n\n.vpg-ai-sql-toggle svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n/* Expanded SQL block */\n.vpg-ai-sql-expanded-block {\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n margin-bottom: 0.375rem;\n overflow: hidden;\n}\n\n.vpg-ai-sql-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.25rem 0.5rem;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n font-size: 0.625rem;\n font-weight: 600;\n color: #64748b;\n}\n\n/* Result content - full text */\n.vpg-ai-result-content {\n font-size: 0.75rem;\n color: #334155;\n line-height: 1.5;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n.vpg-ai-copy-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #94a3b8;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-copy-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-copy-btn svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-ai-sql-code {\n margin: 0;\n padding: 0.375rem 0.5rem;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.6875rem;\n color: #334155;\n background: #f8fafc;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.vpg-ai-sql-code code {\n font-family: inherit;\n}\n\n/* Loading */\n.vpg-ai-msg-loading {\n align-self: flex-start;\n}\n\n.vpg-ai-typing {\n display: flex;\n gap: 0.1875rem;\n padding: 0.375rem 0.5rem;\n background: #f1f5f9;\n border-radius: 0.5rem;\n}\n\n.vpg-ai-typing span {\n width: 0.3125rem;\n height: 0.3125rem;\n background: #94a3b8;\n border-radius: 50%;\n animation: vpg-ai-bounce 1.4s infinite ease-in-out both;\n}\n\n.vpg-ai-typing span:nth-child(1) { animation-delay: -0.32s; }\n.vpg-ai-typing span:nth-child(2) { animation-delay: -0.16s; }\n\n@keyframes vpg-ai-bounce {\n 0%, 80%, 100% { transform: scale(0); }\n 40% { transform: scale(1); }\n}\n\n/* Input Area */\n.vpg-ai-input-area {\n padding: 0.5rem;\n border-top: 1px solid #e2e8f0;\n background: white;\n}\n\n.vpg-ai-input-form {\n display: flex;\n gap: 0.375rem;\n align-items: flex-end;\n}\n\n.vpg-ai-input {\n flex: 1;\n padding: 0.5rem 0.75rem;\n font-size: 0.8125rem;\n border: 1px solid #e2e8f0;\n border-radius: 0.75rem;\n resize: none;\n outline: none;\n transition: border-color 0.15s, box-shadow 0.15s;\n min-height: 2.25rem;\n max-height: 120px;\n overflow-y: auto;\n line-height: 1.4;\n}\n\n.vpg-ai-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.1);\n}\n\n.vpg-ai-input:disabled {\n background: #f8fafc;\n cursor: not-allowed;\n}\n\n.vpg-ai-send-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n background: #4f46e5;\n border: none;\n border-radius: 50%;\n color: white;\n cursor: pointer;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.vpg-ai-send-btn:hover:not(:disabled) {\n background: #4338ca;\n}\n\n.vpg-ai-send-btn:disabled {\n background: #cbd5e1;\n cursor: not-allowed;\n}\n\n.vpg-ai-send-btn svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Input footer with model name and actions */\n.vpg-ai-input-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 0.375rem;\n}\n\n.vpg-ai-model-name {\n font-size: 0.625rem;\n font-style: italic;\n color: #94a3b8;\n}\n\n/* Action buttons */\n.vpg-ai-input-actions {\n display: flex;\n gap: 0.25rem;\n}\n\n.vpg-ai-action-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n background: #f1f5f9;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-action-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-action-btn svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-ai-action-btn.vpg-ai-action-primary {\n background: #eef2ff;\n color: #4f46e5;\n}\n\n.vpg-ai-action-btn.vpg-ai-action-primary:hover {\n background: #e0e7ff;\n}\n\n/* Preview Panel (3/4) */\n.vpg-ai-preview-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-width: 0;\n background: #f8fafc;\n}\n\n.vpg-ai-preview-header {\n display: flex;\n flex-direction: column;\n background: white;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-preview-title-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n}\n\n.vpg-ai-preview-header h3 {\n margin: 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-preview-meta {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-ai-preview-count {\n font-size: 0.75rem;\n color: #64748b;\n padding: 0.125rem 0.5rem;\n background: #f1f5f9;\n border-radius: 0.25rem;\n}\n\n.vpg-ai-preview-sql-btn,\n.vpg-ai-preview-view-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n background: #f1f5f9;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-preview-sql-btn:hover,\n.vpg-ai-preview-view-btn:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-preview-view-btn {\n background: #eef2ff;\n color: #4f46e5;\n}\n\n.vpg-ai-preview-view-btn:hover {\n background: #e0e7ff;\n}\n\n.vpg-ai-preview-sql-btn svg,\n.vpg-ai-preview-view-btn svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n/* Schema bar in preview header */\n.vpg-ai-schema-bar {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n padding: 0.5rem 0.75rem;\n background: #fafbfc;\n border-top: 1px solid #f1f5f9;\n max-height: 80px;\n overflow-y: auto;\n}\n\n.vpg-ai-schema-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n}\n\n.vpg-ai-chip-type {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #e2e8f0;\n border-radius: 0.125rem;\n font-size: 0.625rem;\n font-weight: 700;\n color: #64748b;\n}\n\n.vpg-ai-chip-name {\n color: #475569;\n font-family: ui-monospace, monospace;\n}\n\n/* SQL Panel (collapsible, above the table) */\n.vpg-ai-sql-panel {\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-sql-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-ai-sql-panel-title {\n font-size: 0.6875rem;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.vpg-ai-sql-panel-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-ai-sql-panel-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n color: #94a3b8;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-ai-sql-panel-close:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-ai-sql-panel-close svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-ai-sql-panel-code {\n margin: 0;\n padding: 0.75rem;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n font-size: 0.75rem;\n line-height: 1.5;\n color: #334155;\n background: #f8fafc;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 150px;\n overflow-y: auto;\n}\n\n.vpg-ai-sql-panel-code code {\n font-family: inherit;\n}\n\n/* SQL button active state */\n.vpg-ai-preview-sql-btn.vpg-ai-sql-active {\n background: #eef2ff;\n color: #6366f1;\n border-color: #c7d2fe;\n}\n\n/* Loading state */\n.vpg-ai-preview-loading {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 2rem;\n}\n\n.vpg-ai-preview-spinner {\n width: 2rem;\n height: 2rem;\n border: 2px solid #e2e8f0;\n border-top-color: #6366f1;\n border-radius: 50%;\n animation: vpg-ai-spin 1s linear infinite;\n}\n\n@keyframes vpg-ai-spin {\n to { transform: rotate(360deg); }\n}\n\n.vpg-ai-preview-loading span {\n font-size: 0.8125rem;\n color: #64748b;\n}\n\n/* Ready state (schema loaded, no data yet) */\n.vpg-ai-preview-ready {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n text-align: center;\n}\n\n.vpg-ai-preview-ready-icon {\n width: 4rem;\n height: 4rem;\n background: #ecfdf5;\n border-radius: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #10b981;\n margin-bottom: 1rem;\n}\n\n.vpg-ai-preview-ready-icon svg {\n width: 2rem;\n height: 2rem;\n}\n\n.vpg-ai-preview-ready p {\n margin: 0 0 0.25rem;\n font-size: 1rem;\n font-weight: 600;\n color: #1e293b;\n}\n\n.vpg-ai-preview-ready span {\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-ai-preview-hint {\n margin-top: 1rem;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-radius: 0.5rem;\n font-size: 0.8125rem;\n color: #64748b;\n}\n\n/* Preview empty state */\n.vpg-ai-preview-empty {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 2rem;\n text-align: center;\n}\n\n.vpg-ai-preview-empty-icon {\n width: 3.5rem;\n height: 3.5rem;\n background: #e2e8f0;\n border-radius: 0.75rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n margin-bottom: 0.75rem;\n}\n\n.vpg-ai-preview-empty-icon svg {\n width: 1.75rem;\n height: 1.75rem;\n}\n\n.vpg-ai-preview-empty p {\n margin: 0 0 0.25rem;\n font-size: 0.8125rem;\n font-weight: 500;\n color: #475569;\n}\n\n.vpg-ai-preview-empty span {\n font-size: 0.75rem;\n color: #94a3b8;\n}\n\n/* Preview table */\n.vpg-ai-preview-table-container {\n flex: 1;\n overflow: auto;\n}\n\n.vpg-ai-preview-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 0.6875rem;\n}\n\n.vpg-ai-preview-table thead {\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.vpg-ai-preview-table th {\n padding: 0.375rem 0.625rem;\n text-align: left;\n font-size: 0.625rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n background: #f1f5f9;\n border-bottom: 1px solid #e2e8f0;\n white-space: nowrap;\n}\n\n.vpg-ai-preview-table td {\n padding: 0.375rem 0.625rem;\n color: #334155;\n background: white;\n border-bottom: 1px solid #f1f5f9;\n white-space: nowrap;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-ai-preview-table tr:hover td {\n background: #f8fafc;\n}\n\n.vpg-ai-preview-more {\n padding: 0.5rem 0.75rem;\n text-align: center;\n font-size: 0.6875rem;\n color: #64748b;\n background: white;\n border-top: 1px solid #e2e8f0;\n}\n\n.vpg-ai-preview-more button {\n color: #4f46e5;\n background: none;\n border: none;\n cursor: pointer;\n font-weight: 500;\n margin-left: 0.25rem;\n}\n\n.vpg-ai-preview-more button:hover {\n text-decoration: underline;\n}\n\n/* Dark theme */\n.vpg-ai-analyst.vpg-theme-dark {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-ai-picker-header h2 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-picker-header p {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-search {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-search-input {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-card {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-card:hover {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-datasource-name {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-chat-panel {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-chat-header {\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-back-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-clear-btn:hover {\n background: rgba(220, 38, 38, 0.15);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-ai-chat-name {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-welcome p {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-suggestions button {\n background: #334155;\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-suggestions button:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-ai-msg-assistant {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result:hover {\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-ai-msg-result.vpg-ai-msg-selected {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-result-badge {\n background: rgba(16, 185, 129, 0.15);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-ai-result-content {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-sql-reference {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-label {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-sql-code {\n background: #0f172a;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-copy-btn:hover {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-typing {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-input-area {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-input {\n background: #0f172a;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-input:focus {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-action-btn.vpg-ai-action-primary {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-preview-panel {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-ai-preview-header {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-preview-header h3 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn,\n.vpg-theme-dark .vpg-ai-preview-view-btn {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn:hover,\n.vpg-theme-dark .vpg-ai-preview-view-btn:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-view-btn {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-ai-preview-count {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-schema-bar {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-schema-chip {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-chip-type {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-chip-name {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-loading span {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-spinner {\n border-color: #334155;\n border-top-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready-icon {\n background: rgba(16, 185, 129, 0.15);\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready p {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-ai-preview-ready span {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-hint {\n background: #1e293b;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-empty-icon {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-preview-empty p {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table th {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table td {\n background: #0f172a;\n border-color: #1e293b;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-table tr:hover td {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-ai-preview-more {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-result-icon {\n background: rgba(16, 185, 129, 0.15);\n}\n\n.vpg-theme-dark .vpg-ai-model-name {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-header {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-title {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-close:hover {\n background: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-sql-panel-code {\n background: #0f172a;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-ai-preview-sql-btn.vpg-ai-sql-active {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { CalculatedField } from '@smallwebco/tinypivot-core'\nimport {\n validateSimpleFormula,\n} from '@smallwebco/tinypivot-core'\n/**\n * Calculated Field Modal\n * UI for creating custom calculated fields with formulas\n */\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n show: boolean\n availableFields: string[]\n existingField?: CalculatedField | null\n}>()\n\nconst emit = defineEmits<{\n (e: 'close'): void\n (e: 'save', field: CalculatedField): void\n}>()\n\n// Form state\nconst name = ref('')\nconst formula = ref('')\nconst formatAs = ref<'number' | 'percent' | 'currency'>('number')\nconst decimals = ref(2)\nconst error = ref<string | null>(null)\n\n// Reset form when modal opens\nwatch(() => props.show, (show) => {\n if (show) {\n if (props.existingField) {\n name.value = props.existingField.name\n formula.value = props.existingField.formula\n formatAs.value = props.existingField.formatAs || 'number'\n decimals.value = props.existingField.decimals ?? 2\n }\n else {\n name.value = ''\n formula.value = ''\n formatAs.value = 'number'\n decimals.value = 2\n }\n error.value = null\n }\n})\n\n// Validate formula on change\nconst validationError = computed(() => {\n if (!formula.value.trim())\n return null\n return validateSimpleFormula(formula.value, props.availableFields)\n})\n\n// Insert field into formula\nfunction insertField(field: string) {\n // Add field with space padding if there's already content\n if (formula.value.trim() && !formula.value.endsWith(' ')) {\n formula.value += ' '\n }\n formula.value += field\n}\n\n// Insert operator into formula\nfunction insertOperator(op: string) {\n if (formula.value.trim() && !formula.value.endsWith(' ')) {\n formula.value += ' '\n }\n formula.value += `${op} `\n}\n\n// Save calculated field\nfunction save() {\n if (!name.value.trim()) {\n error.value = 'Name is required'\n return\n }\n\n const validationResult = validateSimpleFormula(formula.value, props.availableFields)\n if (validationResult) {\n error.value = validationResult\n return\n }\n\n const field: CalculatedField = {\n id: props.existingField?.id || `calc_${Date.now()}`,\n name: name.value.trim(),\n formula: formula.value.trim(),\n formatAs: formatAs.value,\n decimals: decimals.value,\n }\n\n emit('save', field)\n emit('close')\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div v-if=\"show\" class=\"vpg-modal-overlay\" @click.self=\"emit('close')\">\n <div class=\"vpg-modal\">\n <div class=\"vpg-modal-header\">\n <h3>{{ existingField ? 'Edit' : 'Create' }} Calculated Field</h3>\n <button class=\"vpg-modal-close\" @click=\"emit('close')\">\n ×\n </button>\n </div>\n\n <div class=\"vpg-modal-body\">\n <!-- Name -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label\">Name</label>\n <input\n v-model=\"name\"\n type=\"text\"\n class=\"vpg-input\"\n placeholder=\"e.g., Profit Margin %\"\n >\n </div>\n\n <!-- Formula -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label\">Formula</label>\n <textarea\n v-model=\"formula\"\n class=\"vpg-textarea\"\n placeholder=\"e.g., revenue / units\"\n rows=\"2\"\n />\n <div class=\"vpg-formula-hint\">\n Use field names with math operators: + - * / ( )\n </div>\n <div v-if=\"validationError\" class=\"vpg-error\">\n {{ validationError }}\n </div>\n </div>\n\n <!-- Quick Insert: Operators -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label-small\">Operators</label>\n <div class=\"vpg-button-group\">\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('+')\">\n +\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('-')\">\n −\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('*')\">\n ×\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('/')\">\n ÷\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('(')\">\n (\n </button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator(')')\">\n )\n </button>\n </div>\n </div>\n\n <!-- Quick Insert: Fields (numeric only) -->\n <div class=\"vpg-form-group\">\n <label class=\"vpg-label-small\">Insert Field</label>\n <div v-if=\"availableFields.length > 0\" class=\"vpg-button-group vpg-field-buttons\">\n <button\n v-for=\"field in availableFields\"\n :key=\"field\"\n class=\"vpg-insert-btn vpg-field-btn\"\n @click=\"insertField(field)\"\n >\n {{ field }}\n </button>\n </div>\n <div v-else class=\"vpg-no-fields\">\n No numeric fields available\n </div>\n </div>\n\n <!-- Format Options -->\n <div class=\"vpg-form-row\">\n <div class=\"vpg-form-group vpg-form-group-half\">\n <label class=\"vpg-label\">Format As</label>\n <select v-model=\"formatAs\" class=\"vpg-select\">\n <option value=\"number\">\n Number\n </option>\n <option value=\"percent\">\n Percentage\n </option>\n <option value=\"currency\">\n Currency ($)\n </option>\n </select>\n </div>\n <div class=\"vpg-form-group vpg-form-group-half\">\n <label class=\"vpg-label\">Decimals</label>\n <input\n v-model.number=\"decimals\"\n type=\"number\"\n class=\"vpg-input\"\n min=\"0\"\n max=\"6\"\n >\n </div>\n </div>\n\n <!-- Error -->\n <div v-if=\"error\" class=\"vpg-error vpg-error-box\">\n {{ error }}\n </div>\n </div>\n\n <div class=\"vpg-modal-footer\">\n <button class=\"vpg-btn vpg-btn-secondary\" @click=\"emit('close')\">\n Cancel\n </button>\n <button class=\"vpg-btn vpg-btn-primary\" @click=\"save\">\n {{ existingField ? 'Update' : 'Add' }} Field\n </button>\n </div>\n </div>\n </div>\n </Teleport>\n</template>\n\n<style scoped>\n.vpg-modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9999;\n backdrop-filter: blur(2px);\n}\n\n.vpg-modal {\n background: white;\n border-radius: 0.75rem;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n width: 90%;\n max-width: 520px;\n max-height: 90vh;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-modal-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.25rem;\n border-bottom: 1px solid #e2e8f0;\n background: #f8fafc;\n}\n\n.vpg-modal-header h3 {\n font-size: 1rem;\n font-weight: 600;\n color: #1e293b;\n margin: 0;\n}\n\n.vpg-modal-close {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n color: #64748b;\n background: transparent;\n border: none;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-modal-close:hover {\n background: #e2e8f0;\n color: #1e293b;\n}\n\n.vpg-modal-body {\n padding: 1.25rem;\n overflow-y: auto;\n flex: 1;\n}\n\n.vpg-form-group {\n margin-bottom: 1rem;\n}\n\n.vpg-form-group-half {\n flex: 1;\n}\n\n.vpg-form-row {\n display: flex;\n gap: 1rem;\n}\n\n.vpg-label {\n display: block;\n font-size: 0.8125rem;\n font-weight: 600;\n color: #374151;\n margin-bottom: 0.375rem;\n}\n\n.vpg-label-small {\n display: block;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n margin-bottom: 0.375rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-input,\n.vpg-textarea,\n.vpg-select {\n width: 100%;\n padding: 0.5rem 0.75rem;\n font-size: 0.875rem;\n border: 1px solid #d1d5db;\n border-radius: 0.375rem;\n background: white;\n color: #1e293b;\n transition: all 0.15s;\n}\n\n.vpg-input:focus,\n.vpg-textarea:focus,\n.vpg-select:focus {\n outline: none;\n border-color: #6366f1;\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n}\n\n.vpg-textarea {\n font-family: ui-monospace, monospace;\n resize: vertical;\n}\n\n.vpg-button-group {\n display: flex;\n flex-wrap: wrap;\n gap: 0.375rem;\n}\n\n.vpg-field-buttons {\n max-height: 80px;\n overflow-y: auto;\n}\n\n.vpg-insert-btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 600;\n background: #eef2ff;\n color: #4f46e5;\n border: 1px solid #c7d2fe;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-insert-btn:hover {\n background: #e0e7ff;\n border-color: #a5b4fc;\n}\n\n.vpg-op-btn {\n min-width: 2rem;\n font-size: 0.875rem;\n font-weight: 500;\n}\n\n.vpg-formula-hint {\n margin-top: 0.25rem;\n font-size: 0.6875rem;\n color: #64748b;\n}\n\n.vpg-field-btn {\n background: #f0fdf4;\n color: #15803d;\n border-color: #bbf7d0;\n}\n\n.vpg-field-btn:hover {\n background: #dcfce7;\n border-color: #86efac;\n}\n\n.vpg-no-fields {\n font-size: 0.75rem;\n color: #94a3b8;\n font-style: italic;\n padding: 0.5rem;\n text-align: center;\n background: #f8fafc;\n border-radius: 0.375rem;\n}\n\n.vpg-error {\n font-size: 0.75rem;\n color: #dc2626;\n margin-top: 0.25rem;\n}\n\n.vpg-error-box {\n padding: 0.5rem 0.75rem;\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 0.375rem;\n margin-top: 0.5rem;\n}\n\n.vpg-modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1rem 1.25rem;\n border-top: 1px solid #e2e8f0;\n background: #f8fafc;\n}\n\n.vpg-btn {\n padding: 0.5rem 1rem;\n font-size: 0.875rem;\n font-weight: 500;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-btn-secondary {\n background: white;\n color: #374151;\n border: 1px solid #d1d5db;\n}\n\n.vpg-btn-secondary:hover {\n background: #f3f4f6;\n}\n\n.vpg-btn-primary {\n background: #4f46e5;\n color: white;\n border: 1px solid #4f46e5;\n}\n\n.vpg-btn-primary:hover {\n background: #4338ca;\n border-color: #4338ca;\n}\n</style>\n\n<style>\n/* Dark mode styles */\n.vpg-theme-dark .vpg-modal {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-modal-header {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-modal-header h3 {\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-modal-close {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-modal-close:hover {\n background: #334155;\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-label {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-label-small {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-input,\n.vpg-theme-dark .vpg-textarea,\n.vpg-theme-dark .vpg-select {\n background: #0f172a;\n border-color: #334155;\n color: #f1f5f9;\n}\n\n.vpg-theme-dark .vpg-input:focus,\n.vpg-theme-dark .vpg-textarea:focus,\n.vpg-theme-dark .vpg-select:focus {\n border-color: #6366f1;\n}\n\n.vpg-theme-dark .vpg-insert-btn {\n background: rgba(99, 102, 241, 0.15);\n color: #a5b4fc;\n border-color: rgba(99, 102, 241, 0.3);\n}\n\n.vpg-theme-dark .vpg-field-btn {\n background: rgba(34, 197, 94, 0.15);\n color: #86efac;\n border-color: rgba(34, 197, 94, 0.3);\n}\n\n.vpg-theme-dark .vpg-no-fields {\n background: #334155;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-modal-footer {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-btn-secondary {\n background: #334155;\n color: #e2e8f0;\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-btn-secondary:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-error-box {\n background: rgba(220, 38, 38, 0.15);\n border-color: rgba(220, 38, 38, 0.3);\n}\n</style>\n","<script setup lang=\"ts\">\nimport type {\n ChartAggregation,\n ChartConfig,\n ChartFieldInfo,\n ChartType,\n} from '@smallwebco/tinypivot-core'\n/**\n * TinyPivot - Chart Builder Component\n * Drag-and-drop chart configuration with ApexCharts rendering\n */\nimport type { ApexOptions } from 'apexcharts'\nimport {\n analyzeFieldsForChart,\n CHART_AGGREGATIONS,\n CHART_COLORS,\n CHART_TYPES,\n createDefaultChartConfig,\n getChartGuidance,\n isChartConfigValid,\n processChartData,\n processChartDataForHeatmap,\n processChartDataForPie,\n processChartDataForScatter,\n} from '@smallwebco/tinypivot-core'\nimport { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue'\n\nconst props = defineProps<{\n data: Record<string, unknown>[]\n theme?: 'light' | 'dark'\n fieldRoleOverrides?: Record<string, import('@smallwebco/tinypivot-core').FieldRole>\n}>()\n\nconst emit = defineEmits<{\n (e: 'configChange', config: ChartConfig): void\n}>()\n\n// Lazy load ApexCharts only on client side to avoid SSR issues\nconst VueApexCharts = defineAsyncComponent(() =>\n import('vue3-apexcharts').then(m => m.default),\n)\n\n// Chart configuration state\nconst chartConfig = ref<ChartConfig>(createDefaultChartConfig())\n\n// Field analysis (applies consumer overrides when provided)\nconst fieldInfos = computed(() => analyzeFieldsForChart(props.data, props.fieldRoleOverrides))\n\n// Separate fields by role\nconst dimensions = computed(() => fieldInfos.value.filter(f => f.role === 'dimension' || f.role === 'temporal'))\nconst measures = computed(() => fieldInfos.value.filter(f => f.role === 'measure'))\n\n// Drag state\nconst draggingField = ref<ChartFieldInfo | null>(null)\nconst dragOverZone = ref<string | null>(null)\n\n// UI state\nconst showChartTypeSelector = ref(false)\n\n// Current guidance message\nconst guidance = computed(() => getChartGuidance(chartConfig.value))\n\n// Check if chart is ready to render\nconst chartIsValid = computed(() => isChartConfigValid(chartConfig.value))\n\n// Get currently selected chart type info\nconst selectedChartType = computed(() =>\n CHART_TYPES.find(ct => ct.type === chartConfig.value.type),\n)\n\n// Dynamic zone labels based on chart type\nconst zoneLabels = computed(() => {\n const type = chartConfig.value.type\n switch (type) {\n case 'scatter':\n case 'bubble':\n return {\n xAxis: 'X-Axis (measure)',\n xAxisPlaceholder: 'Drop a measure',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Color by (optional)',\n seriesPlaceholder: 'Group points by dimension',\n showSize: type === 'bubble',\n showSeries: true,\n }\n case 'heatmap':\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (dimension)',\n yAxisPlaceholder: 'Drop a dimension',\n series: 'Value / Intensity',\n seriesPlaceholder: 'Drop a measure for color intensity',\n showSize: false,\n showSeries: true,\n }\n case 'pie':\n case 'donut':\n return {\n xAxis: 'Slices (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Values (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: '',\n seriesPlaceholder: '',\n showSize: false,\n showSeries: false,\n }\n case 'radar':\n return {\n xAxis: 'Axes (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Values (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Compare by (optional)',\n seriesPlaceholder: 'Group by dimension',\n showSize: false,\n showSeries: true,\n }\n case 'stackedBar':\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Series (stacking field)',\n seriesPlaceholder: 'Drop a dimension to stack by',\n showSize: false,\n showSeries: true,\n }\n default: // bar, line, area\n return {\n xAxis: 'X-Axis (dimension)',\n xAxisPlaceholder: 'Drop a dimension',\n yAxis: 'Y-Axis (measure)',\n yAxisPlaceholder: 'Drop a measure',\n series: 'Color / Series (optional)',\n seriesPlaceholder: 'Group by dimension',\n showSize: false,\n showSeries: true,\n }\n }\n})\n\n// Check if scatter/bubble needs numeric fields\nconst isScatterType = computed(() => ['scatter', 'bubble'].includes(chartConfig.value.type))\nconst isHeatmapType = computed(() => chartConfig.value.type === 'heatmap')\n\n// Drag handlers\nfunction handleDragStart(field: ChartFieldInfo, event: DragEvent) {\n draggingField.value = field\n event.dataTransfer?.setData('text/plain', field.field)\n}\n\nfunction handleDragEnd() {\n draggingField.value = null\n dragOverZone.value = null\n}\n\nfunction handleDragOver(zone: string, event: DragEvent) {\n event.preventDefault()\n dragOverZone.value = zone\n}\n\nfunction handleDragLeave() {\n dragOverZone.value = null\n}\n\nfunction handleDrop(zone: string, event: DragEvent) {\n event.preventDefault()\n dragOverZone.value = null\n\n if (!draggingField.value)\n return\n\n const field = draggingField.value\n const chartField = {\n field: field.field,\n label: field.label,\n role: field.role,\n aggregation: field.role === 'measure' ? 'sum' as ChartAggregation : undefined,\n }\n\n switch (zone) {\n case 'xAxis':\n chartConfig.value = { ...chartConfig.value, xAxis: chartField }\n break\n case 'yAxis':\n chartConfig.value = { ...chartConfig.value, yAxis: chartField }\n break\n case 'series':\n chartConfig.value = { ...chartConfig.value, seriesField: chartField }\n break\n case 'size':\n chartConfig.value = { ...chartConfig.value, sizeField: chartField }\n break\n case 'color':\n chartConfig.value = { ...chartConfig.value, colorField: chartField }\n break\n }\n\n emit('configChange', chartConfig.value)\n}\n\nfunction removeField(zone: string) {\n switch (zone) {\n case 'xAxis':\n chartConfig.value = { ...chartConfig.value, xAxis: undefined }\n break\n case 'yAxis':\n chartConfig.value = { ...chartConfig.value, yAxis: undefined }\n break\n case 'series':\n chartConfig.value = { ...chartConfig.value, seriesField: undefined }\n break\n case 'size':\n chartConfig.value = { ...chartConfig.value, sizeField: undefined }\n break\n case 'color':\n chartConfig.value = { ...chartConfig.value, colorField: undefined }\n break\n }\n emit('configChange', chartConfig.value)\n}\n\nfunction selectChartType(type: ChartType) {\n chartConfig.value = { ...chartConfig.value, type }\n showChartTypeSelector.value = false\n emit('configChange', chartConfig.value)\n}\n\nfunction updateAggregation(zone: string, aggregation: ChartAggregation) {\n const field = zone === 'yAxis' ? chartConfig.value.yAxis : chartConfig.value.sizeField\n if (!field)\n return\n\n const updated = { ...field, aggregation }\n if (zone === 'yAxis') {\n chartConfig.value = { ...chartConfig.value, yAxis: updated }\n }\n else if (zone === 'size') {\n chartConfig.value = { ...chartConfig.value, sizeField: updated }\n }\n emit('configChange', chartConfig.value)\n}\n\n// Chart rendering\nconst chartOptions = computed<ApexOptions>(() => {\n const isDark = props.theme === 'dark'\n const config = chartConfig.value\n const options = config.options || {}\n\n const baseOptions: ApexOptions = {\n chart: {\n type: getApexChartType(config.type),\n background: 'transparent',\n foreColor: isDark ? '#e2e8f0' : '#334155',\n toolbar: {\n show: true,\n tools: {\n download: true,\n selection: false,\n zoom: options.enableZoom ?? false,\n zoomin: options.enableZoom ?? false,\n zoomout: options.enableZoom ?? false,\n pan: false,\n reset: options.enableZoom ?? false,\n },\n export: {\n csv: { filename: 'chart-data' },\n svg: { filename: 'chart' },\n png: { filename: 'chart' },\n },\n },\n animations: {\n enabled: options.animated ?? true,\n speed: 400,\n dynamicAnimation: { enabled: true, speed: 300 },\n },\n fontFamily: 'system-ui, -apple-system, sans-serif',\n },\n colors: options.colors || CHART_COLORS,\n theme: {\n mode: isDark ? 'dark' : 'light',\n },\n grid: {\n show: options.showGrid ?? true,\n borderColor: isDark ? '#334155' : '#e2e8f0',\n },\n legend: {\n show: options.showLegend ?? true,\n position: options.legendPosition || 'top',\n },\n dataLabels: {\n enabled: options.showDataLabels ?? false,\n },\n tooltip: {\n theme: isDark ? 'dark' : 'light',\n style: {\n fontSize: '12px',\n },\n // Override light mode tooltip text color for better contrast\n cssClass: isDark ? '' : 'apexcharts-tooltip-light',\n },\n stroke: {\n curve: 'smooth',\n width: config.type === 'line' ? 3 : config.type === 'area' ? 2 : 0,\n },\n fill: {\n opacity: config.type === 'area' ? 0.4 : 1,\n },\n }\n\n // Add axis titles\n if (config.xAxis) {\n baseOptions.xaxis = {\n ...baseOptions.xaxis,\n title: { text: options.xAxisTitle || config.xAxis.label },\n labels: {\n style: { colors: isDark ? '#94a3b8' : '#64748b' },\n },\n }\n }\n\n if (config.yAxis && !['pie', 'donut', 'radar'].includes(config.type)) {\n baseOptions.yaxis = {\n title: { text: options.yAxisTitle || config.yAxis.label },\n labels: {\n style: { colors: isDark ? '#94a3b8' : '#64748b' },\n formatter: (val: number) => formatValue(val, options.valueFormat, options.decimals),\n },\n }\n }\n\n // Chart title\n if (options.title) {\n baseOptions.title = {\n text: options.title,\n style: {\n fontSize: '16px',\n fontWeight: 600,\n color: isDark ? '#e2e8f0' : '#334155',\n },\n }\n }\n\n // Stacking — forced on for stackedBar, optional for bar/area\n if (config.type === 'stackedBar' || (options.stacked && ['bar', 'area'].includes(config.type))) {\n baseOptions.chart!.stacked = true\n }\n\n // Pie/Donut specific\n if (config.type === 'pie' || config.type === 'donut') {\n baseOptions.plotOptions = {\n pie: {\n donut: {\n size: config.type === 'donut' ? '55%' : '0%',\n labels: {\n show: config.type === 'donut',\n total: {\n show: true,\n label: 'Total',\n formatter: (w) => {\n const total = w.globals.seriesTotals.reduce((a: number, b: number) => a + b, 0)\n return formatValue(total, options.valueFormat, options.decimals)\n },\n },\n },\n },\n },\n }\n }\n\n // Radar specific\n if (config.type === 'radar') {\n baseOptions.plotOptions = {\n radar: {\n polygons: {\n strokeColors: isDark ? '#334155' : '#e2e8f0',\n fill: { colors: isDark ? ['#1e293b', '#0f172a'] : ['#f8fafc', '#f1f5f9'] },\n },\n },\n }\n }\n\n return baseOptions\n})\n\nconst chartSeries = computed(() => {\n const config = chartConfig.value\n\n if (!chartIsValid.value)\n return []\n\n // Process based on chart type\n if (config.type === 'pie' || config.type === 'donut') {\n const data = processChartDataForPie(props.data, config)\n return data.series[0]?.data || []\n }\n\n if (config.type === 'scatter' || config.type === 'bubble') {\n const scatterData = processChartDataForScatter(props.data, config)\n return scatterData.series\n }\n\n if (config.type === 'heatmap') {\n const heatmapData = processChartDataForHeatmap(props.data, config)\n return heatmapData.series\n }\n\n // Standard charts (bar, line, area, etc.)\n const data = processChartData(props.data, config)\n return data.series\n})\n\nconst chartLabels = computed(() => {\n const config = chartConfig.value\n\n if (!chartIsValid.value)\n return []\n\n if (config.type === 'pie' || config.type === 'donut') {\n const data = processChartDataForPie(props.data, config)\n return data.categories\n }\n\n const data = processChartData(props.data, config)\n return data.categories\n})\n\n// Update xaxis categories in options\nconst chartOptionsWithCategories = computed<ApexOptions>(() => {\n const options = { ...chartOptions.value }\n const config = chartConfig.value\n\n // Heatmap, scatter, bubble have x values in data itself\n if (!['pie', 'donut', 'scatter', 'bubble', 'heatmap'].includes(config.type)) {\n options.xaxis = {\n ...options.xaxis,\n categories: chartLabels.value,\n }\n }\n\n if (config.type === 'pie' || config.type === 'donut') {\n options.labels = chartLabels.value\n }\n\n // Heatmap specific options\n if (config.type === 'heatmap') {\n options.chart = {\n ...options.chart,\n type: 'heatmap',\n }\n options.xaxis = {\n ...options.xaxis,\n type: 'category',\n }\n options.dataLabels = {\n enabled: true,\n style: {\n colors: ['#fff'],\n fontSize: '10px',\n },\n formatter: (val: unknown) => {\n if (val === null || val === undefined)\n return ''\n if (typeof val !== 'number')\n return String(val)\n if (val >= 1000000)\n return `${(val / 1000000).toFixed(1)}M`\n if (val >= 1000)\n return `${(val / 1000).toFixed(0)}K`\n return Math.round(val).toLocaleString()\n },\n }\n options.plotOptions = {\n heatmap: {\n shadeIntensity: 0.5,\n radius: 2,\n enableShades: true,\n colorScale: {\n inverse: false,\n },\n },\n }\n // Use a single color that varies by intensity\n options.colors = ['#6366f1']\n // Disable legend for heatmap (color scale is self-explanatory)\n options.legend = { show: false }\n }\n\n return options\n})\n\ntype ApexChartType = 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter' | 'heatmap' | 'bubble'\n\nfunction getApexChartType(type: ChartType): ApexChartType {\n const mapping: Record<ChartType, ApexChartType> = {\n bar: 'bar',\n stackedBar: 'bar',\n line: 'line',\n area: 'area',\n pie: 'pie',\n donut: 'donut',\n radar: 'radar',\n scatter: 'scatter',\n bubble: 'bubble',\n heatmap: 'heatmap',\n }\n return mapping[type] || 'bar'\n}\n\nfunction formatValue(val: unknown, format?: string, decimals?: number): string {\n // Handle non-number values (ApexCharts sometimes passes strings or undefined)\n if (val === null || val === undefined)\n return ''\n if (typeof val !== 'number')\n return String(val)\n if (Number.isNaN(val))\n return ''\n\n const dec = decimals ?? 0\n if (format === 'percent') {\n return `${val.toFixed(dec)}%`\n }\n if (format === 'currency') {\n return `$${val.toLocaleString(undefined, { minimumFractionDigits: dec, maximumFractionDigits: dec })}`\n }\n if (Math.abs(val) >= 1000) {\n return val.toLocaleString(undefined, { maximumFractionDigits: dec })\n }\n return val.toFixed(dec)\n}\n\n// Icons for chart types (inline SVG paths)\nfunction getChartIcon(type: ChartType): string {\n const icons: Record<ChartType, string> = {\n bar: 'M3 3v18h18V3H3zm4 14H5v-6h2v6zm4 0H9V7h2v10zm4 0h-2V9h2v8zm4 0h-2v-4h2v4z',\n stackedBar: 'M3 3v18h18V3H3zm4 14H5v-3h2v3zm0-4H5v-3h2v3zm4 4H9v-5h2v5zm0-6H9v-4h2v4zm4 6h-2v-3h2v3zm0-4h-2v-5h2v5zm4 4h-2v-2h2v2zm0-3h-2v-2h2v2z',\n line: 'M3.5 18.5l6-6 4 4 8-8M14.5 8.5h6v6',\n area: 'M3 17l6-6 4 4 8-8v10H3z',\n pie: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8v8l5.66 5.66C14.28 19.04 13.18 20 12 20z',\n donut: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 14c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z',\n scatter: 'M7 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5-6a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm-3 4a2 2 0 1 0 0-4 2 2 0 0 0 0 4z',\n bubble: 'M7 14a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm5-5a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm5 7a4 4 0 1 0 0-8 4 4 0 0 0 0 8z',\n heatmap: 'M3 3h4v4H3V3zm6 0h4v4H9V3zm6 0h4v4h-4V3zM3 9h4v4H3V9zm6 0h4v4H9V9zm6 0h4v4h-4V9zM3 15h4v4H3v-4zm6 0h4v4H9v-4zm6 0h4v4h-4v-4z',\n radar: 'M12 2L4 6v6c0 5.55 3.84 10.74 8 12 4.16-1.26 8-6.45 8-12V6l-8-4zm0 3.18l6 3v5.09c0 4.08-2.76 7.91-6 9.14V5.18z',\n }\n return icons[type] || icons.bar\n}\n\n// Watch for data changes\nwatch(() => props.data, () => {\n // Fields might have changed, could reset config if needed\n}, { deep: true })\n\n// Emit initial config\nonMounted(() => {\n emit('configChange', chartConfig.value)\n})\n</script>\n\n<template>\n <div class=\"vpg-chart-builder\">\n <!-- Chart Type Selector -->\n <div class=\"vpg-chart-type-bar\">\n <button\n v-for=\"ct in CHART_TYPES\"\n :key=\"ct.type\"\n class=\"vpg-chart-type-btn\"\n :class=\"{ active: chartConfig.type === ct.type }\"\n :title=\"ct.description\"\n @click=\"selectChartType(ct.type)\"\n >\n <svg class=\"vpg-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path :d=\"getChartIcon(ct.type)\" />\n </svg>\n <span class=\"vpg-chart-type-label\">{{ ct.label.replace(' Chart', '') }}</span>\n </button>\n </div>\n\n <div class=\"vpg-chart-builder-content\">\n <!-- Field Lists -->\n <div class=\"vpg-chart-fields-panel\">\n <div class=\"vpg-chart-fields-section\">\n <h4 class=\"vpg-chart-fields-title\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M4 6h16M4 12h10M4 18h6\" />\n </svg>\n Dimensions\n <span class=\"vpg-chart-fields-hint\">(text/date)</span>\n </h4>\n <div class=\"vpg-chart-fields-list\">\n <div\n v-for=\"field in dimensions\"\n :key=\"field.field\"\n class=\"vpg-chart-field-chip vpg-field-dimension\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-name\">{{ field.label }}</span>\n <span class=\"vpg-field-type\">{{ field.role === 'temporal' ? 'date' : 'text' }}</span>\n </div>\n <div v-if=\"dimensions.length === 0\" class=\"vpg-chart-fields-empty\">\n No dimension fields detected\n </div>\n </div>\n </div>\n\n <div class=\"vpg-chart-fields-section\">\n <h4 class=\"vpg-chart-fields-title\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M16 8v8M12 11v5M8 14v2M4 4v16h16\" />\n </svg>\n Measures\n <span class=\"vpg-chart-fields-hint\">(numbers)</span>\n </h4>\n <div class=\"vpg-chart-fields-list\">\n <div\n v-for=\"field in measures\"\n :key=\"field.field\"\n class=\"vpg-chart-field-chip vpg-field-measure\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-name\">{{ field.label }}</span>\n <span class=\"vpg-field-type\">#</span>\n </div>\n <div v-if=\"measures.length === 0\" class=\"vpg-chart-fields-empty\">\n No numeric fields detected\n </div>\n </div>\n </div>\n </div>\n\n <!-- Drop Zones -->\n <div class=\"vpg-chart-config-panel\">\n <!-- X-Axis -->\n <div class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.xAxis }}</label>\n <div\n class=\"vpg-chart-drop-zone\"\n :class=\"{ 'drag-over': dragOverZone === 'xAxis', 'has-field': chartConfig.xAxis }\"\n @dragover=\"handleDragOver('xAxis', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('xAxis', $event)\"\n >\n <template v-if=\"chartConfig.xAxis\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.xAxis.label }}</span>\n <select\n v-if=\"isScatterType && chartConfig.xAxis.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.xAxis.aggregation || 'sum'\"\n @change=\"updateAggregation('xAxis', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('xAxis')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.xAxisPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Y-Axis -->\n <div class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.yAxis }}</label>\n <div\n class=\"vpg-chart-drop-zone\"\n :class=\"{ 'drag-over': dragOverZone === 'yAxis', 'has-field': chartConfig.yAxis }\"\n @dragover=\"handleDragOver('yAxis', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('yAxis', $event)\"\n >\n <template v-if=\"chartConfig.yAxis\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.yAxis.label }}</span>\n <select\n v-if=\"chartConfig.yAxis.role === 'measure' && !isHeatmapType\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.yAxis.aggregation || 'sum'\"\n @change=\"updateAggregation('yAxis', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('yAxis')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.yAxisPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Series / Color (conditional) -->\n <div v-if=\"zoneLabels.showSeries\" class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">{{ zoneLabels.series }}</label>\n <div\n class=\"vpg-chart-drop-zone vpg-zone-optional\"\n :class=\"{ 'drag-over': dragOverZone === 'series', 'has-field': chartConfig.seriesField || (isHeatmapType && chartConfig.colorField) }\"\n @dragover=\"handleDragOver(isHeatmapType ? 'color' : 'series', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop(isHeatmapType ? 'color' : 'series', $event)\"\n >\n <template v-if=\"isHeatmapType ? chartConfig.colorField : chartConfig.seriesField\">\n <span class=\"vpg-zone-field-name\">{{ isHeatmapType ? chartConfig.colorField?.label : chartConfig.seriesField?.label }}</span>\n <select\n v-if=\"isHeatmapType && chartConfig.colorField?.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.colorField?.aggregation || 'sum'\"\n @change=\"updateAggregation('color', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField(isHeatmapType ? 'color' : 'series')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">{{ zoneLabels.seriesPlaceholder }}</span>\n </template>\n </div>\n </div>\n\n <!-- Size (for bubble charts) -->\n <div v-if=\"zoneLabels.showSize\" class=\"vpg-chart-drop-zone-wrapper\">\n <label class=\"vpg-chart-zone-label\">Size (number)</label>\n <div\n class=\"vpg-chart-drop-zone vpg-zone-optional\"\n :class=\"{ 'drag-over': dragOverZone === 'size', 'has-field': chartConfig.sizeField }\"\n @dragover=\"handleDragOver('size', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('size', $event)\"\n >\n <template v-if=\"chartConfig.sizeField\">\n <span class=\"vpg-zone-field-name\">{{ chartConfig.sizeField.label }}</span>\n <select\n v-if=\"chartConfig.sizeField.role === 'measure'\"\n class=\"vpg-zone-aggregation\"\n :value=\"chartConfig.sizeField.aggregation || 'sum'\"\n @change=\"updateAggregation('size', ($event.target as HTMLSelectElement).value as ChartAggregation)\"\n >\n <option v-for=\"agg in CHART_AGGREGATIONS\" :key=\"agg.value\" :value=\"agg.value\">\n {{ agg.symbol }}\n </option>\n </select>\n <button class=\"vpg-zone-remove-btn\" @click=\"removeField('size')\">\n <svg class=\"vpg-icon-xs\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-zone-placeholder\">Drop a number for bubble size</span>\n </template>\n </div>\n </div>\n\n <!-- Guidance -->\n <div class=\"vpg-chart-guidance\">\n <svg class=\"vpg-icon-sm\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 16v-4M12 8h.01\" />\n </svg>\n <span>{{ guidance }}</span>\n </div>\n </div>\n\n <!-- Chart Preview -->\n <div class=\"vpg-chart-preview-panel\">\n <div v-if=\"chartIsValid\" class=\"vpg-chart-container\">\n <Suspense>\n <VueApexCharts\n :key=\"`${chartConfig.type}-${JSON.stringify(chartConfig.xAxis)}-${JSON.stringify(chartConfig.yAxis)}`\"\n :type=\"getApexChartType(chartConfig.type)\"\n :options=\"chartOptionsWithCategories\"\n :series=\"chartSeries\"\n height=\"100%\"\n />\n <template #fallback>\n <div class=\"vpg-chart-loading\">\n <div class=\"vpg-chart-spinner\" />\n <span>Loading chart...</span>\n </div>\n </template>\n </Suspense>\n </div>\n <div v-else class=\"vpg-chart-empty-state\">\n <svg class=\"vpg-icon-lg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\">\n <path :d=\"getChartIcon(chartConfig.type)\" />\n </svg>\n <h3>Build your chart</h3>\n <p>Drag fields from the left panel to configure your visualization</p>\n <div class=\"vpg-chart-hint\">\n <strong>{{ selectedChartType?.label }}</strong>: {{ selectedChartType?.description }}\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { DateFormat, DateRange } from '@smallwebco/tinypivot-core'\nimport { formatDate, getDatePlaceholder, parseDateInput } from '@smallwebco/tinypivot-core'\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n dataMin: string // ISO date string\n dataMax: string // ISO date string\n currentRange: DateRange | null\n dateFormat?: DateFormat\n}>()\n\nconst emit = defineEmits<{\n change: [range: DateRange | null]\n}>()\n\nconst format = computed(() => props.dateFormat ?? 'iso')\n\n// Local state\nconst localMinText = ref('')\nconst localMaxText = ref('')\nconst minError = ref(false)\nconst maxError = ref(false)\n\n// Initialize from props\nfunction initFromRange(range: DateRange | null) {\n if (range?.min) {\n localMinText.value = formatDate(range.min, format.value)\n }\n else {\n localMinText.value = ''\n }\n if (range?.max) {\n localMaxText.value = formatDate(range.max, format.value)\n }\n else {\n localMaxText.value = ''\n }\n minError.value = false\n maxError.value = false\n}\n\n// Display formatted data bounds\nconst formattedMin = computed(() => formatDate(props.dataMin, format.value))\nconst formattedMax = computed(() => formatDate(props.dataMax, format.value))\n\nconst isFilterActive = computed(() => localMinText.value !== '' || localMaxText.value !== '')\n\nfunction handleMinInput() {\n if (localMinText.value === '') {\n minError.value = false\n emitChange()\n return\n }\n const parsed = parseDateInput(localMinText.value, format.value)\n minError.value = parsed === null\n if (!minError.value)\n emitChange()\n}\n\nfunction handleMaxInput() {\n if (localMaxText.value === '') {\n maxError.value = false\n emitChange()\n return\n }\n const parsed = parseDateInput(localMaxText.value, format.value)\n maxError.value = parsed === null\n if (!maxError.value)\n emitChange()\n}\n\nfunction emitChange() {\n const min = localMinText.value ? parseDateInput(localMinText.value, format.value) : null\n const max = localMaxText.value ? parseDateInput(localMaxText.value, format.value) : null\n if (min === null && max === null) {\n emit('change', null)\n }\n else {\n emit('change', { min, max })\n }\n}\n\nfunction clearFilter() {\n localMinText.value = ''\n localMaxText.value = ''\n minError.value = false\n maxError.value = false\n emit('change', null)\n}\n\nfunction setFullRange() {\n localMinText.value = formatDate(props.dataMin, format.value)\n localMaxText.value = formatDate(props.dataMax, format.value)\n minError.value = false\n maxError.value = false\n emit('change', { min: props.dataMin, max: props.dataMax })\n}\n\nwatch(() => props.currentRange, (newRange) => {\n initFromRange(newRange)\n}, { immediate: true })\n</script>\n\n<template>\n <div class=\"vpg-range-filter\">\n <!-- Data range info -->\n <div class=\"vpg-range-info\">\n <span class=\"vpg-range-label\">Data range:</span>\n <span class=\"vpg-range-bounds\">{{ formattedMin }} – {{ formattedMax }}</span>\n </div>\n\n <!-- Input fields -->\n <div class=\"vpg-range-inputs\">\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">From</label>\n <input\n v-model=\"localMinText\"\n type=\"text\"\n class=\"vpg-range-input\"\n :class=\"{ 'vpg-input-error': minError }\"\n :placeholder=\"getDatePlaceholder(format)\"\n @blur=\"handleMinInput\"\n @keyup.enter=\"handleMinInput\"\n >\n </div>\n <span class=\"vpg-input-separator\">to</span>\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">To</label>\n <input\n v-model=\"localMaxText\"\n type=\"text\"\n class=\"vpg-range-input\"\n :class=\"{ 'vpg-input-error': maxError }\"\n :placeholder=\"getDatePlaceholder(format)\"\n @blur=\"handleMaxInput\"\n @keyup.enter=\"handleMaxInput\"\n >\n </div>\n </div>\n\n <!-- Quick actions -->\n <div class=\"vpg-range-actions\">\n <button\n class=\"vpg-range-btn\"\n :disabled=\"!isFilterActive\"\n @click=\"clearFilter\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear\n </button>\n <button class=\"vpg-range-btn\" @click=\"setFullRange\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n Full Range\n </button>\n </div>\n\n <!-- Filter summary -->\n <div v-if=\"isFilterActive && !minError && !maxError\" class=\"vpg-filter-summary\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span>\n Showing dates\n <strong v-if=\"localMinText\">from {{ localMinText }}</strong>\n {{ localMinText && localMaxText ? ' ' : '' }}\n <strong v-if=\"localMaxText\">to {{ localMaxText }}</strong>\n </span>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-range-filter { padding: 0.5rem; }\n.vpg-range-info { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; font-size: 0.6875rem; }\n.vpg-range-label { color: #64748b; }\n.vpg-range-bounds { font-weight: 500; color: #334155; background: #f1f5f9; padding: 0.125rem 0.375rem; border-radius: 0.25rem; }\n.vpg-range-inputs { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }\n.vpg-input-group { flex: 1; }\n.vpg-input-label { display: block; font-size: 0.625rem; font-weight: 500; color: #64748b; margin-bottom: 0.125rem; text-transform: uppercase; letter-spacing: 0.025em; }\n.vpg-range-input { width: 100%; padding: 0.375rem 0.5rem; font-size: 0.75rem; border: 1px solid #cbd5e1; border-radius: 0.25rem; outline: none; transition: border-color 0.15s, box-shadow 0.15s; }\n.vpg-range-input:focus { border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15); }\n.vpg-range-input::placeholder { color: #94a3b8; }\n.vpg-range-input.vpg-input-error { border-color: #ef4444; }\n.vpg-range-input.vpg-input-error:focus { box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.15); }\n.vpg-input-separator { color: #94a3b8; font-size: 0.6875rem; padding-top: 1rem; }\n.vpg-range-actions { display: flex; gap: 0.375rem; margin-bottom: 0.5rem; }\n.vpg-range-btn { display: flex; align-items: center; gap: 0.25rem; padding: 0.25rem 0.5rem; font-size: 0.6875rem; font-weight: 500; color: #475569; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 0.25rem; cursor: pointer; transition: all 0.15s; }\n.vpg-range-btn:hover:not(:disabled) { background: #f1f5f9; border-color: #cbd5e1; color: #334155; }\n.vpg-range-btn:disabled { opacity: 0.5; cursor: not-allowed; }\n.vpg-icon-xs { width: 0.75rem; height: 0.75rem; }\n.vpg-filter-summary { display: flex; align-items: center; gap: 0.375rem; padding: 0.375rem 0.5rem; background: #eef2ff; border-radius: 0.25rem; font-size: 0.6875rem; color: #4338ca; }\n.vpg-filter-summary strong { font-weight: 600; }\n</style>\n","<script setup lang=\"ts\">\nimport type { NumberFormat, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Numeric Range Filter Component\n * Provides an intuitive dual-handle slider and input fields for filtering numeric data\n */\nimport { formatNumber } from '@smallwebco/tinypivot-core'\nimport { computed, ref, watch } from 'vue'\n\nconst props = defineProps<{\n dataMin: number\n dataMax: number\n currentRange: NumericRange | null\n numberFormat?: NumberFormat\n}>()\n\nconst emit = defineEmits<{\n change: [range: NumericRange | null]\n}>()\n\n// Local state for the range values\nconst localMin = ref<number | null>(props.currentRange?.min ?? null)\nconst localMax = ref<number | null>(props.currentRange?.max ?? null)\n\n// Calculate step based on data range\nconst step = computed(() => {\n const range = props.dataMax - props.dataMin\n if (range === 0)\n return 1\n if (range <= 1)\n return 0.01\n if (range <= 10)\n return 0.1\n if (range <= 100)\n return 1\n if (range <= 1000)\n return 10\n return 10 ** (Math.floor(Math.log10(range)) - 2)\n})\n\n// Format numbers for display\nfunction formatValue(val: number | null): string {\n if (val === null)\n return ''\n return formatNumber(val, props.numberFormat ?? 'us')\n}\n\n// Check if filter is active\nconst isFilterActive = computed(() => {\n return localMin.value !== null || localMax.value !== null\n})\n\n// Calculate slider percentages for visual representation\nconst minPercent = computed(() => {\n if (localMin.value === null || props.dataMax === props.dataMin)\n return 0\n return ((localMin.value - props.dataMin) / (props.dataMax - props.dataMin)) * 100\n})\n\nconst maxPercent = computed(() => {\n if (localMax.value === null || props.dataMax === props.dataMin)\n return 100\n return ((localMax.value - props.dataMin) / (props.dataMax - props.dataMin)) * 100\n})\n\n// Handle min slider change\nfunction handleMinSlider(event: Event) {\n const target = event.target as HTMLInputElement\n const value = Number.parseFloat(target.value)\n\n // Ensure min doesn't exceed max\n if (localMax.value !== null && value > localMax.value) {\n localMin.value = localMax.value\n }\n else {\n localMin.value = value\n }\n}\n\n// Handle max slider change\nfunction handleMaxSlider(event: Event) {\n const target = event.target as HTMLInputElement\n const value = Number.parseFloat(target.value)\n\n // Ensure max doesn't go below min\n if (localMin.value !== null && value < localMin.value) {\n localMax.value = localMin.value\n }\n else {\n localMax.value = value\n }\n}\n\n// Handle min input change\nfunction handleMinInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? null : Number.parseFloat(target.value)\n\n if (value !== null && !Number.isNaN(value)) {\n // Clamp to data bounds\n localMin.value = Math.max(props.dataMin, Math.min(value, localMax.value ?? props.dataMax))\n }\n else if (value === null) {\n localMin.value = null\n }\n}\n\n// Handle max input change\nfunction handleMaxInput(event: Event) {\n const target = event.target as HTMLInputElement\n const value = target.value === '' ? null : Number.parseFloat(target.value)\n\n if (value !== null && !Number.isNaN(value)) {\n // Clamp to data bounds\n localMax.value = Math.min(props.dataMax, Math.max(value, localMin.value ?? props.dataMin))\n }\n else if (value === null) {\n localMax.value = null\n }\n}\n\n// Clear the filter\nfunction clearFilter() {\n localMin.value = null\n localMax.value = null\n emitChange()\n}\n\n// Set to full range\nfunction setFullRange() {\n localMin.value = props.dataMin\n localMax.value = props.dataMax\n emitChange()\n}\n\n// Emit change\nfunction emitChange() {\n if (localMin.value === null && localMax.value === null) {\n emit('change', null)\n }\n else {\n emit('change', { min: localMin.value, max: localMax.value })\n }\n}\n\n// Sync with props\nwatch(() => props.currentRange, (newRange) => {\n localMin.value = newRange?.min ?? null\n localMax.value = newRange?.max ?? null\n}, { immediate: true })\n</script>\n\n<template>\n <div class=\"vpg-range-filter\">\n <!-- Data range info -->\n <div class=\"vpg-range-info\">\n <span class=\"vpg-range-label\">Data range:</span>\n <span class=\"vpg-range-bounds\">{{ formatValue(dataMin) }} – {{ formatValue(dataMax) }}</span>\n </div>\n\n <!-- Dual slider track -->\n <div class=\"vpg-slider-container\">\n <div class=\"vpg-slider-track\">\n <div\n class=\"vpg-slider-fill\"\n :style=\"{\n left: `${minPercent}%`,\n right: `${100 - maxPercent}%`,\n }\"\n />\n </div>\n\n <!-- Min slider (lower handle) -->\n <input\n type=\"range\"\n class=\"vpg-slider vpg-slider-min\"\n :min=\"dataMin\"\n :max=\"dataMax\"\n :step=\"step\"\n :value=\"localMin ?? dataMin\"\n @input=\"handleMinSlider\"\n @change=\"emitChange\"\n >\n\n <!-- Max slider (upper handle) -->\n <input\n type=\"range\"\n class=\"vpg-slider vpg-slider-max\"\n :min=\"dataMin\"\n :max=\"dataMax\"\n :step=\"step\"\n :value=\"localMax ?? dataMax\"\n @input=\"handleMaxSlider\"\n @change=\"emitChange\"\n >\n </div>\n\n <!-- Input fields for precise entry -->\n <div class=\"vpg-range-inputs\">\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">Min</label>\n <input\n type=\"number\"\n class=\"vpg-range-input\"\n :placeholder=\"formatValue(dataMin)\"\n :value=\"localMin ?? ''\"\n :step=\"step\"\n @input=\"handleMinInput\"\n @change=\"emitChange\"\n >\n </div>\n <span class=\"vpg-input-separator\">to</span>\n <div class=\"vpg-input-group\">\n <label class=\"vpg-input-label\">Max</label>\n <input\n type=\"number\"\n class=\"vpg-range-input\"\n :placeholder=\"formatValue(dataMax)\"\n :value=\"localMax ?? ''\"\n :step=\"step\"\n @input=\"handleMaxInput\"\n @change=\"emitChange\"\n >\n </div>\n </div>\n\n <!-- Quick actions -->\n <div class=\"vpg-range-actions\">\n <button\n class=\"vpg-range-btn\"\n :disabled=\"!isFilterActive\"\n @click=\"clearFilter\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear\n </button>\n <button class=\"vpg-range-btn\" @click=\"setFullRange\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4\" />\n </svg>\n Full Range\n </button>\n </div>\n\n <!-- Current filter display -->\n <div v-if=\"isFilterActive\" class=\"vpg-filter-summary\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span>\n Showing values\n <strong>{{ localMin !== null ? `≥ ${formatValue(localMin)}` : '' }}</strong>\n {{ localMin !== null && localMax !== null ? ' and ' : '' }}\n <strong>{{ localMax !== null ? `≤ ${formatValue(localMax)}` : '' }}</strong>\n </span>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-range-filter {\n padding: 0.5rem;\n}\n\n.vpg-range-info {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0.75rem;\n font-size: 0.6875rem;\n}\n\n.vpg-range-label {\n color: #64748b;\n}\n\n.vpg-range-bounds {\n font-weight: 500;\n color: #334155;\n background: #f1f5f9;\n padding: 0.125rem 0.375rem;\n border-radius: 0.25rem;\n}\n\n/* Slider container with dual handles */\n.vpg-slider-container {\n position: relative;\n height: 24px;\n margin: 0.75rem 0;\n}\n\n.vpg-slider-track {\n position: absolute;\n top: 50%;\n left: 0;\n right: 0;\n height: 4px;\n background: #e2e8f0;\n border-radius: 2px;\n transform: translateY(-50%);\n}\n\n.vpg-slider-fill {\n position: absolute;\n top: 0;\n bottom: 0;\n background: linear-gradient(90deg, #6366f1, #8b5cf6);\n border-radius: 2px;\n transition: left 0.1s, right 0.1s;\n}\n\n.vpg-slider {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: transparent;\n pointer-events: none;\n -webkit-appearance: none;\n appearance: none;\n margin: 0;\n}\n\n.vpg-slider::-webkit-slider-thumb {\n -webkit-appearance: none;\n appearance: none;\n pointer-events: auto;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: white;\n border: 2px solid #6366f1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n}\n\n.vpg-slider::-webkit-slider-thumb:hover {\n transform: scale(1.15);\n box-shadow: 0 2px 6px rgba(99, 102, 241, 0.4);\n}\n\n.vpg-slider::-webkit-slider-thumb:active {\n transform: scale(1.1);\n box-shadow: 0 2px 8px rgba(99, 102, 241, 0.5);\n}\n\n.vpg-slider::-moz-range-thumb {\n pointer-events: auto;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: white;\n border: 2px solid #6366f1;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);\n cursor: pointer;\n transition: transform 0.15s, box-shadow 0.15s;\n}\n\n.vpg-slider::-moz-range-thumb:hover {\n transform: scale(1.15);\n}\n\n.vpg-slider-min {\n z-index: 1;\n}\n\n.vpg-slider-max {\n z-index: 2;\n}\n\n/* Input fields */\n.vpg-range-inputs {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n\n.vpg-input-group {\n flex: 1;\n}\n\n.vpg-input-label {\n display: block;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n margin-bottom: 0.125rem;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n.vpg-range-input {\n width: 100%;\n padding: 0.375rem 0.5rem;\n font-size: 0.75rem;\n border: 1px solid #cbd5e1;\n border-radius: 0.25rem;\n outline: none;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.vpg-range-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);\n}\n\n.vpg-range-input::placeholder {\n color: #94a3b8;\n}\n\n/* Hide number input spinners */\n.vpg-range-input::-webkit-outer-spin-button,\n.vpg-range-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n.vpg-range-input[type=\"number\"] {\n -moz-appearance: textfield;\n}\n\n.vpg-input-separator {\n color: #94a3b8;\n font-size: 0.6875rem;\n padding-top: 1rem;\n}\n\n/* Action buttons */\n.vpg-range-actions {\n display: flex;\n gap: 0.375rem;\n margin-bottom: 0.5rem;\n}\n\n.vpg-range-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #475569;\n background: #f8fafc;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-range-btn:hover:not(:disabled) {\n background: #f1f5f9;\n border-color: #cbd5e1;\n color: #334155;\n}\n\n.vpg-range-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n/* Filter summary */\n.vpg-filter-summary {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.5rem;\n background: #eef2ff;\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n color: #4338ca;\n}\n\n.vpg-filter-summary strong {\n font-weight: 600;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { ColumnStats, DateFormat, DateRange, NumberFormat, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Column Filter Dropdown Component\n * Shows unique values with checkboxes, search, and sort controls\n * For numeric columns, also provides a range filter option\n * For date columns, also provides a date range filter option\n */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport DateRangeFilter from './DateRangeFilter.vue'\nimport NumericRangeFilter from './NumericRangeFilter.vue'\n\ntype FilterMode = 'values' | 'range'\n\nconst props = defineProps<{\n columnId: string\n columnName: string\n stats: ColumnStats\n selectedValues: string[]\n sortDirection: 'asc' | 'desc' | null\n /** Current numeric range filter (if any) */\n numericRange?: NumericRange | null\n /** Current date range filter (if any) */\n dateRange?: DateRange | null\n /** Number display format */\n numberFormat?: NumberFormat\n /** Date display format */\n dateFormat?: DateFormat\n}>()\n\nconst emit = defineEmits<{\n filter: [values: string[]]\n sort: [direction: 'asc' | 'desc' | null]\n close: []\n /** Emitted when a numeric range filter is applied */\n rangeFilter: [range: NumericRange | null]\n /** Emitted when a date range filter is applied */\n dateRangeFilter: [range: DateRange | null]\n}>()\n\n// Local state\nconst searchQuery = ref('')\nconst dropdownRef = ref<HTMLDivElement>()\nconst searchInputRef = ref<HTMLInputElement>()\n\n// Filter mode (values vs range) - only available for numeric/date columns\nconst isNumericColumn = computed(() => props.stats.type === 'number'\n && props.stats.numericMin !== undefined\n && props.stats.numericMax !== undefined)\n\nconst isDateColumn = computed(() => props.stats.type === 'date'\n && props.stats.dateMin !== undefined\n && props.stats.dateMax !== undefined)\n\n// Determine initial mode based on existing filters\nconst filterMode = ref<FilterMode>(props.numericRange || props.dateRange ? 'range' : 'values')\n\n// Local range for the numeric filter\nconst localRange = ref<NumericRange | null>(props.numericRange ?? null)\n\n// Local range for the date filter\nconst localDateRange = ref<DateRange | null>(props.dateRange ?? null)\n\n// Initialize with selected values\nconst localSelected = ref<Set<string>>(new Set(props.selectedValues))\n\n// Include blank option if there are null values\nconst hasBlankValues = computed(() => props.stats.nullCount > 0)\n\n// Filtered unique values based on search\nconst filteredValues = computed(() => {\n const values = props.stats.uniqueValues\n if (!searchQuery.value)\n return values\n\n const query = searchQuery.value.toLowerCase()\n return values.filter(v => v.toLowerCase().includes(query))\n})\n\n// All values including blank\nconst allValues = computed(() => {\n const values = [...filteredValues.value]\n if (hasBlankValues.value && (!searchQuery.value || '(blank)'.includes(searchQuery.value.toLowerCase()))) {\n values.unshift('(blank)')\n }\n return values\n})\n\n// Sort label helpers\nconst ascLabel = computed(() => {\n if (isDateColumn.value)\n return 'Old\\u2192New'\n if (isNumericColumn.value)\n return '1\\u21929'\n return 'A\\u2192Z'\n})\n\nconst descLabel = computed(() => {\n if (isDateColumn.value)\n return 'New\\u2192Old'\n if (isNumericColumn.value)\n return '9\\u21921'\n return 'Z\\u2192A'\n})\n\nconst ascTitle = computed(() => {\n if (isDateColumn.value)\n return 'Sort Old to New'\n if (isNumericColumn.value)\n return 'Sort Low to High'\n return 'Sort A to Z'\n})\n\nconst descTitle = computed(() => {\n if (isDateColumn.value)\n return 'Sort New to Old'\n if (isNumericColumn.value)\n return 'Sort High to Low'\n return 'Sort Z to A'\n})\n\n// Toggle single value\nfunction toggleValue(value: string) {\n if (localSelected.value.has(value)) {\n localSelected.value.delete(value)\n }\n else {\n localSelected.value.add(value)\n }\n localSelected.value = new Set(localSelected.value)\n}\n\n// Select all visible\nfunction selectAll() {\n for (const value of allValues.value) {\n localSelected.value.add(value)\n }\n localSelected.value = new Set(localSelected.value)\n}\n\n// Clear all\nfunction clearAll() {\n localSelected.value.clear()\n localSelected.value = new Set(localSelected.value)\n}\n\n// Apply filter\nfunction applyFilter() {\n if (localSelected.value.size === 0) {\n emit('filter', [])\n }\n else {\n emit('filter', Array.from(localSelected.value))\n }\n emit('close')\n}\n\n// Sort handlers\nfunction sortAscending() {\n emit('sort', props.sortDirection === 'asc' ? null : 'asc')\n}\n\nfunction sortDescending() {\n emit('sort', props.sortDirection === 'desc' ? null : 'desc')\n}\n\n// Clear filter only\nfunction clearFilter() {\n localSelected.value.clear()\n localSelected.value = new Set(localSelected.value)\n emit('filter', [])\n emit('close')\n}\n\n// Handle range filter change from the NumericRangeFilter component\nfunction handleRangeChange(range: NumericRange | null) {\n localRange.value = range\n}\n\n// Apply the range filter\nfunction applyRangeFilter() {\n emit('rangeFilter', localRange.value)\n emit('close')\n}\n\n// Clear range filter\nfunction clearRangeFilter() {\n localRange.value = null\n emit('rangeFilter', null)\n emit('close')\n}\n\n// Handle date range filter change from the DateRangeFilter component\nfunction handleDateRangeChange(range: DateRange | null) {\n localDateRange.value = range\n}\n\n// Apply the date range filter\nfunction applyDateRangeFilter() {\n emit('dateRangeFilter', localDateRange.value)\n emit('close')\n}\n\n// Clear date range filter\nfunction clearDateRangeFilter() {\n localDateRange.value = null\n emit('dateRangeFilter', null)\n emit('close')\n}\n\n// Switch filter mode\nfunction setFilterMode(mode: FilterMode) {\n filterMode.value = mode\n}\n\n// Click outside handler\nfunction handleClickOutside(event: MouseEvent) {\n if (dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {\n emit('close')\n }\n}\n\n// Keyboard handling\nfunction handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n emit('close')\n }\n else if (event.key === 'Enter' && event.ctrlKey) {\n applyFilter()\n }\n}\n\n// Focus search on mount\nonMounted(() => {\n nextTick(() => {\n searchInputRef.value?.focus()\n })\n document.addEventListener('mousedown', handleClickOutside)\n document.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mousedown', handleClickOutside)\n document.removeEventListener('keydown', handleKeydown)\n})\n\n// Sync with props\nwatch(() => props.selectedValues, (newValues) => {\n localSelected.value = new Set(newValues)\n}, { immediate: true })\n\n// Sync numeric range with props\nwatch(() => props.numericRange, (newRange) => {\n localRange.value = newRange ?? null\n if (newRange) {\n filterMode.value = 'range'\n }\n}, { immediate: true })\n\n// Sync date range with props\nwatch(() => props.dateRange, (newRange) => {\n localDateRange.value = newRange ?? null\n if (newRange) {\n filterMode.value = 'range'\n }\n}, { immediate: true })\n</script>\n\n<template>\n <div ref=\"dropdownRef\" class=\"vpg-filter-dropdown\">\n <!-- Header -->\n <div class=\"vpg-filter-header\">\n <span class=\"vpg-filter-title\">{{ columnName }}</span>\n <span class=\"vpg-filter-count\">\n {{ stats.uniqueValues.length.toLocaleString() }} unique\n </span>\n </div>\n\n <!-- Sort Controls -->\n <div class=\"vpg-sort-controls\">\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'asc' }\"\n :title=\"ascTitle\"\n @click=\"sortAscending\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4h13M3 8h9m-9 4h6m4 0l4-4m0 0l4 4m-4-4v12\" />\n </svg>\n <span>{{ ascLabel }}</span>\n </button>\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'desc' }\"\n :title=\"descTitle\"\n @click=\"sortDescending\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4\" />\n </svg>\n <span>{{ descLabel }}</span>\n </button>\n </div>\n\n <div class=\"vpg-divider\" />\n\n <!-- Filter Mode Tabs (for numeric or date columns) -->\n <div v-if=\"isNumericColumn || isDateColumn\" class=\"vpg-filter-tabs\">\n <button\n class=\"vpg-tab-btn\"\n :class=\"{ active: filterMode === 'values' }\"\n @click=\"setFilterMode('values')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\" />\n </svg>\n Values\n </button>\n <button\n class=\"vpg-tab-btn\"\n :class=\"{ active: filterMode === 'range' }\"\n @click=\"setFilterMode('range')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01\" />\n </svg>\n Range\n </button>\n </div>\n\n <!-- Values Filter Mode -->\n <template v-if=\"(!isNumericColumn && !isDateColumn) || filterMode === 'values'\">\n <!-- Search -->\n <div class=\"vpg-search-container\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n ref=\"searchInputRef\"\n v-model=\"searchQuery\"\n type=\"text\"\n placeholder=\"Search values...\"\n class=\"vpg-search-input\"\n >\n <button v-if=\"searchQuery\" class=\"vpg-clear-search\" @click=\"searchQuery = ''\">\n ×\n </button>\n </div>\n\n <!-- Select All / Clear All -->\n <div class=\"vpg-bulk-actions\">\n <button class=\"vpg-bulk-btn\" @click=\"selectAll\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n Select All\n </button>\n <button class=\"vpg-bulk-btn\" @click=\"clearAll\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear All\n </button>\n </div>\n\n <!-- Values List -->\n <div class=\"vpg-values-list\">\n <label\n v-for=\"value in allValues\"\n :key=\"value\"\n class=\"vpg-value-item\"\n :class=\"{ selected: localSelected.has(value) }\"\n >\n <input\n type=\"checkbox\"\n :checked=\"localSelected.has(value)\"\n class=\"vpg-value-checkbox\"\n @change=\"toggleValue(value)\"\n >\n <span class=\"vpg-value-text\" :class=\"{ 'vpg-blank': value === '(blank)' }\">\n {{ value }}\n </span>\n </label>\n\n <div v-if=\"allValues.length === 0\" class=\"vpg-no-results\">\n No matching values\n </div>\n </div>\n\n <!-- Footer for Values Mode -->\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyFilter\">\n Apply\n </button>\n </div>\n </template>\n\n <!-- Numeric Range Filter Mode -->\n <template v-else-if=\"isNumericColumn && filterMode === 'range'\">\n <NumericRangeFilter\n :data-min=\"stats.numericMin!\"\n :data-max=\"stats.numericMax!\"\n :current-range=\"localRange\"\n :number-format=\"numberFormat\"\n @change=\"handleRangeChange\"\n />\n\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearRangeFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyRangeFilter\">\n Apply\n </button>\n </div>\n </template>\n\n <!-- Date Range Filter Mode -->\n <template v-else-if=\"isDateColumn && filterMode === 'range'\">\n <DateRangeFilter\n :data-min=\"stats.dateMin!\"\n :data-max=\"stats.dateMax!\"\n :current-range=\"localDateRange\"\n :date-format=\"dateFormat\"\n @change=\"handleDateRangeChange\"\n />\n\n <div class=\"vpg-filter-footer\">\n <button class=\"vpg-btn-clear\" @click=\"clearDateRangeFilter\">\n Clear Filter\n </button>\n <button class=\"vpg-btn-apply\" @click=\"applyDateRangeFilter\">\n Apply\n </button>\n </div>\n </template>\n </div>\n</template>\n\n<style scoped>\n.vpg-filter-dropdown {\n position: absolute;\n z-index: 50;\n background: white;\n border-radius: 0.375rem;\n box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n border: 1px solid #e2e8f0;\n min-width: 220px;\n max-width: 280px;\n top: 100%;\n left: 0;\n margin-top: 2px;\n max-height: calc(100vh - 100px);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-filter-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.625rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n border-radius: 0.375rem 0.375rem 0 0;\n}\n\n.vpg-filter-title {\n font-size: 0.75rem;\n font-weight: 600;\n color: #1e293b;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vpg-filter-count {\n font-size: 0.625rem;\n color: #64748b;\n}\n\n.vpg-sort-controls {\n display: flex;\n gap: 0.25rem;\n padding: 0.5rem;\n background: #f8fafc;\n}\n\n.vpg-sort-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n border-radius: 0.25rem;\n color: #475569;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-sort-btn:hover {\n background: #e2e8f0;\n}\n\n.vpg-sort-btn.active {\n background: #e0e7ff;\n color: #4338ca;\n}\n\n.vpg-icon-sm {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-divider {\n height: 1px;\n background: #e2e8f0;\n}\n\n/* Filter mode tabs */\n.vpg-filter-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.375rem 0.5rem;\n background: #f8fafc;\n}\n\n.vpg-tab-btn {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n padding: 0.375rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n color: #64748b;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-tab-btn:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-tab-btn.active {\n background: #4f46e5;\n color: white;\n border-color: #4f46e5;\n}\n\n.vpg-tab-btn.active:hover {\n background: #4338ca;\n}\n\n.vpg-search-container {\n position: relative;\n padding: 0.375rem 0.5rem;\n}\n\n.vpg-search-icon {\n position: absolute;\n left: 0.875rem;\n top: 50%;\n transform: translateY(-50%);\n width: 0.875rem;\n height: 0.875rem;\n color: #94a3b8;\n}\n\n.vpg-search-input {\n width: 100%;\n padding: 0.25rem 1.5rem 0.25rem 1.75rem;\n font-size: 0.75rem;\n border: 1px solid #cbd5e1;\n border-radius: 0.25rem;\n outline: none;\n}\n\n.vpg-search-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 1px #6366f1;\n}\n\n.vpg-clear-search {\n position: absolute;\n right: 0.875rem;\n top: 50%;\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n font-size: 0.875rem;\n line-height: 1;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.vpg-clear-search:hover {\n color: #475569;\n}\n\n.vpg-bulk-actions {\n display: flex;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n border-bottom: 1px solid #f1f5f9;\n}\n\n.vpg-bulk-btn {\n display: flex;\n align-items: center;\n gap: 0.125rem;\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-bulk-btn:hover {\n color: #4f46e5;\n background: #eef2ff;\n}\n\n.vpg-values-list {\n max-height: 200px;\n overflow-y: auto;\n padding: 0.125rem 0.25rem;\n flex: 1;\n min-height: 0;\n}\n\n.vpg-value-item {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.375rem;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: background 0.15s;\n}\n\n.vpg-value-item:hover {\n background: #f1f5f9;\n}\n\n.vpg-value-item.selected {\n background: #eef2ff;\n}\n\n.vpg-value-checkbox {\n width: 0.875rem;\n height: 0.875rem;\n accent-color: #4f46e5;\n border-radius: 0.25rem;\n}\n\n.vpg-value-text {\n font-size: 0.75rem;\n color: #334155;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.vpg-value-text.vpg-blank {\n font-style: italic;\n color: #94a3b8;\n}\n\n.vpg-no-results {\n text-align: center;\n padding: 0.75rem;\n font-size: 0.75rem;\n color: #94a3b8;\n}\n\n.vpg-filter-footer {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5rem 0.625rem;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n border-radius: 0 0 0.375rem 0.375rem;\n}\n\n.vpg-btn-clear {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #475569;\n background: transparent;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-btn-clear:hover {\n background: #e2e8f0;\n color: #1e293b;\n}\n\n.vpg-btn-apply {\n padding: 0.25rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: white;\n background: #4f46e5;\n border: none;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-btn-apply:hover {\n background: #4338ca;\n}\n</style>\n","import type { ColumnFilterValue, ColumnStats, DateRange, NumericRange } from '@smallwebco/tinypivot-core'\n/**\n * Excel-like Grid Composable for Vue\n * Provides Excel-like filtering, sorting, and data manipulation functionality\n */\nimport type { ColumnDef, ColumnFiltersState, FilterFn, SortingState, VisibilityState } from '@tanstack/vue-table'\nimport { formatCellValue, getColumnUniqueValues, isDateRange, isNumericRange } from '@smallwebco/tinypivot-core'\nimport {\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useVueTable,\n} from '@tanstack/vue-table'\nimport { computed, type Ref, ref, watch } from 'vue'\n\n// Re-export for convenience\nexport { formatCellValue, getColumnUniqueValues, isDateRange, isNumericRange }\n\nexport interface ExcelGridOptions<T> {\n data: Ref<T[]>\n columns?: string[]\n enableSorting?: boolean\n enableFiltering?: boolean\n pageSize?: number\n}\n\n/**\n * Combined filter function for Excel-style filtering, numeric range, and date range filtering\n */\n\nconst multiSelectFilter: FilterFn<any> = (row, columnId, filterValue: ColumnFilterValue | undefined) => {\n if (!filterValue)\n return true\n\n // Handle numeric range filter\n if (isNumericRange(filterValue)) {\n const cellValue = row.getValue(columnId)\n if (cellValue === null || cellValue === undefined || cellValue === '') {\n return false // Exclude null/empty values from numeric range filtering\n }\n const num = typeof cellValue === 'number' ? cellValue : Number.parseFloat(String(cellValue))\n if (Number.isNaN(num))\n return false\n\n const { min, max } = filterValue\n if (min !== null && num < min)\n return false\n if (max !== null && num > max)\n return false\n return true\n }\n\n // Handle date range filter\n if (isDateRange(filterValue)) {\n const cellValue = row.getValue(columnId)\n if (cellValue === null || cellValue === undefined || cellValue === '') {\n return false\n }\n const dateObj = cellValue instanceof Date ? cellValue : new Date(String(cellValue))\n if (Number.isNaN(dateObj.getTime()))\n return false\n const dateStr = dateObj.toISOString().split('T')[0]\n\n const { min, max } = filterValue\n if (min !== null && dateStr < min)\n return false\n if (max !== null && dateStr > max)\n return false\n return true\n }\n\n // Handle multi-select array filter\n if (Array.isArray(filterValue) && filterValue.length > 0) {\n const cellValue = row.getValue(columnId)\n const cellString = cellValue === null || cellValue === undefined || cellValue === ''\n ? '(blank)'\n : String(cellValue)\n return filterValue.includes(cellString)\n }\n\n return true\n}\n\n/**\n * Create Excel-like grid composable\n */\nexport function useExcelGrid<T extends Record<string, unknown>>(options: ExcelGridOptions<T>) {\n const { data, enableSorting = true, enableFiltering = true } = options\n\n // State\n const sorting = ref<SortingState>([])\n const columnFilters = ref<ColumnFiltersState>([])\n const columnVisibility = ref<VisibilityState>({})\n const globalFilter = ref('')\n\n // Column statistics cache\n const columnStatsCache = ref<Record<string, ColumnStats>>({})\n\n // Compute columns from data\n const columnKeys = computed(() => {\n if (data.value.length === 0)\n return []\n return Object.keys(data.value[0] as Record<string, unknown>)\n })\n\n // Get column stats (memoized)\n function getColumnStats(columnKey: string): ColumnStats {\n const cacheKey = `${columnKey}-${data.value.length}`\n if (!columnStatsCache.value[cacheKey]) {\n columnStatsCache.value[cacheKey] = getColumnUniqueValues(data.value, columnKey)\n }\n return columnStatsCache.value[cacheKey]\n }\n\n // Clear stats cache when data changes\n function clearStatsCache() {\n columnStatsCache.value = {}\n }\n\n // Create column definitions dynamically\n const columnDefs = computed<ColumnDef<T, unknown>[]>(() => {\n return columnKeys.value.map((key) => {\n const stats = getColumnStats(key)\n\n return {\n id: key,\n accessorKey: key,\n header: key,\n\n cell: (info: any) => formatCellValue(info.getValue(), stats.type),\n filterFn: multiSelectFilter,\n meta: {\n type: stats.type,\n uniqueCount: stats.uniqueValues.length,\n },\n } as ColumnDef<T, unknown>\n })\n })\n\n // Create table instance\n const table = useVueTable({\n get data() { return data.value },\n get columns() { return columnDefs.value },\n state: {\n get sorting() { return sorting.value },\n get columnFilters() { return columnFilters.value },\n get columnVisibility() { return columnVisibility.value },\n get globalFilter() { return globalFilter.value },\n },\n onSortingChange: (updater) => {\n sorting.value = typeof updater === 'function' ? updater(sorting.value) : updater\n },\n onColumnFiltersChange: (updater) => {\n columnFilters.value = typeof updater === 'function' ? updater(columnFilters.value) : updater\n },\n getCoreRowModel: getCoreRowModel(),\n getSortedRowModel: enableSorting ? getSortedRowModel() : undefined,\n getFilteredRowModel: enableFiltering ? getFilteredRowModel() : undefined,\n filterFns: {\n multiSelect: multiSelectFilter,\n },\n enableSorting,\n enableFilters: enableFiltering,\n })\n\n // Computed properties\n const filteredRowCount = computed(() => table.getFilteredRowModel().rows.length)\n const totalRowCount = computed(() => data.value.length)\n\n // Active filters (handles array values, numeric ranges, and date ranges)\n const activeFilters = computed(() => {\n return columnFilters.value.map((f) => {\n const filterValue = f.value as ColumnFilterValue | undefined\n\n // Handle numeric range\n if (filterValue && isNumericRange(filterValue)) {\n return {\n column: f.id,\n type: 'range' as const,\n range: filterValue,\n dateRange: null as DateRange | null,\n values: [] as string[],\n }\n }\n\n // Handle date range\n if (filterValue && isDateRange(filterValue)) {\n return {\n column: f.id,\n type: 'dateRange' as const,\n range: null as NumericRange | null,\n dateRange: filterValue,\n values: [] as string[],\n }\n }\n\n // Handle value array\n return {\n column: f.id,\n type: 'values' as const,\n values: Array.isArray(filterValue) ? filterValue : [],\n range: null as NumericRange | null,\n dateRange: null as DateRange | null,\n }\n })\n })\n\n // Check if column has active filter (handles array, numeric range, and date range)\n function hasActiveFilter(columnId: string): boolean {\n const column = table.getColumn(columnId)\n if (!column)\n return false\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (!filterValue)\n return false\n\n // Check for numeric range\n if (isNumericRange(filterValue)) {\n return filterValue.min !== null || filterValue.max !== null\n }\n\n // Check for date range\n if (isDateRange(filterValue)) {\n return filterValue.min !== null || filterValue.max !== null\n }\n\n // Check for value array\n return Array.isArray(filterValue) && filterValue.length > 0\n }\n\n // Set column filter (value-based)\n function setColumnFilter(columnId: string, values: string[]) {\n const column = table.getColumn(columnId)\n if (column) {\n column.setFilterValue(values.length === 0 ? undefined : values)\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Set numeric range filter\n function setNumericRangeFilter(columnId: string, range: NumericRange | null) {\n const column = table.getColumn(columnId)\n if (column) {\n if (!range || (range.min === null && range.max === null)) {\n column.setFilterValue(undefined)\n }\n else {\n column.setFilterValue(range)\n }\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Get numeric range filter for a column\n function getNumericRangeFilter(columnId: string): NumericRange | null {\n const column = table.getColumn(columnId)\n if (!column)\n return null\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (filterValue && isNumericRange(filterValue)) {\n return filterValue\n }\n return null\n }\n\n // Set date range filter\n function setDateRangeFilter(columnId: string, range: DateRange | null) {\n const column = table.getColumn(columnId)\n if (column) {\n if (!range || (range.min === null && range.max === null)) {\n column.setFilterValue(undefined)\n }\n else {\n column.setFilterValue(range)\n }\n // Force sync columnFilters ref with table state\n columnFilters.value = table.getState().columnFilters\n }\n }\n\n // Get date range filter for a column\n function getDateRangeFilter(columnId: string): DateRange | null {\n const column = table.getColumn(columnId)\n if (!column)\n return null\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (filterValue && isDateRange(filterValue)) {\n return filterValue\n }\n return null\n }\n\n // Clear all filters\n function clearAllFilters() {\n table.resetColumnFilters()\n globalFilter.value = ''\n // Force sync columnFilters ref with table state\n columnFilters.value = []\n }\n\n // Get filter values for a specific column\n function getColumnFilterValues(columnId: string): string[] {\n const column = table.getColumn(columnId)\n if (!column)\n return []\n const filterValue = column.getFilterValue()\n return Array.isArray(filterValue) ? filterValue : []\n }\n\n // Toggle column sort\n function toggleSort(columnId: string) {\n const current = sorting.value.find(s => s.id === columnId)\n if (!current) {\n sorting.value = [{ id: columnId, desc: false }]\n }\n else if (!current.desc) {\n sorting.value = [{ id: columnId, desc: true }]\n }\n else {\n sorting.value = []\n }\n }\n\n // Get sort direction for column\n function getSortDirection(columnId: string): 'asc' | 'desc' | null {\n const sort = sorting.value.find(s => s.id === columnId)\n if (!sort)\n return null\n return sort.desc ? 'desc' : 'asc'\n }\n\n // Watch data changes to clear cache\n watch(data, () => {\n clearStatsCache()\n })\n\n return {\n // Table instance\n table,\n\n // State\n sorting,\n columnFilters,\n columnVisibility,\n globalFilter,\n columnKeys,\n\n // Computed\n filteredRowCount,\n totalRowCount,\n activeFilters,\n\n // Methods\n getColumnStats,\n clearStatsCache,\n hasActiveFilter,\n setColumnFilter,\n getColumnFilterValues,\n clearAllFilters,\n toggleSort,\n getSortDirection,\n // Numeric range filters\n setNumericRangeFilter,\n getNumericRangeFilter,\n // Date range filters\n setDateRangeFilter,\n getDateRangeFilter,\n }\n}\n","import type { ExportOptions, PaginationOptions, PivotExportData, PivotValueField, SelectionBounds } from '@smallwebco/tinypivot-core'\nimport {\n copyToClipboard as coreCopyToClipboard,\n exportPivotToCSV as coreExportPivotToCSV,\n exportToCSV as coreExportToCSV,\n formatSelectionForClipboard as coreFormatSelection,\n} from '@smallwebco/tinypivot-core'\n/**\n * Grid Features Composable for Vue\n * Provides CSV export, clipboard, pagination, and other utility features\n */\nimport { computed, ref, type Ref } from 'vue'\n\n// Re-export core functions\nexport {\n copyToClipboard,\n exportPivotToCSV,\n exportToCSV,\n formatSelectionForClipboard,\n}\n\n/**\n * CSV Export functionality wrapper\n */\nfunction exportToCSV<T extends Record<string, unknown>>(\n data: T[],\n columns: string[],\n options?: ExportOptions,\n): void {\n coreExportToCSV(data, columns, options)\n}\n\n/**\n * Pivot CSV export wrapper\n */\nfunction exportPivotToCSV(\n pivotData: PivotExportData,\n rowFields: string[],\n columnFields: string[],\n valueFields: PivotValueField[],\n options?: ExportOptions,\n): void {\n coreExportPivotToCSV(pivotData, rowFields, columnFields, valueFields, options)\n}\n\n/**\n * Copy to clipboard wrapper\n */\nfunction copyToClipboard(\n text: string,\n onSuccess?: () => void,\n onError?: (err: Error) => void,\n): void {\n coreCopyToClipboard(text, onSuccess, onError)\n}\n\n/**\n * Format selection for clipboard wrapper\n */\nfunction formatSelectionForClipboard<T extends Record<string, unknown>>(\n rows: T[],\n columns: string[],\n selectionBounds: SelectionBounds,\n): string {\n return coreFormatSelection(rows, columns, selectionBounds)\n}\n\n/**\n * Pagination composable\n */\nexport function usePagination<T>(data: Ref<T[]>, options: PaginationOptions = {}) {\n const pageSize = ref(options.pageSize ?? 50)\n const currentPage = ref(options.currentPage ?? 1)\n\n const totalPages = computed(() =>\n Math.max(1, Math.ceil(data.value.length / pageSize.value)),\n )\n\n const paginatedData = computed(() => {\n const start = (currentPage.value - 1) * pageSize.value\n const end = start + pageSize.value\n return data.value.slice(start, end)\n })\n\n const startIndex = computed(() => (currentPage.value - 1) * pageSize.value + 1)\n const endIndex = computed(() =>\n Math.min(currentPage.value * pageSize.value, data.value.length),\n )\n\n function goToPage(page: number) {\n currentPage.value = Math.max(1, Math.min(page, totalPages.value))\n }\n\n function nextPage() {\n if (currentPage.value < totalPages.value) {\n currentPage.value++\n }\n }\n\n function prevPage() {\n if (currentPage.value > 1) {\n currentPage.value--\n }\n }\n\n function firstPage() {\n currentPage.value = 1\n }\n\n function lastPage() {\n currentPage.value = totalPages.value\n }\n\n function setPageSize(size: number) {\n pageSize.value = size\n currentPage.value = 1\n }\n\n return {\n pageSize,\n currentPage,\n totalPages,\n paginatedData,\n startIndex,\n endIndex,\n goToPage,\n nextPage,\n prevPage,\n firstPage,\n lastPage,\n setPageSize,\n }\n}\n\n/**\n * Global search/filter composable\n */\nexport function useGlobalSearch<T extends Record<string, unknown>>(\n data: Ref<T[]>,\n columns: Ref<string[]>,\n) {\n const searchTerm = ref('')\n const caseSensitive = ref(false)\n\n const filteredData = computed(() => {\n if (!searchTerm.value.trim()) {\n return data.value\n }\n\n const term = caseSensitive.value\n ? searchTerm.value.trim()\n : searchTerm.value.trim().toLowerCase()\n\n return data.value.filter((row) => {\n for (const col of columns.value) {\n const value = row[col]\n if (value === null || value === undefined)\n continue\n\n const strValue = caseSensitive.value ? String(value) : String(value).toLowerCase()\n\n if (strValue.includes(term)) {\n return true\n }\n }\n return false\n })\n })\n\n function clearSearch() {\n searchTerm.value = ''\n }\n\n return {\n searchTerm,\n caseSensitive,\n filteredData,\n clearSearch,\n }\n}\n\n/**\n * Row selection composable\n */\nexport function useRowSelection<T>(data: Ref<T[]>) {\n const selectedRowIndices = ref<Set<number>>(new Set())\n\n const selectedRows = computed(() => {\n return Array.from(selectedRowIndices.value)\n .sort((a, b) => a - b)\n .map(idx => data.value[idx])\n .filter(Boolean)\n })\n\n const allSelected = computed(() => {\n return data.value.length > 0 && selectedRowIndices.value.size === data.value.length\n })\n\n const someSelected = computed(() => {\n return selectedRowIndices.value.size > 0 && selectedRowIndices.value.size < data.value.length\n })\n\n function toggleRow(index: number) {\n if (selectedRowIndices.value.has(index)) {\n selectedRowIndices.value.delete(index)\n }\n else {\n selectedRowIndices.value.add(index)\n }\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function selectRow(index: number) {\n selectedRowIndices.value.add(index)\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function deselectRow(index: number) {\n selectedRowIndices.value.delete(index)\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n function selectAll() {\n selectedRowIndices.value = new Set(data.value.map((_, idx) => idx))\n }\n\n function deselectAll() {\n selectedRowIndices.value = new Set()\n }\n\n function toggleAll() {\n if (allSelected.value) {\n deselectAll()\n }\n else {\n selectAll()\n }\n }\n\n function isSelected(index: number): boolean {\n return selectedRowIndices.value.has(index)\n }\n\n function selectRange(startIndex: number, endIndex: number) {\n const min = Math.min(startIndex, endIndex)\n const max = Math.max(startIndex, endIndex)\n for (let i = min; i <= max; i++) {\n selectedRowIndices.value.add(i)\n }\n selectedRowIndices.value = new Set(selectedRowIndices.value)\n }\n\n return {\n selectedRowIndices,\n selectedRows,\n allSelected,\n someSelected,\n toggleRow,\n selectRow,\n deselectRow,\n selectAll,\n deselectAll,\n toggleAll,\n isSelected,\n selectRange,\n }\n}\n\n/**\n * Column resizing composable\n */\nexport function useColumnResize(\n initialWidths: Ref<Record<string, number>>,\n minWidth = 60,\n maxWidth = 600,\n) {\n const columnWidths = ref<Record<string, number>>({ ...initialWidths.value })\n const isResizing = ref(false)\n const resizingColumn = ref<string | null>(null)\n\n function startResize(columnId: string, event: MouseEvent) {\n isResizing.value = true\n resizingColumn.value = columnId\n const startX = event.clientX\n const startWidth = columnWidths.value[columnId] || 150\n\n const handleMouseMove = (e: MouseEvent) => {\n const diff = e.clientX - startX\n const newWidth = Math.max(minWidth, Math.min(maxWidth, startWidth + diff))\n columnWidths.value = {\n ...columnWidths.value,\n [columnId]: newWidth,\n }\n }\n\n const handleMouseUp = () => {\n isResizing.value = false\n resizingColumn.value = null\n document.removeEventListener('mousemove', handleMouseMove)\n document.removeEventListener('mouseup', handleMouseUp)\n }\n\n document.addEventListener('mousemove', handleMouseMove)\n document.addEventListener('mouseup', handleMouseUp)\n }\n\n function resetColumnWidth(columnId: string) {\n if (initialWidths.value[columnId]) {\n columnWidths.value = {\n ...columnWidths.value,\n [columnId]: initialWidths.value[columnId],\n }\n }\n }\n\n function resetAllWidths() {\n columnWidths.value = { ...initialWidths.value }\n }\n\n return {\n columnWidths,\n isResizing,\n resizingColumn,\n startResize,\n resetColumnWidth,\n resetAllWidths,\n }\n}\n","import type { LicenseInfo } from '@smallwebco/tinypivot-core'\nimport {\n canUseAIAnalyst as coreCanUseAIAnalyst,\n canUseCharts as coreCanUseCharts,\n canUsePivot as coreCanUsePivot,\n configureLicenseSecret as coreConfigureLicenseSecret,\n isPro as coreIsPro,\n shouldShowWatermark as coreShouldShowWatermark,\n getDemoLicenseInfo,\n getFreeLicenseInfo,\n logProRequired,\n validateLicenseKey,\n} from '@smallwebco/tinypivot-core'\n/**\n * License Management Composable for Vue\n * Wraps core license logic with Vue reactivity\n */\nimport { computed, ref } from 'vue'\n\n// License state\nconst licenseKey = ref<string | null>(null)\nconst demoMode = ref(false)\nconst licenseInfo = ref<LicenseInfo>(getFreeLicenseInfo())\n\n// Cached validation result\nlet validationPromise: Promise<LicenseInfo> | null = null\n\n/**\n * Set the license key for the library\n * Returns a promise that resolves when validation is complete\n */\nexport async function setLicenseKey(key: string): Promise<void> {\n licenseKey.value = key\n\n // Start validation\n validationPromise = validateLicenseKey(key)\n licenseInfo.value = await validationPromise\n validationPromise = null\n\n if (!licenseInfo.value.isValid) {\n console.warn('[TinyPivot] License validation failed. Check the console for environment details. Running in free mode.')\n }\n else if (licenseInfo.value.type !== 'free') {\n console.info(`[TinyPivot] Pro license activated (${licenseInfo.value.type})`)\n }\n}\n\n/**\n * Enable demo mode - unlocks all features for evaluation\n * Requires the correct demo secret\n * Shows \"Demo Mode\" watermark\n */\nexport async function enableDemoMode(secret: string): Promise<boolean> {\n const demoLicense = await getDemoLicenseInfo(secret)\n if (!demoLicense) {\n console.warn('[TinyPivot] Demo mode activation failed - invalid secret')\n return false\n }\n demoMode.value = true\n licenseInfo.value = demoLicense\n console.info('[TinyPivot] Demo mode enabled - all Pro features unlocked for evaluation')\n return true\n}\n\n/**\n * Configure the license secret\n */\nexport function configureLicenseSecret(secret: string): void {\n coreConfigureLicenseSecret(secret)\n}\n\n/**\n * Composable for accessing license information\n */\nexport function useLicense() {\n const isDemo = computed(() => demoMode.value)\n\n const isPro = computed(() => demoMode.value || coreIsPro(licenseInfo.value))\n\n const canUsePivot = computed(() => demoMode.value || coreCanUsePivot(licenseInfo.value))\n\n const canUseAdvancedAggregations = computed(\n () => demoMode.value || licenseInfo.value.features.advancedAggregations,\n )\n\n const canUsePercentageMode = computed(\n () => demoMode.value || licenseInfo.value.features.percentageMode,\n )\n\n const canUseCharts = computed(() => demoMode.value || coreCanUseCharts(licenseInfo.value))\n\n const canUseAIAnalyst = computed(() => demoMode.value || coreCanUseAIAnalyst(licenseInfo.value))\n\n const showWatermark = computed(() => coreShouldShowWatermark(licenseInfo.value, demoMode.value))\n\n function requirePro(feature: string): boolean {\n if (!isPro.value) {\n logProRequired(feature)\n return false\n }\n return true\n }\n\n return {\n licenseInfo: computed(() => licenseInfo.value),\n isDemo,\n isPro,\n canUsePivot,\n canUseAdvancedAggregations,\n canUsePercentageMode,\n canUseCharts,\n canUseAIAnalyst,\n showWatermark,\n requirePro,\n }\n}\n","import type { AggregationFunction, CalculatedField, FieldStats, PivotConfig, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n computeAvailableFields,\n computePivotResult,\n generateStorageKey,\n getAggregationLabel,\n getUnassignedFields,\n isConfigValidForFields,\n isPivotConfigured,\n loadCalculatedFields,\n loadPivotConfig,\n saveCalculatedFields,\n savePivotConfig,\n} from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Composable for Vue\n * Wraps core pivot logic with Vue reactivity\n */\nimport { computed, type Ref, ref, watch } from 'vue'\nimport { useLicense } from './useLicense'\n\n// Re-export for convenience\nexport { getAggregationLabel }\n\n/**\n * Main pivot table composable\n */\nexport function usePivotTable(data: Ref<Record<string, unknown>[]>) {\n const { canUsePivot, requirePro } = useLicense()\n\n // Configuration state\n const rowFields = ref<string[]>([])\n const columnFields = ref<string[]>([])\n const valueFields = ref<PivotValueField[]>([])\n const showRowTotals = ref(true)\n const showColumnTotals = ref(true)\n const calculatedFields = ref<CalculatedField[]>(loadCalculatedFields())\n\n // Track current storage key\n const currentStorageKey = ref<string | null>(null)\n\n // Compute available fields from data\n const availableFields = computed((): FieldStats[] => {\n return computeAvailableFields(data.value)\n })\n\n // Get fields that haven't been assigned yet\n const unassignedFields = computed(() => {\n return getUnassignedFields(\n availableFields.value,\n rowFields.value,\n columnFields.value,\n valueFields.value,\n )\n })\n\n // Check if pivot is configured\n const isConfigured = computed(() => {\n return isPivotConfigured({\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n })\n })\n\n // Build pivot result\n const pivotResult = computed(() => {\n if (!isConfigured.value)\n return null\n\n // Check license for pivot feature\n if (!canUsePivot.value)\n return null\n\n return computePivotResult(data.value, {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n calculatedFields: calculatedFields.value,\n })\n })\n\n // Actions - pivot is free with sum aggregation, Pro required for other aggregations\n function addRowField(field: string) {\n if (!rowFields.value.includes(field)) {\n rowFields.value = [...rowFields.value, field]\n }\n }\n\n function removeRowField(field: string) {\n rowFields.value = rowFields.value.filter(f => f !== field)\n }\n\n function addColumnField(field: string) {\n if (!columnFields.value.includes(field)) {\n columnFields.value = [...columnFields.value, field]\n }\n }\n\n function removeColumnField(field: string) {\n columnFields.value = columnFields.value.filter(f => f !== field)\n }\n\n function addValueField(field: string, aggregation: AggregationFunction = 'sum') {\n // Pro required for non-sum aggregations\n if (aggregation !== 'sum' && !requirePro(`${aggregation} aggregation`)) {\n return\n }\n if (valueFields.value.some(v => v.field === field && v.aggregation === aggregation)) {\n return\n }\n valueFields.value = [...valueFields.value, { field, aggregation }]\n }\n\n function removeValueField(field: string, aggregation?: AggregationFunction) {\n if (aggregation) {\n valueFields.value = valueFields.value.filter(\n v => !(v.field === field && v.aggregation === aggregation),\n )\n }\n else {\n valueFields.value = valueFields.value.filter(v => v.field !== field)\n }\n }\n\n function updateValueFieldAggregation(\n field: string,\n oldAgg: AggregationFunction,\n newAgg: AggregationFunction,\n ) {\n valueFields.value = valueFields.value.map((v) => {\n if (v.field === field && v.aggregation === oldAgg) {\n return { ...v, aggregation: newAgg }\n }\n return v\n })\n }\n\n function clearConfig() {\n rowFields.value = []\n columnFields.value = []\n valueFields.value = []\n }\n\n function moveField(\n from: { area: 'row' | 'column' | 'value', index: number },\n to: { area: 'row' | 'column' | 'value', index: number },\n ) {\n if (from.area === to.area) {\n if (from.area === 'row') {\n const items = [...rowFields.value]\n const [removed] = items.splice(from.index, 1)\n items.splice(to.index, 0, removed)\n rowFields.value = items\n }\n else if (from.area === 'column') {\n const items = [...columnFields.value]\n const [removed] = items.splice(from.index, 1)\n items.splice(to.index, 0, removed)\n columnFields.value = items\n }\n }\n }\n\n function autoSuggestConfig() {\n if (!requirePro('Pivot Table - Auto Suggest'))\n return\n if (availableFields.value.length === 0)\n return\n\n const categoricalFields = availableFields.value.filter(f => !f.isNumeric && f.uniqueCount < 50)\n const numericFields = availableFields.value.filter(f => f.isNumeric)\n\n if (categoricalFields.length > 0 && numericFields.length > 0) {\n rowFields.value = [categoricalFields[0].field]\n valueFields.value = [{ field: numericFields[0].field, aggregation: 'sum' }]\n }\n }\n\n // Calculated field management\n function addCalculatedField(field: CalculatedField) {\n const existing = calculatedFields.value.findIndex(f => f.id === field.id)\n if (existing >= 0) {\n calculatedFields.value = [\n ...calculatedFields.value.slice(0, existing),\n field,\n ...calculatedFields.value.slice(existing + 1),\n ]\n }\n else {\n calculatedFields.value = [...calculatedFields.value, field]\n }\n saveCalculatedFields(calculatedFields.value)\n }\n\n function removeCalculatedField(id: string) {\n calculatedFields.value = calculatedFields.value.filter(f => f.id !== id)\n // Also remove from value fields if it was being used\n valueFields.value = valueFields.value.filter(v => v.field !== `calc:${id}`)\n saveCalculatedFields(calculatedFields.value)\n }\n\n // Watch data to restore or validate config\n watch(\n data,\n (newData) => {\n if (newData.length === 0)\n return\n\n const newKeys = Object.keys(newData[0])\n const storageKey = generateStorageKey(newKeys)\n\n if (storageKey !== currentStorageKey.value) {\n currentStorageKey.value = storageKey\n\n const savedConfig = loadPivotConfig(storageKey)\n if (savedConfig && isConfigValidForFields(savedConfig, newKeys)) {\n rowFields.value = savedConfig.rowFields\n columnFields.value = savedConfig.columnFields\n valueFields.value = savedConfig.valueFields\n showRowTotals.value = savedConfig.showRowTotals\n showColumnTotals.value = savedConfig.showColumnTotals\n if (savedConfig.calculatedFields) {\n calculatedFields.value = savedConfig.calculatedFields\n }\n }\n else {\n const currentConfig: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n }\n if (!isConfigValidForFields(currentConfig, newKeys)) {\n clearConfig()\n }\n }\n }\n else {\n const currentConfig: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n }\n if (!isConfigValidForFields(currentConfig, newKeys)) {\n clearConfig()\n }\n }\n },\n { immediate: true },\n )\n\n // Watch config changes and save to sessionStorage\n watch(\n [rowFields, columnFields, valueFields, showRowTotals, showColumnTotals, calculatedFields],\n () => {\n if (!currentStorageKey.value)\n return\n\n const config: PivotConfig = {\n rowFields: rowFields.value,\n columnFields: columnFields.value,\n valueFields: valueFields.value,\n showRowTotals: showRowTotals.value,\n showColumnTotals: showColumnTotals.value,\n calculatedFields: calculatedFields.value,\n }\n savePivotConfig(currentStorageKey.value, config)\n },\n { deep: true },\n )\n\n return {\n // State\n rowFields,\n columnFields,\n valueFields,\n showRowTotals,\n showColumnTotals,\n calculatedFields,\n\n // Computed\n availableFields,\n unassignedFields,\n isConfigured,\n pivotResult,\n\n // Actions\n addRowField,\n removeRowField,\n addColumnField,\n removeColumnField,\n addValueField,\n removeValueField,\n updateValueFieldAggregation,\n clearConfig,\n moveField,\n autoSuggestConfig,\n addCalculatedField,\n removeCalculatedField,\n }\n}\n","<script setup lang=\"ts\">\nimport type { AggregationFunction, CalculatedField, PivotValueField } from '@smallwebco/tinypivot-core'\nimport { AGGREGATION_OPTIONS, getAggregationSymbol } from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Configuration Panel\n * Draggable fields with aggregation selection\n */\nimport { computed, ref } from 'vue'\nimport { useLicense } from '../composables/useLicense'\nimport CalculatedFieldModal from './CalculatedFieldModal.vue'\n\ninterface FieldStats {\n field: string\n type: 'string' | 'number' | 'date' | 'boolean' | 'mixed'\n uniqueCount: number\n isNumeric: boolean\n}\n\ninterface ExtendedFieldStats extends FieldStats {\n isCalculated: boolean\n calcId?: string\n calcName?: string\n calcFormula?: string\n}\n\nconst props = defineProps<{\n availableFields: FieldStats[]\n rowFields: string[]\n columnFields: string[]\n valueFields: PivotValueField[]\n showRowTotals: boolean\n showColumnTotals: boolean\n calculatedFields?: CalculatedField[]\n}>()\n\nconst emit = defineEmits<{\n (e: 'update:showRowTotals', value: boolean): void\n (e: 'update:showColumnTotals', value: boolean): void\n (e: 'clearConfig'): void\n (e: 'dragStart', field: string, event: DragEvent): void\n (e: 'dragEnd'): void\n (e: 'updateAggregation', field: string, oldAgg: AggregationFunction, newAgg: AggregationFunction): void\n (e: 'addRowField', field: string): void\n (e: 'removeRowField', field: string): void\n (e: 'addColumnField', field: string): void\n (e: 'removeColumnField', field: string): void\n (e: 'addValueField', field: string, aggregation: AggregationFunction): void\n (e: 'removeValueField', field: string, aggregation: AggregationFunction): void\n (e: 'addCalculatedField', field: CalculatedField): void\n (e: 'removeCalculatedField', id: string): void\n (e: 'updateCalculatedField', field: CalculatedField): void\n}>()\n\nconst { canUseAdvancedAggregations } = useLicense()\n\n// Use aggregation options from core\nconst aggregationOptions = AGGREGATION_OPTIONS\n\n// Check if an aggregation requires Pro (everything except sum)\nfunction aggregationRequiresPro(agg: AggregationFunction): boolean {\n return agg !== 'sum'\n}\n\n// Check if an aggregation is available based on license\nfunction isAggregationAvailable(agg: AggregationFunction): boolean {\n return !aggregationRequiresPro(agg) || canUseAdvancedAggregations.value\n}\n\n// Calculated field modal state\nconst showCalcModal = ref(false)\nconst editingCalcField = ref<CalculatedField | null>(null)\n\n// Get only numeric field names for calculated field formulas\nconst numericFieldNames = computed(() =>\n props.availableFields\n .filter(f => f.isNumeric)\n .map(f => f.field),\n)\n\nfunction openCalcModal(field?: CalculatedField) {\n editingCalcField.value = field || null\n showCalcModal.value = true\n}\n\nfunction handleSaveCalcField(field: CalculatedField) {\n if (editingCalcField.value) {\n emit('updateCalculatedField', field)\n }\n else {\n emit('addCalculatedField', field)\n }\n showCalcModal.value = false\n editingCalcField.value = null\n}\n\n// Toggle both row and column totals together\nfunction handleTotalsToggle(checked: boolean) {\n emit('update:showRowTotals', checked)\n emit('update:showColumnTotals', checked)\n}\n\n// Convert calculated fields to virtual FieldStats for display\nconst calculatedFieldsAsStats = computed<ExtendedFieldStats[]>(() => {\n if (!props.calculatedFields)\n return []\n return props.calculatedFields.map(calc => ({\n field: `calc:${calc.id}`,\n type: 'number' as const,\n uniqueCount: 0,\n isNumeric: true,\n isCalculated: true,\n calcId: calc.id,\n calcName: calc.name,\n calcFormula: calc.formula,\n }))\n})\n\n// Combined available fields (data fields + calculated fields)\nconst allAvailableFields = computed<ExtendedFieldStats[]>(() => [\n ...props.availableFields.map(f => ({ ...f, isCalculated: false as const })),\n ...calculatedFieldsAsStats.value,\n])\n\n// Assigned fields\nconst assignedFields = computed(() => {\n const rowSet = new Set(props.rowFields)\n const colSet = new Set(props.columnFields)\n const valueMap = new Map(props.valueFields.map(v => [v.field, v]))\n\n return allAvailableFields.value\n .filter(f => rowSet.has(f.field) || colSet.has(f.field) || valueMap.has(f.field))\n .map(f => ({\n ...f,\n assignedTo: rowSet.has(f.field)\n ? 'row' as const\n : colSet.has(f.field)\n ? 'column' as const\n : 'value' as const,\n valueConfig: valueMap.get(f.field),\n }))\n})\n\n// Unassigned fields (including unassigned calculated fields)\nconst unassignedFields = computed(() => {\n const rowSet = new Set(props.rowFields)\n const colSet = new Set(props.columnFields)\n const valSet = new Set(props.valueFields.map(v => v.field))\n\n return allAvailableFields.value.filter(f =>\n !rowSet.has(f.field) && !colSet.has(f.field) && !valSet.has(f.field),\n )\n})\n\nconst assignedCount = computed(() => assignedFields.value.length)\n\n// Field search\nconst fieldSearch = ref('')\nconst filteredUnassignedFields = computed(() => {\n if (!fieldSearch.value.trim())\n return unassignedFields.value\n const search = fieldSearch.value.toLowerCase().trim()\n return unassignedFields.value.filter((f) => {\n // Search by field name or calculated field display name\n const fieldName = f.field.toLowerCase()\n const displayName = f.isCalculated && f.calcName ? f.calcName.toLowerCase() : ''\n return fieldName.includes(search) || displayName.includes(search)\n })\n})\n\n// Field type icons\nfunction getFieldIcon(type: FieldStats['type'], isCalculated?: boolean): string {\n if (isCalculated)\n return 'ƒ'\n switch (type) {\n case 'number': return '#'\n case 'date': return '📅'\n case 'boolean': return '✓'\n default: return 'Aa'\n }\n}\n\n// Get display name for field (handles calculated fields)\nfunction getFieldDisplayName(field: any): string {\n if (field.isCalculated && field.calcName) {\n return field.calcName\n }\n return field.field\n}\n\nfunction handleDragStart(field: string, event: DragEvent) {\n event.dataTransfer?.setData('text/plain', field)\n event.dataTransfer!.effectAllowed = 'move'\n emit('dragStart', field, event)\n}\n\nfunction handleDragEnd() {\n emit('dragEnd')\n}\n\nfunction handleAggregationChange(field: string, currentAgg: AggregationFunction, newAgg: AggregationFunction) {\n // Prevent changing to Pro aggregations without license\n if (!isAggregationAvailable(newAgg)) {\n console.warn(`[TinyPivot] \"${newAgg}\" aggregation requires a Pro license. Visit https://tiny-pivot.com/#pricing to upgrade.`)\n return\n }\n emit('updateAggregation', field, currentAgg, newAgg)\n}\n\nfunction toggleRowColumn(field: string, currentAssignment: 'row' | 'column') {\n if (currentAssignment === 'row') {\n emit('removeRowField', field)\n emit('addColumnField', field)\n }\n else {\n emit('removeColumnField', field)\n emit('addRowField', field)\n }\n}\n\nfunction removeField(field: string, assignedTo: 'row' | 'column' | 'value', valueConfig?: PivotValueField) {\n if (assignedTo === 'row') {\n emit('removeRowField', field)\n }\n else if (assignedTo === 'column') {\n emit('removeColumnField', field)\n }\n else if (valueConfig) {\n emit('removeValueField', field, valueConfig.aggregation)\n }\n}\n</script>\n\n<template>\n <div class=\"vpg-pivot-config\">\n <!-- Header -->\n <div class=\"vpg-config-header\">\n <h3 class=\"vpg-config-title\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 6h16M4 10h16M4 14h16M4 18h16\" />\n </svg>\n Fields\n </h3>\n <div class=\"vpg-header-actions\">\n <button\n v-if=\"assignedCount > 0\"\n class=\"vpg-action-btn vpg-clear-btn\"\n title=\"Clear all\"\n @click=\"emit('clearConfig')\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Assigned Fields -->\n <div v-if=\"assignedCount > 0\" class=\"vpg-assigned-section\">\n <div class=\"vpg-section-label\">\n Active\n </div>\n <div class=\"vpg-assigned-list\">\n <div\n v-for=\"field in assignedFields\"\n :key=\"field.field\"\n class=\"vpg-assigned-item\"\n :class=\"[`vpg-type-${field.assignedTo}`, { 'vpg-type-calc': field.isCalculated }]\"\n :title=\"field.isCalculated ? field.calcFormula : field.field\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field.field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <div class=\"vpg-item-main\">\n <span class=\"vpg-item-badge\" :class=\"[field.assignedTo, { calc: field.isCalculated }]\">\n {{ field.isCalculated ? 'ƒ' : (field.assignedTo === 'row' ? 'R' : field.assignedTo === 'column' ? 'C' : getAggregationSymbol(field.valueConfig?.aggregation || 'sum')) }}\n </span>\n <span class=\"vpg-item-name\">{{ getFieldDisplayName(field) }}</span>\n </div>\n\n <div class=\"vpg-item-actions\">\n <button\n v-if=\"field.assignedTo === 'row' || field.assignedTo === 'column'\"\n class=\"vpg-toggle-btn\"\n :title=\"field.assignedTo === 'row' ? 'Move to Columns' : 'Move to Rows'\"\n @click.stop=\"toggleRowColumn(field.field, field.assignedTo)\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4\" />\n </svg>\n </button>\n\n <select\n v-if=\"field.assignedTo === 'value' && field.valueConfig\"\n class=\"vpg-agg-select\"\n :value=\"field.valueConfig.aggregation\"\n @change=\"handleAggregationChange(field.field, field.valueConfig!.aggregation, ($event.target as HTMLSelectElement).value as AggregationFunction)\"\n @click.stop\n >\n <option\n v-for=\"agg in aggregationOptions\"\n :key=\"agg.value\"\n :value=\"agg.value\"\n :disabled=\"aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations\"\n >\n {{ agg.symbol }} {{ agg.label }}{{ aggregationRequiresPro(agg.value) && !canUseAdvancedAggregations ? ' (Pro)' : '' }}\n </option>\n </select>\n\n <button\n class=\"vpg-remove-btn\"\n title=\"Remove\"\n @click.stop=\"removeField(field.field, field.assignedTo, field.valueConfig)\"\n >\n ×\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Unassigned Fields -->\n <div class=\"vpg-unassigned-section\">\n <div class=\"vpg-section-header\">\n <div class=\"vpg-section-label\">\n Available <span class=\"vpg-count\">{{ unassignedFields.length }}</span>\n </div>\n </div>\n\n <!-- Field Search -->\n <div class=\"vpg-field-search\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n v-model=\"fieldSearch\"\n type=\"text\"\n placeholder=\"Search fields...\"\n class=\"vpg-search-input\"\n >\n <button v-if=\"fieldSearch\" class=\"vpg-clear-search\" @click=\"fieldSearch = ''\">\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div class=\"vpg-field-list\">\n <div\n v-for=\"field in filteredUnassignedFields\"\n :key=\"field.field\"\n class=\"vpg-field-item\"\n :class=\"{\n 'vpg-is-numeric': field.isNumeric && !field.isCalculated,\n 'vpg-is-calculated': field.isCalculated,\n }\"\n :title=\"field.isCalculated ? field.calcFormula : field.field\"\n draggable=\"true\"\n @dragstart=\"handleDragStart(field.field, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"vpg-field-type-icon\" :class=\"{ 'vpg-calc-type': field.isCalculated }\">\n {{ getFieldIcon(field.type, field.isCalculated) }}\n </span>\n <span class=\"vpg-field-name\">{{ getFieldDisplayName(field) }}</span>\n <template v-if=\"field.isCalculated\">\n <button\n class=\"vpg-field-edit\"\n title=\"Edit calculated field\"\n @click.stop=\"openCalcModal(calculatedFields?.find(c => c.id === field.calcId))\"\n >\n ✎\n </button>\n <button\n class=\"vpg-field-delete\"\n title=\"Delete calculated field\"\n @click.stop=\"field.calcId && emit('removeCalculatedField', field.calcId)\"\n >\n ×\n </button>\n </template>\n <template v-else>\n <span class=\"vpg-unique-count\">{{ field.uniqueCount }}</span>\n </template>\n </div>\n <div v-if=\"filteredUnassignedFields.length === 0 && fieldSearch\" class=\"vpg-empty-hint\">\n No fields match \"{{ fieldSearch }}\"\n </div>\n <div v-else-if=\"unassignedFields.length === 0\" class=\"vpg-empty-hint\">\n All fields assigned\n </div>\n </div>\n </div>\n\n <!-- Options -->\n <div class=\"vpg-options-section\">\n <label class=\"vpg-option-toggle\">\n <input\n type=\"checkbox\"\n :checked=\"showRowTotals\"\n @change=\"handleTotalsToggle(($event.target as HTMLInputElement).checked)\"\n >\n <span>Totals</span>\n </label>\n <button class=\"vpg-calc-btn\" title=\"Add calculated field (e.g. Profit Margin %)\" @click=\"openCalcModal()\">\n <span class=\"vpg-calc-icon\">ƒ</span>\n <span>+ Calc</span>\n </button>\n </div>\n\n <!-- Calculated Field Modal -->\n <CalculatedFieldModal\n :show=\"showCalcModal\"\n :available-fields=\"numericFieldNames\"\n :existing-field=\"editingCalcField\"\n @close=\"showCalcModal = false; editingCalcField = null\"\n @save=\"handleSaveCalcField\"\n />\n </div>\n</template>\n\n<style scoped>\n.vpg-pivot-config {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-config-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 0.75rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-config-title {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-icon-sm {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-header-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-action-btn {\n padding: 0.375rem;\n border-radius: 0.25rem;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-clear-btn {\n color: #94a3b8;\n}\n\n.vpg-clear-btn:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-section-label {\n font-size: 0.625rem;\n font-weight: 700;\n color: #94a3b8;\n text-transform: uppercase;\n letter-spacing: 0.1em;\n padding: 0.25rem 0.5rem;\n}\n\n.vpg-section-label .vpg-count {\n color: #cbd5e1;\n margin-left: 0.25rem;\n}\n\n.vpg-assigned-section {\n border-bottom: 1px solid #e2e8f0;\n background: linear-gradient(to bottom, #f8fafc, white);\n padding-bottom: 0.5rem;\n flex-shrink: 0;\n}\n\n.vpg-assigned-list {\n padding: 0 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.vpg-assigned-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.375rem 0.5rem;\n border-radius: 0.5rem;\n font-size: 0.75rem;\n cursor: grab;\n transition: all 0.15s;\n}\n\n.vpg-assigned-item:active {\n cursor: grabbing;\n transform: scale(0.98);\n}\n\n.vpg-assigned-item.vpg-type-row {\n background: #eef2ff;\n border: 1px solid #c7d2fe;\n}\n\n.vpg-assigned-item.vpg-type-column {\n background: #f5f3ff;\n border: 1px solid #ddd6fe;\n}\n\n.vpg-assigned-item.vpg-type-value {\n background: #ecfdf5;\n border: 1px solid #a7f3d0;\n}\n\n.vpg-assigned-item.vpg-type-calc {\n background: #fdf4ff;\n border: 1px solid #f0abfc;\n cursor: pointer;\n}\n\n.vpg-item-main {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n min-width: 0;\n}\n\n.vpg-item-badge {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n}\n\n.vpg-item-badge.row {\n background: #c7d2fe;\n color: #4338ca;\n}\n\n.vpg-item-badge.column {\n background: #ddd6fe;\n color: #7c3aed;\n}\n\n.vpg-item-badge.value {\n background: #a7f3d0;\n color: #059669;\n}\n\n.vpg-item-badge.calc {\n background: #f0abfc;\n color: #86198f;\n}\n\n.vpg-item-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n color: #334155;\n}\n\n.vpg-item-actions {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n.vpg-toggle-btn {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 0.25rem;\n color: #94a3b8;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-toggle-btn:hover {\n background: white;\n color: #475569;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-agg-select {\n font-size: 0.625rem;\n background: white;\n border: 1px solid #a7f3d0;\n border-radius: 0.25rem;\n padding: 0.125rem 0.25rem;\n color: #059669;\n font-weight: 500;\n min-width: 70px;\n cursor: pointer;\n}\n\n.vpg-agg-select:focus {\n outline: none;\n box-shadow: 0 0 0 1px #10b981;\n}\n\n.vpg-remove-btn {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n line-height: 1;\n color: #94a3b8;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-remove-btn:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-unassigned-section {\n flex: 1;\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n}\n\n.vpg-section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0 0.5rem;\n}\n\n.vpg-field-search {\n position: relative;\n margin: 0 0.5rem 0.5rem;\n}\n\n.vpg-search-icon {\n position: absolute;\n left: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n width: 0.875rem;\n height: 0.875rem;\n color: #94a3b8;\n pointer-events: none;\n}\n\n.vpg-search-input {\n width: 100%;\n padding: 0.375rem 1.75rem 0.375rem 1.75rem;\n font-size: 0.75rem;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n background: white;\n color: #334155;\n}\n\n.vpg-search-input::placeholder {\n color: #94a3b8;\n}\n\n.vpg-search-input:focus {\n outline: none;\n box-shadow: 0 0 0 1px #6366f1;\n border-color: #6366f1;\n}\n\n.vpg-clear-search {\n position: absolute;\n right: 0.5rem;\n top: 50%;\n transform: translateY(-50%);\n padding: 0.125rem;\n border-radius: 0.25rem;\n color: #94a3b8;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-clear-search:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-field-list {\n flex: 1;\n overflow-y: auto;\n padding: 0 0.5rem 0.5rem;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.vpg-field-item {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.375rem 0.5rem;\n border-radius: 0.375rem;\n font-size: 0.75rem;\n cursor: grab;\n background: white;\n border: 1px solid #e2e8f0;\n color: #475569;\n transition: all 0.15s;\n}\n\n.vpg-field-item:hover {\n border-color: #cbd5e1;\n background: #f8fafc;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-field-item:active {\n cursor: grabbing;\n transform: scale(0.98);\n}\n\n.vpg-field-item.vpg-is-numeric {\n border-color: #bfdbfe;\n background: rgba(239, 246, 255, 0.3);\n}\n\n.vpg-field-item.vpg-is-calculated {\n border-color: #e9d5ff;\n background: rgba(250, 232, 255, 0.5);\n}\n\n.vpg-calc-type {\n background: #f0abfc !important;\n color: #86198f !important;\n}\n\n.vpg-field-edit,\n.vpg-field-delete {\n width: 1.125rem;\n height: 1.125rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n line-height: 1;\n color: #94a3b8;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.vpg-field-edit:hover {\n background: #e0e7ff;\n color: #4f46e5;\n}\n\n.vpg-field-delete:hover {\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-field-type-icon {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n background: #f1f5f9;\n border-radius: 0.25rem;\n color: #64748b;\n flex-shrink: 0;\n}\n\n.vpg-field-item.vpg-is-numeric .vpg-field-type-icon {\n background: #dbeafe;\n color: #2563eb;\n}\n\n.vpg-field-name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n\n.vpg-unique-count {\n font-size: 0.625rem;\n color: #94a3b8;\n font-variant-numeric: tabular-nums;\n flex-shrink: 0;\n}\n\n.vpg-empty-hint {\n font-size: 0.6875rem;\n color: #94a3b8;\n font-style: italic;\n text-align: center;\n padding: 1rem;\n}\n\n.vpg-options-section {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n border-top: 1px solid #f1f5f9;\n background: rgba(248, 250, 252, 0.5);\n flex-shrink: 0;\n}\n\n.vpg-option-toggle {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n font-size: 0.6875rem;\n color: #64748b;\n cursor: pointer;\n user-select: none;\n}\n\n.vpg-option-toggle input {\n width: 0.875rem;\n height: 0.875rem;\n border-radius: 0.25rem;\n accent-color: #10b981;\n cursor: pointer;\n}\n\n.vpg-calc-btn {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.6875rem;\n font-weight: 500;\n border-radius: 0.25rem;\n background: #fdf4ff;\n color: #a855f7;\n border: 1px solid #e9d5ff;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-calc-btn:hover {\n background: #fae8ff;\n border-color: #d8b4fe;\n}\n\n.vpg-calc-icon {\n font-size: 0.75rem;\n font-weight: 700;\n}\n\n/* Scrollbar */\n.vpg-field-list::-webkit-scrollbar {\n width: 0.375rem;\n}\n\n.vpg-field-list::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.vpg-field-list::-webkit-scrollbar-thumb {\n background: #e2e8f0;\n border-radius: 9999px;\n}\n\n.vpg-field-list::-webkit-scrollbar-thumb:hover {\n background: #cbd5e1;\n}\n</style>\n\n<style>\n/* Dark mode - PivotConfig */\n.vpg-theme-dark .vpg-pivot-config {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-config-header {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-config-title {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-section-label {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-section-label .vpg-count {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-assigned-section {\n border-color: #334155;\n background: linear-gradient(to bottom, #0f172a, #1e293b);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-row {\n background: rgba(99, 102, 241, 0.15);\n border-color: rgba(99, 102, 241, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-column {\n background: rgba(139, 92, 246, 0.15);\n border-color: rgba(139, 92, 246, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-value {\n background: rgba(16, 185, 129, 0.15);\n border-color: rgba(16, 185, 129, 0.3);\n}\n\n.vpg-theme-dark .vpg-assigned-item.vpg-type-calc {\n background: rgba(168, 85, 247, 0.15);\n border-color: rgba(168, 85, 247, 0.3);\n}\n\n.vpg-theme-dark .vpg-item-badge.row {\n background: rgba(99, 102, 241, 0.3);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-item-badge.column {\n background: rgba(139, 92, 246, 0.3);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-item-badge.value {\n background: rgba(16, 185, 129, 0.3);\n color: #6ee7b7;\n}\n\n.vpg-theme-dark .vpg-item-badge.calc {\n background: rgba(168, 85, 247, 0.3);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-item-name {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-toggle-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-toggle-btn:hover {\n background: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-agg-select {\n background: #0f172a;\n border-color: rgba(16, 185, 129, 0.3);\n color: #6ee7b7;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-agg-select:focus {\n box-shadow: 0 0 0 1px #10b981;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-remove-btn {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-remove-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input {\n background: #0f172a;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input::placeholder {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-input:focus {\n border-color: #6366f1;\n box-shadow: 0 0 0 1px #6366f1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-search-icon {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-clear-search:hover {\n background: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item {\n background: #0f172a;\n border-color: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item:hover {\n border-color: #475569;\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-numeric {\n border-color: rgba(59, 130, 246, 0.3);\n background: rgba(59, 130, 246, 0.1);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-type-icon {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-numeric .vpg-field-type-icon {\n background: rgba(59, 130, 246, 0.3);\n color: #60a5fa;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-item.vpg-is-calculated {\n border-color: rgba(168, 85, 247, 0.3);\n background: rgba(168, 85, 247, 0.1);\n}\n\n.vpg-theme-dark .vpg-calc-type {\n background: rgba(168, 85, 247, 0.4) !important;\n color: #c4b5fd !important;\n}\n\n.vpg-theme-dark .vpg-field-edit,\n.vpg-theme-dark .vpg-field-delete {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-field-edit:hover {\n background: rgba(99, 102, 241, 0.2);\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-field-delete:hover {\n background: rgba(239, 68, 68, 0.2);\n color: #f87171;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-unique-count {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-empty-hint {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-options-section {\n border-color: #334155;\n background: rgba(15, 23, 42, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-option-toggle {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-calc-btn {\n background: rgba(168, 85, 247, 0.15);\n color: #c084fc;\n border-color: rgba(168, 85, 247, 0.3);\n}\n\n.vpg-theme-dark .vpg-calc-btn:hover {\n background: rgba(168, 85, 247, 0.25);\n border-color: rgba(168, 85, 247, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-list::-webkit-scrollbar-thumb {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-config .vpg-field-list::-webkit-scrollbar-thumb:hover {\n background: #475569;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type { AggregationFunction, CalculatedField, PivotResult, PivotValueField } from '@smallwebco/tinypivot-core'\nimport { getAggregationLabel, getAggregationSymbol } from '@smallwebco/tinypivot-core'\n/**\n * Pivot Table Skeleton + Data Display\n * Visual layout for pivot configuration and results\n */\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\nimport { useLicense } from '../composables/useLicense'\n\ninterface ActiveFilter {\n column: string\n valueCount: number\n values?: string[]\n displayText?: string\n isRange?: boolean\n}\n\nconst props = defineProps<{\n rowFields: string[]\n columnFields: string[]\n valueFields: PivotValueField[]\n calculatedFields?: CalculatedField[]\n isConfigured: boolean\n draggingField: string | null\n pivotResult: PivotResult | null\n fontSize?: 'xs' | 'sm' | 'base'\n activeFilters?: ActiveFilter[] | null\n totalRowCount?: number\n filteredRowCount?: number\n}>()\n\nconst emit = defineEmits<{\n (e: 'addRowField', field: string): void\n (e: 'removeRowField', field: string): void\n (e: 'addColumnField', field: string): void\n (e: 'removeColumnField', field: string): void\n (e: 'addValueField', field: string, aggregation: AggregationFunction): void\n (e: 'removeValueField', field: string, aggregation: AggregationFunction): void\n (e: 'updateAggregation', field: string, oldAgg: AggregationFunction, newAgg: AggregationFunction): void\n (e: 'reorderRowFields', fields: string[]): void\n (e: 'reorderColumnFields', fields: string[]): void\n}>()\n\n// Helper to get display name for value fields (resolves calc IDs to names)\nfunction getValueFieldDisplayName(field: string): string {\n if (field.startsWith('calc:')) {\n const calcId = field.replace('calc:', '')\n const calcField = props.calculatedFields?.find(c => c.id === calcId)\n return calcField?.name || field\n }\n return field\n}\n\n// Helper to check if field is a calculated field\nfunction isCalculatedField(field: string): boolean {\n return field.startsWith('calc:')\n}\n\nconst { showWatermark, canUsePivot, isDemo } = useLicense()\n\n// Drag state\nconst dragOverArea = ref<'row' | 'column' | 'value' | null>(null)\n\n// Reorder drag state\nconst reorderDragSource = ref<{ zone: 'row' | 'column', index: number } | null>(null)\nconst reorderDropTarget = ref<{ zone: 'row' | 'column', index: number } | null>(null)\n\n// Use getAggregationLabel and getAggregationSymbol from core\n\n// Font size\nconst currentFontSize = ref(props.fontSize || 'xs')\nconst fontSizeOptions = [\n { value: 'xs', label: 'S' },\n { value: 'sm', label: 'M' },\n { value: 'base', label: 'L' },\n] as const\n\n// Filter status\nconst hasActiveFilters = computed(() => props.activeFilters && props.activeFilters.length > 0)\nconst filterSummary = computed(() => {\n if (!props.activeFilters || props.activeFilters.length === 0)\n return ''\n const columns = props.activeFilters.map(f => f.column).join(', ')\n return columns\n})\n\n// Detailed filter tooltip\nconst filterTooltipDetails = computed(() => {\n if (!props.activeFilters || props.activeFilters.length === 0)\n return []\n return props.activeFilters.map((f) => {\n // Handle range filters\n if (f.isRange && f.displayText) {\n return {\n column: f.column,\n displayText: f.displayText,\n isRange: true,\n values: [],\n remaining: 0,\n }\n }\n // Handle value filters\n const values = f.values || []\n const maxDisplay = 5\n const displayValues = values.slice(0, maxDisplay)\n const remaining = values.length - maxDisplay\n return {\n column: f.column,\n values: displayValues,\n remaining: remaining > 0 ? remaining : 0,\n isRange: false,\n }\n })\n})\n\n// Show/hide tooltip\nconst showFilterTooltip = ref(false)\n\n// Sorting\ntype SortDirection = 'asc' | 'desc'\ntype SortTarget = 'row' | number\nconst sortDirection = ref<SortDirection>('asc')\nconst sortTarget = ref<SortTarget>('row')\n\nfunction toggleSort(target: SortTarget = 'row') {\n if (sortTarget.value === target) {\n sortDirection.value = sortDirection.value === 'asc' ? 'desc' : 'asc'\n }\n else {\n sortTarget.value = target\n sortDirection.value = 'asc'\n }\n}\n\n// Sorted row indices\nconst sortedRowIndices = computed(() => {\n if (!props.pivotResult)\n return []\n\n const indices = props.pivotResult.rowHeaders.map((_, i) => i)\n const headers = props.pivotResult.rowHeaders\n const data = props.pivotResult.data\n\n indices.sort((a, b) => {\n let cmp: number\n\n if (sortTarget.value === 'row') {\n const aHeader = headers[a]?.join(' / ') || ''\n const bHeader = headers[b]?.join(' / ') || ''\n cmp = aHeader.localeCompare(bHeader, undefined, { numeric: true, sensitivity: 'base' })\n }\n else {\n const colIdx = sortTarget.value as number\n const aVal = data[a]?.[colIdx]?.value ?? null\n const bVal = data[b]?.[colIdx]?.value ?? null\n\n if (aVal === null && bVal === null)\n cmp = 0\n else if (aVal === null)\n cmp = 1\n else if (bVal === null)\n cmp = -1\n else cmp = aVal - bVal\n }\n\n return sortDirection.value === 'asc' ? cmp : -cmp\n })\n\n return indices\n})\n\n// Column headers\nconst columnHeaderCells = computed(() => {\n if (!props.pivotResult || props.pivotResult.headers.length === 0) {\n return [props.valueFields.map(vf => ({\n label: isCalculatedField(vf.field)\n ? `${getValueFieldDisplayName(vf.field)} (${getAggregationLabel(vf.aggregation)})`\n : `${vf.field} (${getAggregationLabel(vf.aggregation)})`,\n colspan: 1,\n }))]\n }\n\n const result: Array<Array<{ label: string, colspan: number }>> = []\n\n for (let level = 0; level < props.pivotResult.headers.length; level++) {\n const headerRow = props.pivotResult.headers[level]\n const cells: Array<{ label: string, colspan: number }> = []\n\n let i = 0\n while (i < headerRow.length) {\n const value = headerRow[i]\n let colspan = 1\n\n while (i + colspan < headerRow.length && headerRow[i + colspan] === value) {\n colspan++\n }\n\n cells.push({ label: value, colspan })\n i += colspan\n }\n\n result.push(cells)\n }\n\n return result\n})\n\n// Selection for copy support with drag\nconst selectedCell = ref<{ row: number, col: number } | null>(null)\nconst selectionStart = ref<{ row: number, col: number } | null>(null)\nconst selectionEnd = ref<{ row: number, col: number } | null>(null)\nconst isSelecting = ref(false)\nconst showCopyToast = ref(false)\nconst copyToastMessage = ref('')\n\nconst selectionBounds = computed(() => {\n if (!selectionStart.value || !selectionEnd.value)\n return null\n return {\n minRow: Math.min(selectionStart.value.row, selectionEnd.value.row),\n maxRow: Math.max(selectionStart.value.row, selectionEnd.value.row),\n minCol: Math.min(selectionStart.value.col, selectionEnd.value.col),\n maxCol: Math.max(selectionStart.value.col, selectionEnd.value.col),\n }\n})\n\nfunction handleCellMouseDown(rowIndex: number, colIndex: number, event: MouseEvent) {\n event.preventDefault()\n\n if (event.shiftKey && selectedCell.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n else {\n selectedCell.value = { row: rowIndex, col: colIndex }\n selectionStart.value = { row: rowIndex, col: colIndex }\n selectionEnd.value = { row: rowIndex, col: colIndex }\n isSelecting.value = true\n }\n}\n\nfunction handleCellMouseEnter(rowIndex: number, colIndex: number) {\n if (isSelecting.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n}\n\nfunction handleMouseUp() {\n isSelecting.value = false\n}\n\nfunction isCellSelected(rowIndex: number, colIndex: number): boolean {\n if (!selectionBounds.value) {\n return selectedCell.value?.row === rowIndex && selectedCell.value?.col === colIndex\n }\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n return rowIndex >= minRow && rowIndex <= maxRow && colIndex >= minCol && colIndex <= maxCol\n}\n\nfunction copySelectionToClipboard() {\n if (!selectionBounds.value || !props.pivotResult)\n return\n\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n const lines: string[] = []\n\n for (let r = minRow; r <= maxRow; r++) {\n const sortedIdx = sortedRowIndices.value[r]\n if (sortedIdx === undefined)\n continue\n\n const rowValues: string[] = []\n for (let c = minCol; c <= maxCol; c++) {\n const cell = props.pivotResult.data[sortedIdx]?.[c]\n rowValues.push(cell?.formattedValue ?? '')\n }\n lines.push(rowValues.join('\\t'))\n }\n\n const text = lines.join('\\n')\n\n navigator.clipboard.writeText(text).then(() => {\n const cellCount = (maxRow - minRow + 1) * (maxCol - minCol + 1)\n copyToastMessage.value = `Copied ${cellCount} cell${cellCount > 1 ? 's' : ''}`\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n }).catch((err) => {\n console.error('Copy failed:', err)\n })\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n // Only handle if pivot has focus or selection\n if (!selectionBounds.value)\n return\n\n if ((event.ctrlKey || event.metaKey) && event.key === 'c') {\n event.preventDefault()\n copySelectionToClipboard()\n return\n }\n\n if (event.key === 'Escape') {\n selectedCell.value = null\n selectionStart.value = null\n selectionEnd.value = null\n }\n}\n\n// Selection statistics for the footer\nconst selectionStats = computed(() => {\n if (!selectionBounds.value || !props.pivotResult)\n return null\n\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n const values: number[] = []\n let count = 0\n\n for (let r = minRow; r <= maxRow; r++) {\n const sortedIdx = sortedRowIndices.value[r]\n if (sortedIdx === undefined)\n continue\n\n for (let c = minCol; c <= maxCol; c++) {\n const cell = props.pivotResult.data[sortedIdx]?.[c]\n count++\n if (cell?.value !== null && cell?.value !== undefined && typeof cell.value === 'number') {\n values.push(cell.value)\n }\n }\n }\n\n if (count <= 1)\n return null\n\n const sum = values.reduce((a, b) => a + b, 0)\n const avg = values.length > 0 ? sum / values.length : 0\n\n return {\n count,\n numericCount: values.length,\n sum,\n avg,\n }\n})\n\nfunction formatStatValue(val: number): string {\n if (Math.abs(val) >= 1_000_000)\n return `${(val / 1_000_000).toFixed(2)}M`\n if (Math.abs(val) >= 1_000)\n return `${(val / 1_000).toFixed(2)}K`\n return val.toFixed(2)\n}\n\n// Lifecycle hooks for event listeners\nonMounted(() => {\n document.addEventListener('mouseup', handleMouseUp)\n document.addEventListener('keydown', handleKeydown)\n})\n\nonUnmounted(() => {\n document.removeEventListener('mouseup', handleMouseUp)\n document.removeEventListener('keydown', handleKeydown)\n})\n\n// Drag handlers\nfunction handleDragOver(area: 'row' | 'column' | 'value', event: DragEvent) {\n event.preventDefault()\n event.dataTransfer!.dropEffect = 'move'\n dragOverArea.value = area\n}\n\nfunction handleDragLeave() {\n dragOverArea.value = null\n}\n\nfunction handleDrop(area: 'row' | 'column' | 'value', event: DragEvent) {\n event.preventDefault()\n const field = event.dataTransfer?.getData('text/plain')\n\n // Skip if this is a reorder operation (handled by chip drop)\n if (!field || field.startsWith('reorder:')) {\n dragOverArea.value = null\n return\n }\n\n if (props.rowFields.includes(field))\n emit('removeRowField', field)\n if (props.columnFields.includes(field))\n emit('removeColumnField', field)\n const existingValue = props.valueFields.find(v => v.field === field)\n if (existingValue)\n emit('removeValueField', field, existingValue.aggregation)\n\n switch (area) {\n case 'row':\n emit('addRowField', field)\n break\n case 'column':\n emit('addColumnField', field)\n break\n case 'value':\n emit('addValueField', field, 'sum')\n break\n }\n dragOverArea.value = null\n}\n\n// Reorder handlers for chips within zones\nfunction handleChipDragStart(zone: 'row' | 'column', index: number, event: DragEvent) {\n reorderDragSource.value = { zone, index }\n event.dataTransfer!.effectAllowed = 'move'\n event.dataTransfer!.setData('text/plain', `reorder:${zone}:${index}`)\n // Add a slight delay to ensure visual feedback\n requestAnimationFrame(() => {\n dragOverArea.value = null\n })\n}\n\nfunction handleChipDragEnd() {\n reorderDragSource.value = null\n reorderDropTarget.value = null\n}\n\nfunction handleChipDragOver(zone: 'row' | 'column', index: number, event: DragEvent) {\n event.preventDefault()\n // Only handle reorder within same zone\n if (reorderDragSource.value && reorderDragSource.value.zone === zone) {\n event.dataTransfer!.dropEffect = 'move'\n reorderDropTarget.value = { zone, index }\n }\n}\n\nfunction handleChipDragLeave() {\n reorderDropTarget.value = null\n}\n\nfunction handleChipDrop(zone: 'row' | 'column', targetIndex: number, event: DragEvent) {\n event.preventDefault()\n event.stopPropagation()\n\n if (!reorderDragSource.value || reorderDragSource.value.zone !== zone) {\n return\n }\n\n const sourceIndex = reorderDragSource.value.index\n if (sourceIndex === targetIndex) {\n reorderDragSource.value = null\n reorderDropTarget.value = null\n return\n }\n\n // Create reordered array\n const fields = zone === 'row' ? [...props.rowFields] : [...props.columnFields]\n const [movedField] = fields.splice(sourceIndex, 1)\n fields.splice(targetIndex, 0, movedField)\n\n // Emit reorder event\n if (zone === 'row') {\n emit('reorderRowFields', fields)\n }\n else {\n emit('reorderColumnFields', fields)\n }\n\n reorderDragSource.value = null\n reorderDropTarget.value = null\n}\n\nfunction isChipDragSource(zone: 'row' | 'column', index: number): boolean {\n return reorderDragSource.value?.zone === zone && reorderDragSource.value?.index === index\n}\n\nfunction isChipDropTarget(zone: 'row' | 'column', index: number): boolean {\n return reorderDropTarget.value?.zone === zone && reorderDropTarget.value?.index === index\n}\n\n// Column width\nconst rowHeaderWidth = ref(180)\nconst dataColWidth = ref(80)\n\n// Calculate width per row header column\nconst rowHeaderColWidth = computed(() => {\n const numCols = Math.max(props.rowFields.length, 1)\n return Math.max(rowHeaderWidth.value / numCols, 80)\n})\n\n// Calculate left offset for each row header column (for sticky positioning)\nfunction getRowHeaderLeftOffset(fieldIdx: number): number {\n return fieldIdx * rowHeaderColWidth.value\n}\n</script>\n\n<template>\n <div\n class=\"vpg-pivot-skeleton\"\n :class=\"[\n `vpg-font-${currentFontSize}`,\n { 'vpg-is-dragging': draggingField },\n ]\"\n >\n <!-- Copy Toast -->\n <Transition name=\"vpg-toast\">\n <div v-if=\"showCopyToast\" class=\"vpg-toast\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n {{ copyToastMessage }}\n </div>\n </Transition>\n\n <!-- Header Bar -->\n <div class=\"vpg-skeleton-header\">\n <div class=\"vpg-skeleton-title\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\" />\n </svg>\n <span>Pivot Table</span>\n </div>\n\n <div class=\"vpg-header-right\">\n <!-- Filter indicator with tooltip -->\n <div\n v-if=\"hasActiveFilters\"\n class=\"vpg-filter-indicator\"\n @mouseenter=\"showFilterTooltip = true\"\n @mouseleave=\"showFilterTooltip = false\"\n >\n <svg class=\"vpg-filter-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n <span class=\"vpg-filter-text\">\n Filtered: <strong>{{ filterSummary }}</strong>\n <span v-if=\"filteredRowCount !== undefined && totalRowCount !== undefined\" class=\"vpg-filter-count\">\n ({{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} rows)\n </span>\n </span>\n\n <!-- Tooltip -->\n <div v-if=\"showFilterTooltip\" class=\"vpg-filter-tooltip\">\n <div class=\"vpg-tooltip-header\">\n Active Filters\n </div>\n <div v-for=\"filter in filterTooltipDetails\" :key=\"filter.column\" class=\"vpg-tooltip-filter\">\n <div class=\"vpg-tooltip-column\">\n {{ filter.column }}\n </div>\n <div class=\"vpg-tooltip-values\">\n <!-- Range filter display -->\n <template v-if=\"filter.isRange\">\n <span class=\"vpg-tooltip-value vpg-range-value\">{{ filter.displayText }}</span>\n </template>\n <!-- Value filter display -->\n <template v-else>\n <span v-for=\"(val, idx) in filter.values\" :key=\"idx\" class=\"vpg-tooltip-value\">\n {{ val }}\n </span>\n <span v-if=\"filter.remaining > 0\" class=\"vpg-tooltip-more\">\n +{{ filter.remaining }} more\n </span>\n </template>\n </div>\n </div>\n <div v-if=\"filteredRowCount !== undefined && totalRowCount !== undefined\" class=\"vpg-tooltip-summary\">\n Showing {{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} rows\n </div>\n </div>\n </div>\n\n <div v-if=\"isConfigured\" class=\"vpg-config-summary\">\n <span class=\"vpg-summary-badge vpg-rows\">{{ rowFields.length }} row{{ rowFields.length !== 1 ? 's' : '' }}</span>\n <span class=\"vpg-summary-badge vpg-cols\">{{ columnFields.length }} col{{ columnFields.length !== 1 ? 's' : '' }}</span>\n <span class=\"vpg-summary-badge vpg-vals\">{{ valueFields.length }} val{{ valueFields.length !== 1 ? 's' : '' }}</span>\n </div>\n\n <div v-if=\"isConfigured && pivotResult\" class=\"vpg-font-size-toggle\">\n <button\n v-for=\"opt in fontSizeOptions\"\n :key=\"opt.value\"\n class=\"vpg-font-size-btn\"\n :class=\"{ active: currentFontSize === opt.value }\"\n @click=\"currentFontSize = opt.value\"\n >\n {{ opt.label }}\n </button>\n </div>\n </div>\n </div>\n\n <!-- License Required Message -->\n <div v-if=\"!canUsePivot\" class=\"vpg-pro-required\">\n <div class=\"vpg-pro-content\">\n <svg class=\"vpg-pro-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n <h3>Pro Feature</h3>\n <p>Pivot Table functionality requires a Pro license.</p>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" class=\"vpg-pro-link\">\n Get Pro License →\n </a>\n </div>\n </div>\n\n <!-- Content when licensed -->\n <template v-else>\n <!-- Config Bar -->\n <div class=\"vpg-config-bar\">\n <!-- Row drop zone -->\n <div\n class=\"vpg-drop-zone vpg-row-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'row' }\"\n @dragover=\"handleDragOver('row', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('row', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-row-icon\">↓</span>\n <span class=\"vpg-zone-label\">Rows</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"(field, idx) in rowFields\"\n :key=\"field\"\n class=\"vpg-mini-chip vpg-row-chip\"\n :class=\"{\n 'vpg-chip-dragging': isChipDragSource('row', idx),\n 'vpg-chip-drop-target': isChipDropTarget('row', idx),\n }\"\n draggable=\"true\"\n @dragstart=\"handleChipDragStart('row', idx, $event)\"\n @dragend=\"handleChipDragEnd\"\n @dragover=\"handleChipDragOver('row', idx, $event)\"\n @dragleave=\"handleChipDragLeave\"\n @drop=\"handleChipDrop('row', idx, $event)\"\n >\n <span class=\"vpg-drag-handle\">⋮⋮</span>\n <span class=\"vpg-mini-name\">{{ field }}</span>\n <button class=\"vpg-mini-remove\" @click.stop=\"emit('removeRowField', field)\">\n ×\n </button>\n </div>\n <span v-if=\"rowFields.length === 0\" class=\"vpg-zone-hint\">Drop here</span>\n </div>\n </div>\n\n <!-- Column drop zone -->\n <div\n class=\"vpg-drop-zone vpg-column-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'column' }\"\n @dragover=\"handleDragOver('column', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('column', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-column-icon\">→</span>\n <span class=\"vpg-zone-label\">Columns</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"(field, idx) in columnFields\"\n :key=\"field\"\n class=\"vpg-mini-chip vpg-column-chip\"\n :class=\"{\n 'vpg-chip-dragging': isChipDragSource('column', idx),\n 'vpg-chip-drop-target': isChipDropTarget('column', idx),\n }\"\n draggable=\"true\"\n @dragstart=\"handleChipDragStart('column', idx, $event)\"\n @dragend=\"handleChipDragEnd\"\n @dragover=\"handleChipDragOver('column', idx, $event)\"\n @dragleave=\"handleChipDragLeave\"\n @drop=\"handleChipDrop('column', idx, $event)\"\n >\n <span class=\"vpg-drag-handle\">⋮⋮</span>\n <span class=\"vpg-mini-name\">{{ field }}</span>\n <button class=\"vpg-mini-remove\" @click.stop=\"emit('removeColumnField', field)\">\n ×\n </button>\n </div>\n <span v-if=\"columnFields.length === 0\" class=\"vpg-zone-hint\">Drop here</span>\n </div>\n </div>\n\n <!-- Values drop zone -->\n <div\n class=\"vpg-drop-zone vpg-value-zone\"\n :class=\"{ 'vpg-drag-over': dragOverArea === 'value' }\"\n @dragover=\"handleDragOver('value', $event)\"\n @dragleave=\"handleDragLeave\"\n @drop=\"handleDrop('value', $event)\"\n >\n <div class=\"vpg-zone-header\">\n <span class=\"vpg-zone-icon vpg-value-icon\">Σ</span>\n <span class=\"vpg-zone-label\">Values</span>\n </div>\n <div class=\"vpg-zone-chips\">\n <div\n v-for=\"vf in valueFields\"\n :key=\"`${vf.field}-${vf.aggregation}`\"\n class=\"vpg-mini-chip vpg-value-chip\"\n :class=\"{ 'vpg-calc-chip': isCalculatedField(vf.field) }\"\n >\n <span class=\"vpg-agg-symbol\">{{ isCalculatedField(vf.field) ? 'ƒ' : getAggregationSymbol(vf.aggregation) }}</span>\n <span class=\"vpg-mini-name\">{{ getValueFieldDisplayName(vf.field) }}</span>\n <button class=\"vpg-mini-remove\" @click=\"emit('removeValueField', vf.field, vf.aggregation)\">\n ×\n </button>\n </div>\n <span v-if=\"valueFields.length === 0\" class=\"vpg-zone-hint\">Drop numeric</span>\n </div>\n </div>\n </div>\n\n <!-- Placeholder when not configured -->\n <div v-if=\"!isConfigured || !pivotResult\" class=\"vpg-placeholder\">\n <div class=\"vpg-placeholder-content\">\n <svg class=\"vpg-placeholder-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n <span class=\"vpg-placeholder-text\">\n <template v-if=\"valueFields.length === 0\">\n Add a <strong>Values</strong> field to see your pivot table\n </template>\n <template v-else-if=\"rowFields.length === 0 && columnFields.length === 0\">\n Add <strong>Row</strong> or <strong>Column</strong> fields to group your data\n </template>\n <template v-else>\n Your pivot table will appear here\n </template>\n </span>\n </div>\n </div>\n\n <!-- Data Table -->\n <div v-else class=\"vpg-table-container\">\n <table class=\"vpg-pivot-table\">\n <thead>\n <tr v-for=\"(headerRow, levelIdx) in columnHeaderCells\" :key=\"`header-${levelIdx}`\" class=\"vpg-column-header-row\">\n <template v-if=\"levelIdx === 0\">\n <th\n v-for=\"(field, fieldIdx) in (rowFields.length > 0 ? rowFields : ['Rows'])\"\n :key=\"`row-header-${fieldIdx}`\"\n class=\"vpg-row-header-label\"\n :rowspan=\"columnHeaderCells.length\"\n :style=\"{ width: `${rowHeaderColWidth}px`, minWidth: '80px', left: `${getRowHeaderLeftOffset(fieldIdx)}px` }\"\n @click=\"toggleSort('row')\"\n >\n <div class=\"vpg-header-content\">\n <span>{{ field }}</span>\n <span v-if=\"fieldIdx === rowFields.length - 1 || rowFields.length === 0\" class=\"vpg-sort-indicator\" :class=\"{ active: sortTarget === 'row' }\">\n {{ sortTarget === 'row' ? (sortDirection === 'asc' ? '↑' : '↓') : '⇅' }}\n </span>\n </div>\n </th>\n </template>\n <th\n v-for=\"(cell, idx) in headerRow\"\n :key=\"idx\"\n class=\"vpg-column-header-cell\"\n :colspan=\"cell.colspan\"\n :style=\"{ width: `${dataColWidth * cell.colspan}px` }\"\n @click=\"levelIdx === columnHeaderCells.length - 1 && toggleSort(idx)\"\n >\n <div class=\"vpg-header-content\">\n <span>{{ cell.label }}</span>\n <span v-if=\"levelIdx === columnHeaderCells.length - 1\" class=\"vpg-sort-indicator\" :class=\"{ active: sortTarget === idx }\">\n {{ sortTarget === idx ? (sortDirection === 'asc' ? '↑' : '↓') : '⇅' }}\n </span>\n </div>\n </th>\n <th\n v-if=\"pivotResult.rowTotals.length > 0 && levelIdx === 0\"\n class=\"vpg-total-header\"\n :rowspan=\"columnHeaderCells.length\"\n >\n Total\n </th>\n </tr>\n </thead>\n\n <tbody>\n <tr v-for=\"sortedIdx in sortedRowIndices\" :key=\"sortedIdx\" class=\"vpg-data-row\">\n <th\n v-for=\"(val, idx) in pivotResult.rowHeaders[sortedIdx]\"\n :key=\"`row-${sortedIdx}-${idx}`\"\n class=\"vpg-row-header-cell\"\n :style=\"{ width: `${rowHeaderColWidth}px`, minWidth: '80px', left: `${getRowHeaderLeftOffset(idx)}px` }\"\n >\n {{ val }}\n </th>\n\n <td\n v-for=\"(cell, colIdx) in pivotResult.data[sortedIdx]\"\n :key=\"colIdx\"\n class=\"vpg-data-cell\"\n :class=\"[\n isCellSelected(sortedRowIndices.indexOf(sortedIdx), colIdx) && 'selected',\n cell.value === null && 'vpg-is-null',\n ]\"\n :style=\"{ width: `${dataColWidth}px` }\"\n @mousedown=\"handleCellMouseDown(sortedRowIndices.indexOf(sortedIdx), colIdx, $event)\"\n @mouseenter=\"handleCellMouseEnter(sortedRowIndices.indexOf(sortedIdx), colIdx)\"\n >\n {{ cell.formattedValue }}\n </td>\n\n <td v-if=\"pivotResult.rowTotals[sortedIdx]\" class=\"vpg-data-cell vpg-total-cell\">\n {{ pivotResult.rowTotals[sortedIdx].formattedValue }}\n </td>\n </tr>\n\n <tr v-if=\"pivotResult.columnTotals.length > 0\" class=\"vpg-totals-row\">\n <th\n class=\"vpg-row-header-cell vpg-total-label\"\n :colspan=\"Math.max(rowFields.length, 1)\"\n :style=\"{ width: `${rowHeaderWidth}px` }\"\n >\n Total\n </th>\n <td\n v-for=\"(cell, colIdx) in pivotResult.columnTotals\"\n :key=\"colIdx\"\n class=\"vpg-data-cell vpg-total-cell\"\n :style=\"{ width: `${dataColWidth}px` }\"\n >\n {{ cell.formattedValue }}\n </td>\n <td v-if=\"pivotResult.rowTotals.length > 0\" class=\"vpg-data-cell vpg-grand-total-cell\">\n {{ pivotResult.grandTotal.formattedValue }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Footer -->\n <div v-if=\"isConfigured && pivotResult\" class=\"vpg-skeleton-footer\">\n <span class=\"vpg-footer-info\">{{ pivotResult.rowHeaders.length }} rows × {{ pivotResult.data[0]?.length || 0 }} columns</span>\n\n <div v-if=\"selectionStats && selectionStats.count > 1\" class=\"vpg-selection-stats\">\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Count:</span>\n <span class=\"vpg-stat-value\">{{ selectionStats.count }}</span>\n </span>\n <template v-if=\"selectionStats.numericCount > 0\">\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Sum:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.sum) }}</span>\n </span>\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Avg:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.avg) }}</span>\n </span>\n </template>\n </div>\n </div>\n </template>\n\n <!-- Watermark / Demo Banner -->\n <div v-if=\"showWatermark && canUsePivot\" class=\"vpg-watermark\" :class=\"{ 'vpg-demo-mode': isDemo }\">\n <template v-if=\"isDemo\">\n <span class=\"vpg-demo-badge\">DEMO</span>\n <span>Pro features unlocked for evaluation</span>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" rel=\"noopener\" class=\"vpg-get-pro\">\n Get Pro License →\n </a>\n </template>\n <template v-else>\n <a href=\"https://tiny-pivot.com\" target=\"_blank\" rel=\"noopener\">\n Powered by TinyPivot\n </a>\n </template>\n </div>\n </div>\n</template>\n\n<style scoped>\n.vpg-pivot-skeleton {\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.75rem;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n height: 100%;\n}\n\n.vpg-pivot-skeleton.vpg-is-dragging {\n box-shadow: 0 0 0 2px #10b981;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n/* Header */\n.vpg-skeleton-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-skeleton-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-header-right {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\n\n.vpg-config-summary {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.vpg-summary-badge {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n font-weight: 600;\n border-radius: 0.25rem;\n}\n\n.vpg-summary-badge.vpg-rows {\n background: #e0e7ff;\n color: #4f46e5;\n}\n\n.vpg-summary-badge.vpg-cols {\n background: #ede9fe;\n color: #7c3aed;\n}\n\n.vpg-summary-badge.vpg-vals {\n background: #d1fae5;\n color: #059669;\n}\n\n/* Filter indicator */\n.vpg-filter-indicator {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.625rem;\n background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);\n border: 1px solid #f59e0b;\n border-radius: 0.375rem;\n font-size: 0.6875rem;\n color: #92400e;\n box-shadow: 0 1px 2px rgba(245, 158, 11, 0.15);\n cursor: help;\n}\n\n.vpg-filter-icon {\n width: 0.875rem;\n height: 0.875rem;\n flex-shrink: 0;\n color: #d97706;\n}\n\n.vpg-filter-text {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n white-space: nowrap;\n}\n\n.vpg-filter-text strong {\n font-weight: 600;\n color: #78350f;\n max-width: 150px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.vpg-filter-count {\n color: #a16207;\n font-size: 0.625rem;\n}\n\n/* Filter tooltip */\n.vpg-filter-tooltip {\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n min-width: 220px;\n max-width: 320px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.5rem;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.15), 0 8px 10px -6px rgba(0, 0, 0, 0.1);\n z-index: 100;\n overflow: hidden;\n}\n\n.vpg-tooltip-header {\n padding: 0.5rem 0.75rem;\n font-size: 0.6875rem;\n font-weight: 700;\n color: #475569;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-tooltip-filter {\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid #f1f5f9;\n}\n\n.vpg-tooltip-filter:last-of-type {\n border-bottom: none;\n}\n\n.vpg-tooltip-column {\n font-size: 0.6875rem;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 0.375rem;\n}\n\n.vpg-tooltip-values {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n}\n\n.vpg-tooltip-value {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n background: #fef3c7;\n color: #92400e;\n border-radius: 0.25rem;\n border: 1px solid #fde68a;\n}\n\n.vpg-tooltip-more {\n padding: 0.125rem 0.375rem;\n font-size: 0.625rem;\n color: #64748b;\n font-style: italic;\n}\n\n.vpg-tooltip-summary {\n padding: 0.5rem 0.75rem;\n font-size: 0.625rem;\n color: #64748b;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n text-align: center;\n}\n\n.vpg-font-size-toggle {\n display: flex;\n background: white;\n border-radius: 0.25rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n}\n\n.vpg-font-size-btn {\n padding: 0.125rem 0.5rem;\n font-size: 0.625rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-font-size-btn:hover {\n background: #f1f5f9;\n}\n\n.vpg-font-size-btn.active {\n background: #10b981;\n color: white;\n}\n\n/* Pro Required */\n.vpg-pro-required {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n}\n\n.vpg-pro-content {\n text-align: center;\n padding: 2rem;\n}\n\n.vpg-pro-icon {\n width: 3rem;\n height: 3rem;\n color: #d97706;\n margin: 0 auto 1rem;\n}\n\n.vpg-pro-content h3 {\n font-size: 1.25rem;\n font-weight: 600;\n color: #92400e;\n margin-bottom: 0.5rem;\n}\n\n.vpg-pro-content p {\n font-size: 0.875rem;\n color: #a16207;\n margin-bottom: 1rem;\n}\n\n.vpg-pro-link {\n display: inline-block;\n padding: 0.5rem 1rem;\n background: #f59e0b;\n color: white;\n font-weight: 500;\n border-radius: 0.375rem;\n text-decoration: none;\n transition: background 0.15s;\n}\n\n.vpg-pro-link:hover {\n background: #d97706;\n}\n\n/* Config Bar */\n.vpg-config-bar {\n display: flex;\n align-items: stretch;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-drop-zone {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n border-radius: 0.5rem;\n border: 2px dashed;\n transition: all 0.15s;\n}\n\n.vpg-drop-zone.vpg-row-zone {\n background: rgba(238, 242, 255, 0.5);\n border-color: #c7d2fe;\n}\n\n.vpg-drop-zone.vpg-column-zone {\n background: rgba(245, 243, 255, 0.5);\n border-color: #ddd6fe;\n flex: 1;\n}\n\n.vpg-drop-zone.vpg-value-zone {\n background: rgba(236, 253, 245, 0.5);\n border-color: #a7f3d0;\n}\n\n.vpg-drop-zone.vpg-drag-over {\n border-style: solid;\n box-shadow: 0 0 0 2px currentColor inset;\n}\n\n.vpg-drop-zone.vpg-row-zone.vpg-drag-over {\n background: #eef2ff;\n border-color: #818cf8;\n}\n\n.vpg-drop-zone.vpg-column-zone.vpg-drag-over {\n background: #f5f3ff;\n border-color: #a78bfa;\n}\n\n.vpg-drop-zone.vpg-value-zone.vpg-drag-over {\n background: #ecfdf5;\n border-color: #34d399;\n}\n\n.vpg-zone-header {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n flex-shrink: 0;\n}\n\n.vpg-zone-icon {\n width: 1.25rem;\n height: 1.25rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.75rem;\n font-weight: 700;\n border-radius: 0.25rem;\n}\n\n.vpg-zone-icon.vpg-row-icon {\n background: #c7d2fe;\n color: #4338ca;\n}\n\n.vpg-zone-icon.vpg-column-icon {\n background: #ddd6fe;\n color: #7c3aed;\n}\n\n.vpg-zone-icon.vpg-value-icon {\n background: #a7f3d0;\n color: #059669;\n}\n\n.vpg-zone-label {\n font-size: 0.625rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.vpg-row-zone .vpg-zone-label {\n color: #4f46e5;\n}\n\n.vpg-column-zone .vpg-zone-label {\n color: #7c3aed;\n}\n\n.vpg-value-zone .vpg-zone-label {\n color: #059669;\n}\n\n.vpg-zone-chips {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-zone-hint {\n font-size: 0.625rem;\n color: #94a3b8;\n font-style: italic;\n}\n\n.vpg-mini-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.25rem 0.5rem;\n border-radius: 0.25rem;\n font-size: 0.625rem;\n font-weight: 500;\n max-width: 100%;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n cursor: grab;\n transition: all 0.15s ease;\n}\n\n.vpg-mini-chip:active {\n cursor: grabbing;\n}\n\n.vpg-drag-handle {\n opacity: 0.3;\n font-size: 0.625rem;\n letter-spacing: -0.1em;\n margin-right: 0.125rem;\n cursor: grab;\n flex-shrink: 0;\n}\n\n.vpg-mini-chip:hover .vpg-drag-handle {\n opacity: 0.6;\n}\n\n.vpg-mini-chip.vpg-chip-dragging {\n opacity: 0.4;\n transform: scale(0.95);\n}\n\n.vpg-mini-chip.vpg-chip-drop-target {\n transform: translateX(4px);\n box-shadow: -3px 0 0 0 currentColor, 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-mini-chip.vpg-row-chip {\n background: white;\n color: #4338ca;\n border: 1px solid #c7d2fe;\n}\n\n.vpg-mini-chip.vpg-column-chip {\n background: white;\n color: #7c3aed;\n border: 1px solid #ddd6fe;\n}\n\n.vpg-mini-chip.vpg-value-chip {\n background: white;\n color: #059669;\n border: 1px solid #a7f3d0;\n}\n\n.vpg-mini-chip.vpg-value-chip.vpg-calc-chip {\n background: #fdf4ff;\n color: #86198f;\n border-color: #f0abfc;\n}\n\n.vpg-mini-chip.vpg-value-chip.vpg-calc-chip .vpg-agg-symbol {\n background: #f0abfc;\n color: #86198f;\n}\n\n.vpg-mini-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n}\n\n.vpg-mini-remove {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.875rem;\n line-height: 1;\n opacity: 0.4;\n flex-shrink: 0;\n background: transparent;\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-mini-remove:hover {\n opacity: 1;\n background: #fee2e2;\n color: #ef4444;\n}\n\n.vpg-agg-symbol {\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.625rem;\n font-weight: 700;\n background: #d1fae5;\n color: #059669;\n border-radius: 0.25rem;\n flex-shrink: 0;\n}\n\n/* Placeholder */\n.vpg-placeholder {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n background: linear-gradient(135deg, #f8fafc, white, rgba(236, 253, 245, 0.3));\n border-top: 1px solid #f1f5f9;\n}\n\n.vpg-placeholder-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n text-align: center;\n padding: 2rem;\n}\n\n.vpg-placeholder-icon {\n width: 4rem;\n height: 4rem;\n color: #cbd5e1;\n}\n\n.vpg-placeholder-text {\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-placeholder-text strong {\n color: #334155;\n font-weight: 600;\n}\n\n/* Table */\n.vpg-table-container {\n flex: 1;\n overflow: auto;\n max-height: 100%;\n isolation: isolate;\n}\n\n.vpg-pivot-table {\n border-collapse: collapse;\n table-layout: fixed;\n min-width: max-content;\n}\n\n.vpg-pivot-table thead {\n position: sticky;\n top: 0;\n z-index: 30;\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);\n}\n\n.vpg-column-header-row {\n background: #f8fafc;\n}\n\n.vpg-column-header-row th {\n background: #f8fafc;\n}\n\n.vpg-row-header-label {\n position: sticky;\n /* left is set dynamically via inline style for multi-column row headers */\n z-index: 30;\n padding: 0.5rem 0.75rem;\n text-align: left;\n font-size: 0.625rem;\n font-weight: 600;\n color: #64748b;\n text-transform: uppercase;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n background: #f8fafc;\n cursor: pointer;\n}\n\n.vpg-row-header-label + .vpg-row-header-label {\n border-left: 1px solid #e2e8f0;\n}\n\n.vpg-row-header-label:hover {\n background: #f1f5f9;\n}\n\n.vpg-column-header-cell {\n padding: 0.5rem 0.75rem;\n text-align: center;\n font-size: 0.6875rem;\n font-weight: 600;\n color: #334155;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n white-space: nowrap;\n background: #f8fafc;\n cursor: pointer;\n}\n\n.vpg-column-header-cell:hover {\n background: #f1f5f9;\n}\n\n.vpg-header-content {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.25rem;\n}\n\n.vpg-sort-indicator {\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #94a3b8;\n font-size: 0.75rem;\n}\n\n.vpg-sort-indicator.active {\n color: #4f46e5;\n font-weight: 700;\n}\n\n.vpg-total-header {\n padding: 0.5rem;\n text-align: center;\n font-size: 0.6875rem;\n font-weight: 700;\n color: #92400e;\n border-bottom: 1px solid #cbd5e1;\n border-left: 2px solid #f59e0b;\n background: #fde68a;\n vertical-align: middle;\n}\n\n.vpg-data-row:hover {\n background: #ecfdf5;\n}\n\n.vpg-data-row:nth-child(even) {\n background: #f8fafc;\n}\n\n.vpg-row-header-cell {\n position: sticky;\n /* left is set dynamically via inline style for multi-column row headers */\n padding: 0.5rem 0.75rem;\n text-align: left;\n font-size: 0.75rem;\n font-weight: 500;\n color: #334155;\n background: white;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #e2e8f0;\n white-space: nowrap;\n z-index: 10;\n}\n\n.vpg-data-row:nth-child(even) .vpg-row-header-cell {\n background: #f8fafc;\n}\n\n/* Row header cells now render as separate columns */\n.vpg-row-header-cell + .vpg-row-header-cell {\n border-left: 1px solid #e2e8f0;\n}\n\n.vpg-data-cell {\n padding: 0.5rem 0.75rem;\n text-align: right;\n font-size: 0.75rem;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: #334155;\n font-variant-numeric: tabular-nums;\n border-bottom: 1px solid #f1f5f9;\n border-right: 1px solid #f8fafc;\n cursor: cell;\n white-space: nowrap;\n}\n\n.vpg-data-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(16, 185, 129, 0.4);\n}\n\n.vpg-data-cell.selected {\n background: #d1fae5;\n box-shadow: inset 0 0 0 2px #10b981;\n}\n\n.vpg-data-cell.vpg-is-null {\n color: #cbd5e1;\n}\n\n.vpg-data-cell.vpg-total-cell {\n background: #fef3c7;\n font-weight: 600;\n color: #92400e;\n}\n\n.vpg-data-cell.vpg-grand-total-cell {\n background: #fde68a;\n font-weight: 700;\n color: #92400e;\n}\n\n.vpg-totals-row {\n background: #fef9e7;\n}\n\n.vpg-total-label {\n font-weight: 700;\n color: #92400e;\n background: #fef3c7;\n}\n\n/* Font sizes */\n.vpg-pivot-skeleton.vpg-font-xs .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-xs .vpg-row-header-cell {\n font-size: 0.75rem;\n padding: 0.375rem 0.75rem;\n}\n\n.vpg-pivot-skeleton.vpg-font-sm .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-sm .vpg-row-header-cell {\n font-size: 0.875rem;\n padding: 0.5rem 1rem;\n}\n\n.vpg-pivot-skeleton.vpg-font-base .vpg-data-cell,\n.vpg-pivot-skeleton.vpg-font-base .vpg-row-header-cell {\n font-size: 1rem;\n padding: 0.625rem 1rem;\n}\n\n/* Footer */\n.vpg-skeleton-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n font-size: 0.75rem;\n color: #64748b;\n background: #f8fafc;\n border-top: 1px solid #e2e8f0;\n flex-shrink: 0;\n}\n\n.vpg-skeleton-footer .vpg-footer-info {\n color: #94a3b8;\n}\n\n.vpg-skeleton-footer .vpg-selection-stats {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.125rem 0.5rem;\n background: rgba(16, 185, 129, 0.08);\n border: 1px solid rgba(16, 185, 129, 0.15);\n border-radius: 0.25rem;\n font-size: 0.6875rem;\n}\n\n.vpg-skeleton-footer .vpg-stat {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-skeleton-footer .vpg-stat-label {\n color: #64748b;\n font-weight: 400;\n}\n\n.vpg-skeleton-footer .vpg-stat-value {\n color: #10b981;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n}\n\n.vpg-skeleton-footer .vpg-stat-divider {\n color: #cbd5e1;\n}\n\n/* Watermark */\n.vpg-watermark {\n padding: 0.375rem 1rem;\n background: #f1f5f9;\n border-top: 1px solid #e2e8f0;\n text-align: center;\n flex-shrink: 0;\n}\n\n.vpg-watermark a {\n font-size: 0.625rem;\n color: #94a3b8;\n text-decoration: none;\n transition: color 0.15s;\n}\n\n.vpg-watermark a:hover {\n color: #64748b;\n}\n\n/* Demo Mode Banner */\n.vpg-watermark.vpg-demo-mode {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n padding: 0.5rem 1rem;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n border-top: 1px solid #fcd34d;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-demo-badge {\n display: inline-flex;\n align-items: center;\n padding: 0.125rem 0.5rem;\n background: #f59e0b;\n color: white;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n letter-spacing: 0.05em;\n}\n\n.vpg-get-pro {\n font-weight: 600;\n color: #d97706 !important;\n}\n\n.vpg-get-pro:hover {\n color: #b45309 !important;\n text-decoration: underline;\n}\n\n/* Scrollbar */\n.vpg-table-container::-webkit-scrollbar {\n width: 0.5rem;\n height: 0.5rem;\n}\n\n.vpg-table-container::-webkit-scrollbar-track {\n background: #f1f5f9;\n}\n\n.vpg-table-container::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 9999px;\n}\n\n.vpg-table-container::-webkit-scrollbar-thumb:hover {\n background: #94a3b8;\n}\n\n.vpg-table-container::-webkit-scrollbar-corner {\n background: #f1f5f9;\n}\n\n/* Toast notification */\n.vpg-pivot-skeleton .vpg-toast {\n position: absolute;\n top: 1rem;\n right: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #10b981;\n color: white;\n border-radius: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n z-index: 100;\n}\n\n.vpg-toast-enter-active,\n.vpg-toast-leave-active {\n transition: all 0.2s ease;\n}\n\n.vpg-toast-enter-from,\n.vpg-toast-leave-to {\n opacity: 0;\n transform: translateY(-0.5rem);\n}\n</style>\n\n<style>\n/* Dark Mode - PivotSkeleton */\n.vpg-theme-dark .vpg-pivot-skeleton {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-skeleton-header {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-skeleton-title {\n color: #94a3b8 !important;\n}\n\n/* Config bar (drop zones container) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-config-bar {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zones {\n background: #0f172a !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone {\n background: #1e293b !important;\n border-color: #475569 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone:hover {\n border-color: #64748b !important;\n background: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drop-zone.vpg-zone-active {\n border-color: #10b981 !important;\n background: rgba(16, 185, 129, 0.2) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-label {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-row .vpg-zone-label { color: #a5b4fc !important; }\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-column .vpg-zone-label { color: #c4b5fd !important; }\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-value .vpg-zone-label { color: #6ee7b7 !important; }\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-zone-hint {\n color: #64748b !important;\n}\n\n/* Mini chips in drop zones */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-row-chip {\n background: #312e81 !important;\n color: #a5b4fc !important;\n border-color: #4338ca !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-column-chip {\n background: #4c1d95 !important;\n color: #c4b5fd !important;\n border-color: #7c3aed !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip {\n background: #064e3b !important;\n color: #6ee7b7 !important;\n border-color: #10b981 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip.vpg-calc-chip {\n background: rgba(168, 85, 247, 0.2) !important;\n color: #c4b5fd !important;\n border-color: rgba(168, 85, 247, 0.4) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip.vpg-value-chip.vpg-calc-chip .vpg-agg-symbol {\n background: rgba(168, 85, 247, 0.4);\n color: #c4b5fd;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-drag-handle {\n opacity: 0.4;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-mini-chip:hover .vpg-drag-handle {\n opacity: 0.7;\n}\n\n/* Font size toggle (S M L) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-toggle {\n background: #1e293b !important;\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn:hover {\n background: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-font-size-btn.active {\n background: #10b981 !important;\n color: white !important;\n}\n\n/* Summary badges (1 row, 1 col, 1 val) */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-rows {\n background: rgba(99, 102, 241, 0.2) !important;\n color: #a5b4fc !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-cols {\n background: rgba(139, 92, 246, 0.2) !important;\n color: #c4b5fd !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-summary-badge.vpg-vals {\n background: rgba(16, 185, 129, 0.2) !important;\n color: #6ee7b7 !important;\n}\n\n/* Filter indicator - dark mode */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-indicator {\n background: linear-gradient(135deg, rgba(245, 158, 11, 0.2) 0%, rgba(217, 119, 6, 0.25) 100%) !important;\n border-color: #d97706 !important;\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-icon {\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-text strong {\n color: #fcd34d !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-count {\n color: #fbbf24 !important;\n}\n\n/* Filter tooltip - dark mode */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-filter-tooltip {\n background: #1e293b !important;\n border-color: #475569 !important;\n box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.3);\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-header {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-filter {\n border-color: #334155 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-column {\n color: #e2e8f0 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-value {\n background: rgba(245, 158, 11, 0.2) !important;\n color: #fbbf24 !important;\n border-color: rgba(245, 158, 11, 0.4) !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-more {\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-tooltip-summary {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #94a3b8 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-table {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-pivot-table thead {\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.3);\n}\n\n.vpg-theme-dark .vpg-column-header-row {\n background: #0f172a !important;\n}\n\n.vpg-theme-dark .vpg-column-header-row th {\n background: #0f172a !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-column-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-corner-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-label {\n background: #0f172a !important;\n border-color: #334155 !important;\n color: #e2e8f0 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-label:hover,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-column-header-cell:hover {\n background: #1e293b !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-row-header-cell {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell {\n background: #1e293b;\n border-color: #334155;\n color: #cbd5e1;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(52, 211, 153, 0.5);\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.selected {\n background: rgba(16, 185, 129, 0.2);\n box-shadow: inset 0 0 0 2px #34d399;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:nth-child(even) .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:nth-child(even) .vpg-data-cell {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:hover .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-row:hover .vpg-data-cell {\n background: #334155;\n}\n\n/* Total header column */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-total-header {\n background: #451a03 !important;\n color: #fbbf24 !important;\n border-color: #334155 !important;\n}\n\n/* Total cells in rows - consistent color */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.vpg-total-cell {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n/* Grand total cell */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-data-cell.vpg-grand-total-cell {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n/* Totals row - consistent color */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row {\n background: transparent !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row .vpg-row-header-cell,\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-totals-row .vpg-data-cell {\n background: #451a03 !important;\n}\n\n/* Total label */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-total-label {\n background: #451a03 !important;\n color: #fbbf24 !important;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-empty-state {\n background: #0f172a;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer {\n background: #0f172a;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-footer-info {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-selection-stats {\n background: rgba(16, 185, 129, 0.1);\n border-color: rgba(16, 185, 129, 0.2);\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-value {\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-skeleton-footer .vpg-stat-divider {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-demo-bar {\n background: rgba(245, 158, 11, 0.15);\n border-color: rgba(245, 158, 11, 0.3);\n color: #fbbf24;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-track {\n background: #0f172a;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-thumb {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-thumb:hover {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-table-container::-webkit-scrollbar-corner {\n background: #0f172a;\n}\n\n/* Dark mode - Placeholder */\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder {\n background: linear-gradient(135deg, #1e293b, #0f172a, rgba(16, 185, 129, 0.05));\n border-top-color: #334155;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-icon {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-text {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-pivot-skeleton .vpg-placeholder-text strong {\n color: #e2e8f0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport type {\n AIAnalystConfig,\n AIConversationUpdateEvent,\n AIDataLoadedEvent,\n AIErrorEvent,\n AIQueryExecutedEvent,\n CalculatedField,\n ChartConfig,\n DateFormat,\n NumberFormat,\n} from '@smallwebco/tinypivot-core'\nimport { formatDate as coreFormatDate, formatNumber as coreFormatNumber, loadCalculatedFields, saveCalculatedFields } from '@smallwebco/tinypivot-core'\n/**\n * TinyPivot - Main DataGrid Component\n * Excel-like data grid with optional pivot table functionality\n */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useExcelGrid } from '../composables/useExcelGrid'\nimport {\n copyToClipboard,\n exportPivotToCSV,\n exportToCSV,\n formatSelectionForClipboard,\n} from '../composables/useGridFeatures'\nimport { useLicense } from '../composables/useLicense'\nimport { usePivotTable } from '../composables/usePivotTable'\nimport AIAnalyst from './AIAnalyst.vue'\nimport ChartBuilder from './ChartBuilder.vue'\nimport ColumnFilter from './ColumnFilter.vue'\nimport PivotConfig from './PivotConfig.vue'\nimport PivotSkeleton from './PivotSkeleton.vue'\n\nconst props = withDefaults(defineProps<{\n data: Record<string, unknown>[]\n loading?: boolean\n rowHeight?: number\n headerHeight?: number\n fontSize?: 'xs' | 'sm' | 'base'\n showPivot?: boolean\n // Feature props\n enableExport?: boolean\n enableSearch?: boolean\n enablePagination?: boolean\n pageSize?: number\n enableColumnResize?: boolean\n enableClipboard?: boolean\n theme?: 'light' | 'dark' | 'auto'\n stripedRows?: boolean\n exportFilename?: string\n enableVerticalResize?: boolean\n initialHeight?: number\n minHeight?: number\n maxHeight?: number\n /** AI Data Analyst configuration (Pro feature, disabled by default) */\n aiAnalyst?: AIAnalystConfig\n /** Number display format */\n numberFormat?: NumberFormat\n /** Date display format */\n dateFormat?: DateFormat\n /** Override auto-detected chart field roles per column name */\n fieldRoleOverrides?: Record<string, import('@smallwebco/tinypivot-core').FieldRole>\n}>(), {\n loading: false,\n rowHeight: 36,\n headerHeight: 40,\n fontSize: 'xs',\n showPivot: true,\n // Feature defaults\n enableExport: true,\n enableSearch: true,\n enablePagination: false,\n pageSize: 50,\n enableColumnResize: true,\n enableClipboard: true,\n theme: 'light',\n stripedRows: true,\n exportFilename: 'data-export.csv',\n enableVerticalResize: true,\n initialHeight: 600,\n minHeight: 300,\n maxHeight: 1200,\n aiAnalyst: undefined,\n numberFormat: 'us',\n dateFormat: 'iso',\n})\n\nconst emit = defineEmits<{\n (e: 'cellClick', payload: { row: number, col: number, value: unknown, rowData: Record<string, unknown> }): void\n (e: 'selectionChange', payload: { cells: Array<{ row: number, col: number }>, values: unknown[] }): void\n (e: 'export', payload: { rowCount: number, filename: string }): void\n (e: 'copy', payload: { text: string, cellCount: number }): void\n // AI Analyst events\n (e: 'aiDataLoaded', payload: AIDataLoadedEvent): void\n (e: 'aiConversationUpdate', payload: AIConversationUpdateEvent): void\n (e: 'aiQueryExecuted', payload: AIQueryExecutedEvent): void\n (e: 'aiError', payload: AIErrorEvent): void\n}>()\n\nconst { showWatermark, canUsePivot, canUseCharts, canUseAIAnalyst, isDemo, isPro } = useLicense()\n\n// Check if AI Analyst should be shown (enabled in config + licensed)\nconst showAIAnalyst = computed(() =>\n props.aiAnalyst?.enabled && canUseAIAnalyst.value,\n)\n\n// Theme handling\nconst currentTheme = computed(() => {\n if (props.theme === 'auto') {\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'\n }\n return props.theme\n})\n\n// Font size state\nconst currentFontSize = ref(props.fontSize)\n\n// Global search state\nconst globalSearchTerm = ref('')\nconst showSearchInput = ref(false)\n\n// Pagination state\nconst currentPage = ref(1)\n\n// Column resize state\nconst resizingColumnId = ref<string | null>(null)\nconst resizeStartX = ref(0)\nconst resizeStartWidth = ref(0)\n\n// Vertical resize state\nconst gridHeight = ref(props.initialHeight)\nconst isResizingVertically = ref(false)\nconst verticalResizeStartY = ref(0)\nconst verticalResizeStartHeight = ref(0)\n\n// Clipboard toast state\nconst showCopyToast = ref(false)\nconst copyToastMessage = ref('')\nconst fontSizeOptions = [\n { value: 'xs', label: 'S' },\n { value: 'sm', label: 'M' },\n { value: 'base', label: 'L' },\n] as const\n\n// AI Analyst component ref (for accessing loadFullData)\nconst aiAnalystRef = ref<InstanceType<typeof AIAnalyst> | null>(null)\n\n// AI-loaded data (replaces current data when AI loads results)\n// Must be defined before displayData and dataRef\nconst aiLoadedData = ref<Record<string, unknown>[] | null>(null)\n\n// Data to display - AI loaded data takes precedence\nconst displayData = computed(() => aiLoadedData.value || props.data)\n\n// Grid composable - uses displayData which may be AI-loaded or original props.data\nconst dataRef = computed(() => displayData.value)\nconst {\n table,\n columnKeys,\n filteredRowCount,\n totalRowCount,\n getColumnStats,\n hasActiveFilter,\n setColumnFilter,\n getColumnFilterValues,\n clearAllFilters,\n toggleSort,\n getSortDirection,\n columnFilters,\n activeFilters,\n // Numeric range filters\n setNumericRangeFilter,\n getNumericRangeFilter,\n // Date range filters\n setDateRangeFilter,\n getDateRangeFilter,\n} = useExcelGrid({ data: dataRef })\n\n// Filtered data for pivot table (respects column filters)\nconst filteredDataForPivot = computed(() => {\n const filteredRows = table.getFilteredRowModel().rows\n return filteredRows.map(row => row.original)\n})\n\n// Active filters info for display - use activeFilters from useExcelGrid\nconst activeFilterInfo = computed(() => {\n if (activeFilters.value.length === 0)\n return null\n return activeFilters.value.map((f) => {\n if (f.type === 'range' && f.range) {\n // Format range filter display\n const parts = []\n if (f.range.min !== null)\n parts.push(`≥ ${f.range.min}`)\n if (f.range.max !== null)\n parts.push(`≤ ${f.range.max}`)\n return {\n column: f.column,\n valueCount: 1,\n displayText: parts.join(' and '),\n isRange: true,\n }\n }\n if (f.type === 'dateRange' && f.dateRange) {\n // Format date range filter display\n const parts = []\n if (f.dateRange.min !== null)\n parts.push(`from ${coreFormatDate(f.dateRange.min, props.dateFormat)}`)\n if (f.dateRange.max !== null)\n parts.push(`to ${coreFormatDate(f.dateRange.max, props.dateFormat)}`)\n return {\n column: f.column,\n valueCount: 1,\n displayText: parts.join(' '),\n isRange: true,\n }\n }\n return {\n column: f.column,\n valueCount: f.values?.length || 0,\n values: f.values || [],\n isRange: false,\n }\n })\n})\n\n// Pivot table composable - uses filtered data\nconst {\n rowFields: pivotRowFields,\n columnFields: pivotColumnFields,\n valueFields: pivotValueFields,\n showRowTotals: pivotShowRowTotals,\n showColumnTotals: pivotShowColumnTotals,\n availableFields: pivotAvailableFields,\n isConfigured: pivotIsConfigured,\n pivotResult,\n addRowField,\n removeRowField,\n addColumnField,\n removeColumnField,\n addValueField,\n removeValueField,\n updateValueFieldAggregation,\n clearConfig: clearPivotConfig,\n autoSuggestConfig: _autoSuggestConfig,\n} = usePivotTable(filteredDataForPivot)\n\n// Filtered data based on global search\nconst searchFilteredData = computed(() => {\n if (!globalSearchTerm.value.trim() || !props.enableSearch) {\n return rows.value\n }\n const term = globalSearchTerm.value.toLowerCase().trim()\n return rows.value.filter((row) => {\n for (const col of columnKeys.value) {\n const value = row.original[col]\n if (value === null || value === undefined)\n continue\n if (String(value).toLowerCase().includes(term)) {\n return true\n }\n }\n return false\n })\n})\n\n// Paginated rows\nconst totalSearchedRows = computed(() => searchFilteredData.value.length)\nconst totalPages = computed(() => {\n if (!props.enablePagination)\n return 1\n return Math.max(1, Math.ceil(totalSearchedRows.value / props.pageSize))\n})\n\nconst paginatedRows = computed(() => {\n if (!props.enablePagination)\n return searchFilteredData.value\n const start = (currentPage.value - 1) * props.pageSize\n const end = start + props.pageSize\n return searchFilteredData.value.slice(start, end)\n})\n\nconst paginationStart = computed(() => {\n if (totalSearchedRows.value === 0)\n return 0\n return (currentPage.value - 1) * props.pageSize + 1\n})\n\nconst paginationEnd = computed(() =>\n Math.min(currentPage.value * props.pageSize, totalSearchedRows.value),\n)\n\nfunction nextPage() {\n if (currentPage.value < totalPages.value)\n currentPage.value++\n}\n\nfunction prevPage() {\n if (currentPage.value > 1)\n currentPage.value--\n}\n\n// Reset to page 1 when filters or search changes\nwatch([columnFilters, globalSearchTerm], () => {\n currentPage.value = 1\n})\n\n// Export functionality\nfunction handleExport() {\n if (viewMode.value === 'pivot') {\n handlePivotExport()\n return\n }\n\n const dataToExport = props.enableSearch && globalSearchTerm.value.trim()\n ? searchFilteredData.value.map(row => row.original)\n : rows.value.map(row => row.original)\n\n exportToCSV(dataToExport, columnKeys.value, {\n filename: props.exportFilename,\n includeHeaders: true,\n })\n\n emit('export', { rowCount: dataToExport.length, filename: props.exportFilename })\n}\n\nfunction handlePivotExport() {\n if (!pivotResult.value)\n return\n\n const pivotFilename = props.exportFilename.replace('.csv', '-pivot.csv')\n\n exportPivotToCSV(\n {\n headers: pivotResult.value.headers,\n rowHeaders: pivotResult.value.rowHeaders,\n data: pivotResult.value.data,\n rowTotals: pivotResult.value.rowTotals,\n columnTotals: pivotResult.value.columnTotals,\n grandTotal: pivotResult.value.grandTotal,\n showRowTotals: pivotShowRowTotals.value,\n showColumnTotals: pivotShowColumnTotals.value,\n },\n pivotRowFields.value,\n pivotColumnFields.value,\n pivotValueFields.value,\n { filename: pivotFilename },\n )\n\n const rowCount = pivotResult.value.rowHeaders.length\n emit('export', { rowCount, filename: pivotFilename })\n}\n\n// Column resize methods\nfunction startColumnResize(columnId: string, event: MouseEvent) {\n if (!props.enableColumnResize)\n return\n event.preventDefault()\n event.stopPropagation()\n\n resizingColumnId.value = columnId\n resizeStartX.value = event.clientX\n resizeStartWidth.value = columnWidths.value[columnId] || MIN_COL_WIDTH\n\n document.addEventListener('mousemove', handleResizeMove)\n document.addEventListener('mouseup', handleResizeEnd)\n}\n\nfunction handleResizeMove(event: MouseEvent) {\n if (!resizingColumnId.value)\n return\n const diff = event.clientX - resizeStartX.value\n const newWidth = Math.max(MIN_COL_WIDTH, Math.min(MAX_COL_WIDTH, resizeStartWidth.value + diff))\n columnWidths.value = {\n ...columnWidths.value,\n [resizingColumnId.value]: newWidth,\n }\n}\n\nfunction handleResizeEnd() {\n resizingColumnId.value = null\n document.removeEventListener('mousemove', handleResizeMove)\n document.removeEventListener('mouseup', handleResizeEnd)\n}\n\n// Vertical resize methods\nfunction startVerticalResize(event: MouseEvent) {\n if (!props.enableVerticalResize)\n return\n event.preventDefault()\n\n isResizingVertically.value = true\n verticalResizeStartY.value = event.clientY\n verticalResizeStartHeight.value = gridHeight.value\n\n document.addEventListener('mousemove', handleVerticalResizeMove)\n document.addEventListener('mouseup', handleVerticalResizeEnd)\n}\n\nfunction handleVerticalResizeMove(event: MouseEvent) {\n if (!isResizingVertically.value)\n return\n const diff = event.clientY - verticalResizeStartY.value\n const newHeight = Math.max(\n props.minHeight,\n Math.min(props.maxHeight, verticalResizeStartHeight.value + diff),\n )\n gridHeight.value = newHeight\n}\n\nfunction handleVerticalResizeEnd() {\n isResizingVertically.value = false\n document.removeEventListener('mousemove', handleVerticalResizeMove)\n document.removeEventListener('mouseup', handleVerticalResizeEnd)\n}\n\n// Clipboard methods\nfunction copySelectionToClipboard() {\n if (!selectionBounds.value || !props.enableClipboard)\n return\n\n const text = formatSelectionForClipboard(\n rows.value.map(r => r.original),\n columnKeys.value,\n selectionBounds.value,\n )\n\n copyToClipboard(\n text,\n () => {\n const cellCount\n = (selectionBounds.value!.maxRow - selectionBounds.value!.minRow + 1)\n * (selectionBounds.value!.maxCol - selectionBounds.value!.minCol + 1)\n copyToastMessage.value = `Copied ${cellCount} cell${cellCount > 1 ? 's' : ''}`\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n emit('copy', { text, cellCount })\n },\n (err) => {\n copyToastMessage.value = 'Copy failed'\n showCopyToast.value = true\n setTimeout(() => { showCopyToast.value = false }, 2000)\n console.error('Copy failed:', err)\n },\n )\n}\n\n// View mode\nconst viewMode = ref<'ai' | 'grid' | 'pivot' | 'chart'>('grid')\n\nfunction handleAIDataLoaded(payload: AIDataLoadedEvent) {\n aiLoadedData.value = payload.data\n // Don't auto-switch to grid - let user decide when to view results\n emit('aiDataLoaded', payload)\n}\n\n// Track if we're showing AI-shaped data (filtered/aggregated by AI queries)\nconst isShowingAIData = computed(() => aiLoadedData.value !== null)\n\n// Loading state for full data reset\nconst isLoadingFullData = ref(false)\n\n// Reset to full original dataset\n// If AI Analyst is enabled and has a selected data source, load full data from that source\n// Otherwise, just clear the AI loaded data to show original props.data\nasync function resetToFullData() {\n // If we have AI Analyst with a selected data source, load full data from it\n if (aiAnalystRef.value?.selectedDataSource) {\n isLoadingFullData.value = true\n try {\n const fullData = await aiAnalystRef.value.loadFullData()\n if (fullData && fullData.length > 0) {\n aiLoadedData.value = fullData\n }\n else {\n // Fall back to props.data if loading fails\n aiLoadedData.value = null\n }\n }\n catch (err) {\n console.warn('Failed to load full data:', err)\n aiLoadedData.value = null\n }\n finally {\n isLoadingFullData.value = false\n }\n }\n else {\n // No AI Analyst or no selected data source - just clear filters by resetting to props.data\n aiLoadedData.value = null\n }\n // Also clear any grid filters\n clearAllFilters()\n}\n\nfunction handleAIConversationUpdate(payload: AIConversationUpdateEvent) {\n emit('aiConversationUpdate', payload)\n}\n\nfunction handleAIQueryExecuted(payload: AIQueryExecutedEvent) {\n emit('aiQueryExecuted', payload)\n}\n\nfunction handleAIError(payload: AIErrorEvent) {\n emit('aiError', payload)\n}\n\nfunction handleAIViewResults(payload: { data: Record<string, unknown>[], query: string }) {\n aiLoadedData.value = payload.data\n viewMode.value = 'grid' // Switch to grid to show the results\n}\nconst chartConfig = ref<ChartConfig | null>(null)\n\nfunction handleChartConfigChange(config: ChartConfig) {\n chartConfig.value = config\n}\nconst showPivotConfig = ref(true)\nconst draggingField = ref<string | null>(null)\n\n// Calculated fields state (persisted to localStorage)\nconst calculatedFields = ref<CalculatedField[]>(loadCalculatedFields())\n\nfunction handleAddCalculatedField(field: CalculatedField) {\n // Generate ID if not present\n if (!field.id) {\n field.id = `calc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n }\n calculatedFields.value = [...calculatedFields.value, field]\n saveCalculatedFields(calculatedFields.value)\n}\n\nfunction handleRemoveCalculatedField(id: string) {\n calculatedFields.value = calculatedFields.value.filter(f => f.id !== id)\n saveCalculatedFields(calculatedFields.value)\n // Also remove from valueFields if it was assigned\n const calcFieldKey = `calc:${id}`\n const existing = pivotValueFields.value.find(v => v.field === calcFieldKey)\n if (existing) {\n removeValueField(calcFieldKey, existing.aggregation)\n }\n}\n\nfunction handleUpdateCalculatedField(field: CalculatedField) {\n calculatedFields.value = calculatedFields.value.map(f => f.id === field.id ? field : f)\n saveCalculatedFields(calculatedFields.value)\n}\n\nfunction handlePivotDragStart(field: string) {\n draggingField.value = field\n}\n\nfunction handlePivotDragEnd() {\n draggingField.value = null\n}\n\nfunction reorderRowFields(fields: string[]) {\n pivotRowFields.value = fields\n}\n\nfunction reorderColumnFields(fields: string[]) {\n pivotColumnFields.value = fields\n}\n\n// Container refs\nconst tableContainerRef = ref<HTMLDivElement>()\nconst tableBodyRef = ref<HTMLDivElement>()\n\n// Rows\nconst rows = computed(() => table.getRowModel().rows)\n\n// Column filter dropdown state\nconst activeFilterColumn = ref<string | null>(null)\nconst filterDropdownPosition = ref({ top: 0, left: 0, maxHeight: 400 })\n\n// Column widths\nconst columnWidths = ref<Record<string, number>>({})\nconst MIN_COL_WIDTH = 120\nconst MAX_COL_WIDTH = 350\n\nfunction calculateColumnWidths() {\n // Skip during SSR (no document available)\n if (typeof document === 'undefined')\n return\n\n if (displayData.value.length === 0)\n return\n\n const widths: Record<string, number> = {}\n const sampleSize = Math.min(100, displayData.value.length)\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx)\n return\n\n ctx.font = '13px system-ui, -apple-system, sans-serif'\n\n for (const key of columnKeys.value) {\n let maxWidth = ctx.measureText(key).width + 56\n\n for (let i = 0; i < sampleSize; i++) {\n const value = displayData.value[i][key]\n const text = value === null || value === undefined ? '' : String(value)\n const width = ctx.measureText(text).width + 28\n maxWidth = Math.max(maxWidth, width)\n }\n\n widths[key] = Math.min(Math.max(maxWidth, MIN_COL_WIDTH), MAX_COL_WIDTH)\n }\n\n columnWidths.value = widths\n}\n\nfunction openFilterDropdown(columnId: string, event: MouseEvent) {\n event.stopPropagation()\n const target = event.currentTarget as HTMLElement\n const headerCell = target.closest('.vpg-header-cell') as HTMLElement\n const rect = headerCell?.getBoundingClientRect() || target.getBoundingClientRect()\n\n const dropdownWidth = 280\n const padding = 12\n\n let left = rect.left\n if (left + dropdownWidth > window.innerWidth - padding) {\n left = window.innerWidth - dropdownWidth - padding\n }\n left = Math.max(padding, left)\n\n const spaceBelow = window.innerHeight - rect.bottom - padding\n const spaceAbove = rect.top - padding\n\n let top: number\n let maxHeight: number\n\n if (spaceBelow >= 300 || spaceBelow >= spaceAbove) {\n top = rect.bottom + 4\n maxHeight = Math.min(400, spaceBelow - 4)\n }\n else {\n maxHeight = Math.min(400, spaceAbove - 4)\n top = rect.top - maxHeight - 4\n }\n\n filterDropdownPosition.value = { top, left, maxHeight }\n activeFilterColumn.value = columnId\n}\n\nfunction closeFilterDropdown() {\n activeFilterColumn.value = null\n}\n\nfunction handleFilter(columnId: string, values: string[]) {\n setColumnFilter(columnId, values)\n}\n\nfunction handleRangeFilter(columnId: string, range: import('@smallwebco/tinypivot-core').NumericRange | null) {\n setNumericRangeFilter(columnId, range)\n}\n\nfunction handleDateRangeFilter(columnId: string, range: import('@smallwebco/tinypivot-core').DateRange | null) {\n setDateRangeFilter(columnId, range)\n}\n\nfunction handleSort(columnId: string, direction: 'asc' | 'desc' | null) {\n if (direction === null) {\n const current = getSortDirection(columnId)\n if (current) {\n toggleSort(columnId)\n if (getSortDirection(columnId)) {\n toggleSort(columnId)\n }\n }\n }\n else {\n const current = getSortDirection(columnId)\n if (current === null) {\n toggleSort(columnId)\n if (direction === 'desc' && getSortDirection(columnId) === 'asc') {\n toggleSort(columnId)\n }\n }\n else if (current !== direction) {\n toggleSort(columnId)\n }\n }\n}\n\nconst activeFilterCount = computed(() => columnFilters.value.length)\n\n// Selection state\nconst selectedCell = ref<{ row: number, col: number } | null>(null)\nconst selectionStart = ref<{ row: number, col: number } | null>(null)\nconst selectionEnd = ref<{ row: number, col: number } | null>(null)\nconst isSelecting = ref(false)\n\nfunction selectColumn(colIndex: number) {\n const maxRow = rows.value.length - 1\n if (maxRow < 0)\n return\n\n selectionStart.value = { row: 0, col: colIndex }\n selectionEnd.value = { row: maxRow, col: colIndex }\n selectedCell.value = { row: 0, col: colIndex }\n}\n\nfunction handleHeaderClick(colIndex: number, event: MouseEvent) {\n const target = event.target as HTMLElement\n if (target.closest('.vpg-dropdown-arrow')) {\n const colId = columnKeys.value[colIndex]\n openFilterDropdown(colId, event)\n }\n else {\n selectColumn(colIndex)\n }\n}\n\nconst selectionBounds = computed(() => {\n if (!selectionStart.value || !selectionEnd.value)\n return null\n return {\n minRow: Math.min(selectionStart.value.row, selectionEnd.value.row),\n maxRow: Math.max(selectionStart.value.row, selectionEnd.value.row),\n minCol: Math.min(selectionStart.value.col, selectionEnd.value.col),\n maxCol: Math.max(selectionStart.value.col, selectionEnd.value.col),\n }\n})\n\nfunction isCellInSelection(rowIndex: number, colIndex: number): boolean {\n if (!selectionBounds.value)\n return false\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n return rowIndex >= minRow && rowIndex <= maxRow && colIndex >= minCol && colIndex <= maxCol\n}\n\nconst selectionStats = computed(() => {\n if (!selectionBounds.value)\n return null\n const { minRow, maxRow, minCol, maxCol } = selectionBounds.value\n\n const values: number[] = []\n let count = 0\n\n for (let r = minRow; r <= maxRow; r++) {\n const row = rows.value[r]\n if (!row)\n continue\n\n for (let c = minCol; c <= maxCol; c++) {\n const colId = columnKeys.value[c]\n if (!colId)\n continue\n\n const value = row.original[colId]\n count++\n\n if (value !== null && value !== undefined && value !== '') {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value))\n if (!Number.isNaN(num)) {\n values.push(num)\n }\n }\n }\n }\n\n if (values.length === 0)\n return { count, sum: null, avg: null, numericCount: 0 }\n\n const sum = values.reduce((a, b) => a + b, 0)\n const avg = sum / values.length\n\n return { count, sum, avg, numericCount: values.length }\n})\n\nfunction formatStatValue(value: number | null): string {\n if (value === null)\n return '-'\n return coreFormatNumber(value, props.numberFormat)\n}\n\nfunction handleKeydown(event: KeyboardEvent) {\n // Handle Ctrl+C / Cmd+C for clipboard\n if ((event.ctrlKey || event.metaKey) && event.key === 'c' && selectionBounds.value) {\n event.preventDefault()\n copySelectionToClipboard()\n return\n }\n\n // Handle Ctrl+F / Cmd+F for search\n if ((event.ctrlKey || event.metaKey) && event.key === 'f' && props.enableSearch) {\n event.preventDefault()\n showSearchInput.value = true\n nextTick(() => {\n const input = document.querySelector('.vpg-search-input') as HTMLInputElement\n input?.focus()\n })\n return\n }\n\n if (!selectedCell.value)\n return\n if (activeFilterColumn.value)\n return\n\n const { row, col } = selectedCell.value\n const displayRows = paginatedRows.value\n const maxRow = displayRows.length - 1\n const maxCol = columnKeys.value.length - 1\n\n function updateSelection(newRow: number, newCol: number) {\n if (event.shiftKey) {\n if (!selectionStart.value) {\n selectionStart.value = { row, col }\n }\n selectionEnd.value = { row: newRow, col: newCol }\n }\n else {\n selectionStart.value = { row: newRow, col: newCol }\n selectionEnd.value = { row: newRow, col: newCol }\n }\n selectedCell.value = { row: newRow, col: newCol }\n scrollCellIntoView(newRow, newCol)\n }\n\n switch (event.key) {\n case 'ArrowUp':\n event.preventDefault()\n if (row > 0)\n updateSelection(row - 1, col)\n break\n case 'ArrowDown':\n event.preventDefault()\n if (row < maxRow)\n updateSelection(row + 1, col)\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (col > 0)\n updateSelection(row, col - 1)\n break\n case 'ArrowRight':\n event.preventDefault()\n if (col < maxCol)\n updateSelection(row, col + 1)\n break\n case 'Escape':\n selectedCell.value = null\n selectionStart.value = null\n selectionEnd.value = null\n showSearchInput.value = false\n globalSearchTerm.value = ''\n break\n }\n}\n\nfunction scrollCellIntoView(rowIndex: number, colIndex: number) {\n nextTick(() => {\n const cell = tableBodyRef.value?.querySelector(\n `[data-row=\"${rowIndex}\"][data-col=\"${colIndex}\"]`,\n )\n cell?.scrollIntoView({ block: 'nearest', inline: 'nearest' })\n })\n}\n\nfunction handleMouseDown(rowIndex: number, colIndex: number, event: MouseEvent) {\n event.preventDefault()\n\n if (event.shiftKey && selectedCell.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n else {\n selectedCell.value = { row: rowIndex, col: colIndex }\n selectionStart.value = { row: rowIndex, col: colIndex }\n selectionEnd.value = { row: rowIndex, col: colIndex }\n isSelecting.value = true\n }\n\n // Emit event\n const row = rows.value[rowIndex]\n if (row) {\n const colId = columnKeys.value[colIndex]\n emit('cellClick', {\n row: rowIndex,\n col: colIndex,\n value: row.original[colId],\n rowData: row.original,\n })\n }\n}\n\nfunction handleMouseEnter(rowIndex: number, colIndex: number) {\n if (isSelecting.value) {\n selectionEnd.value = { row: rowIndex, col: colIndex }\n }\n}\n\nfunction handleMouseUp() {\n isSelecting.value = false\n}\n\nfunction isCellSelected(rowIndex: number, colIndex: number): boolean {\n if (isCellInSelection(rowIndex, colIndex))\n return true\n return selectedCell.value?.row === rowIndex && selectedCell.value?.col === colIndex\n}\n\n// Format cell value\nconst noFormatPatterns = /^(?:.*_)?(?:id|code|year|month|quarter|day|week|date|zip|phone|fax|ssn|ein|npi|ndc|gpi|hcpcs|icd|cpt|rx|bin|pcn|group|member|claim|rx_number|script|fill)(?:_.*)?$/i\n\nfunction shouldFormatNumber(columnId: string): boolean {\n return !noFormatPatterns.test(columnId)\n}\n\nfunction formatCellValue(value: unknown, columnId: string): string {\n if (value === null || value === undefined)\n return ''\n if (value === '')\n return ''\n\n const stats = getColumnStats(columnId)\n\n if (stats.type === 'date') {\n return coreFormatDate(value, props.dateFormat)\n }\n\n if (stats.type === 'number') {\n const num = typeof value === 'number' ? value : Number.parseFloat(String(value))\n if (Number.isNaN(num))\n return String(value)\n\n if (shouldFormatNumber(columnId) && Math.abs(num) >= 1000) {\n return coreFormatNumber(num, props.numberFormat)\n }\n\n if (Number.isInteger(num)) {\n return String(num)\n }\n return coreFormatNumber(num, props.numberFormat, { maximumFractionDigits: 4 })\n }\n\n return String(value)\n}\n\nfunction handleTableScroll() {\n if (activeFilterColumn.value) {\n closeFilterDropdown()\n }\n}\n\nfunction handleWindowScroll(event: Event) {\n if (activeFilterColumn.value) {\n const target = event.target as HTMLElement\n if (target && target.closest?.('.vpg-filter-portal')) {\n return\n }\n closeFilterDropdown()\n }\n}\n\n// Initialize\nonMounted(() => {\n calculateColumnWidths()\n document.addEventListener('keydown', handleKeydown)\n document.addEventListener('mouseup', handleMouseUp)\n\n nextTick(() => {\n tableContainerRef.value?.addEventListener('scroll', handleTableScroll, { passive: true })\n })\n\n window.addEventListener('scroll', handleWindowScroll, { passive: true, capture: true })\n})\n\nonUnmounted(() => {\n document.removeEventListener('keydown', handleKeydown)\n document.removeEventListener('mouseup', handleMouseUp)\n tableContainerRef.value?.removeEventListener('scroll', handleTableScroll)\n window.removeEventListener('scroll', handleWindowScroll, { capture: true })\n})\n\n// Watch both props.data and aiLoadedData for recalculating column widths\nwatch([() => props.data, aiLoadedData], () => {\n nextTick(calculateColumnWidths)\n}, { immediate: true })\n\nconst totalTableWidth = computed(() => {\n return columnKeys.value.reduce((sum, key) => sum + (columnWidths.value[key] || MIN_COL_WIDTH), 0)\n})\n\nfunction handleContainerClick(event: MouseEvent) {\n if (activeFilterColumn.value) {\n const target = event.target as HTMLElement\n if (!target.closest('.vpg-filter-portal')) {\n closeFilterDropdown()\n }\n }\n}\n</script>\n\n<template>\n <div\n class=\"vpg-data-grid\"\n :class=\"[\n `vpg-font-${currentFontSize}`,\n `vpg-theme-${currentTheme}`,\n { 'vpg-striped': stripedRows },\n { 'vpg-resizing': resizingColumnId },\n { 'vpg-resizing-vertical': isResizingVertically },\n ]\"\n :style=\"{ height: `${gridHeight}px` }\"\n @click=\"handleContainerClick\"\n >\n <!-- Copy Toast -->\n <Transition name=\"vpg-toast\">\n <div v-if=\"showCopyToast\" class=\"vpg-toast\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 13l4 4L19 7\" />\n </svg>\n {{ copyToastMessage }}\n </div>\n </Transition>\n\n <!-- Toolbar -->\n <div class=\"vpg-toolbar\">\n <div class=\"vpg-toolbar-left\">\n <!-- View mode toggle -->\n <div v-if=\"showPivot\" class=\"vpg-view-toggle\">\n <!-- AI Analyst button (first, only if enabled) -->\n <button\n v-if=\"showAIAnalyst\"\n class=\"vpg-view-btn vpg-ai-btn\"\n :class=\"{ active: viewMode === 'ai' }\"\n @click=\"viewMode = 'ai'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n AI Analyst\n </button>\n <button\n v-else-if=\"aiAnalyst?.enabled && !canUseAIAnalyst\"\n class=\"vpg-view-btn vpg-ai-btn vpg-pro-feature\"\n title=\"AI Analyst (Pro feature)\"\n @click.prevent\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" 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\" />\n </svg>\n AI Analyst\n <span class=\"vpg-pro-badge\">Pro</span>\n </button>\n <button\n class=\"vpg-view-btn\"\n :class=\"{ active: viewMode === 'grid' }\"\n @click=\"viewMode = 'grid'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 10h18M3 14h18m-9-4v8m-7 0h14a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n Grid\n </button>\n <button\n class=\"vpg-view-btn vpg-pivot-btn\"\n :class=\"{ active: viewMode === 'pivot' }\"\n @click=\"viewMode = 'pivot'\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z\" />\n </svg>\n Pivot\n </button>\n <button\n class=\"vpg-view-btn vpg-chart-btn\"\n :class=\"{ 'active': viewMode === 'chart', 'vpg-pro-feature': !canUseCharts }\"\n :title=\"canUseCharts ? 'Chart Builder' : 'Chart Builder (Pro feature)'\"\n @click=\"canUseCharts ? viewMode = 'chart' : null\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z\" />\n </svg>\n Chart\n <span v-if=\"!canUseCharts\" class=\"vpg-pro-badge\">Pro</span>\n </button>\n </div>\n\n <!-- Grid mode controls -->\n <template v-if=\"viewMode === 'grid'\">\n <!-- Search input -->\n <div v-if=\"enableSearch\" class=\"vpg-search-container\">\n <button\n v-if=\"!showSearchInput\"\n class=\"vpg-icon-btn\"\n title=\"Search (Ctrl+F)\"\n @click=\"showSearchInput = true\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n </button>\n <div v-else class=\"vpg-search-box\">\n <svg class=\"vpg-search-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n <input\n v-model=\"globalSearchTerm\"\n type=\"text\"\n class=\"vpg-search-input\"\n placeholder=\"Search all columns...\"\n @keydown.escape=\"showSearchInput = false; globalSearchTerm = ''\"\n >\n <button\n v-if=\"globalSearchTerm\"\n class=\"vpg-search-clear\"\n @click=\"globalSearchTerm = ''\"\n >\n <svg class=\"vpg-icon-xs\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"vpg-font-size-control\">\n <span class=\"vpg-label\">Size:</span>\n <div class=\"vpg-font-size-toggle\">\n <button\n v-for=\"opt in fontSizeOptions\"\n :key=\"opt.value\"\n class=\"vpg-font-size-btn\"\n :class=\"{ active: currentFontSize === opt.value }\"\n @click=\"currentFontSize = opt.value\"\n >\n {{ opt.label }}\n </button>\n </div>\n </div>\n\n <div v-if=\"activeFilterCount > 0\" class=\"vpg-filter-info\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n <span>{{ activeFilterCount }} filter{{ activeFilterCount > 1 ? 's' : '' }}</span>\n </div>\n\n <!-- Reset to full data button (when showing AI-filtered results) -->\n <button\n v-if=\"isShowingAIData\"\n class=\"vpg-reset-data-btn\"\n :class=\"{ 'vpg-loading-btn': isLoadingFullData }\"\n :disabled=\"isLoadingFullData\"\n title=\"Reset to full dataset\"\n @click=\"resetToFullData\"\n >\n <svg v-if=\"isLoadingFullData\" class=\"vpg-icon vpg-spin\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <svg v-else class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n <span>{{ isLoadingFullData ? 'Loading...' : 'Full Data' }}</span>\n </button>\n\n <div v-if=\"globalSearchTerm\" class=\"vpg-search-info\">\n <span>{{ totalSearchedRows }} match{{ totalSearchedRows !== 1 ? 'es' : '' }}</span>\n </div>\n </template>\n\n <!-- Pivot mode controls -->\n <template v-if=\"viewMode === 'pivot' && canUsePivot\">\n <button\n class=\"vpg-config-toggle\"\n :class=\"{ active: showPivotConfig }\"\n @click=\"showPivotConfig = !showPivotConfig\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4\" />\n </svg>\n {{ showPivotConfig ? 'Hide' : 'Show' }} Config\n </button>\n\n <div v-if=\"pivotIsConfigured\" class=\"vpg-pivot-status\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />\n </svg>\n <span>Pivot configured</span>\n </div>\n </template>\n </div>\n\n <div class=\"vpg-toolbar-right\">\n <button v-if=\"viewMode === 'grid' && activeFilterCount > 0\" class=\"vpg-clear-filters\" @click=\"clearAllFilters\">\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n Clear Filters\n </button>\n\n <!-- Copy button -->\n <button\n v-if=\"enableClipboard && selectionBounds && viewMode === 'grid'\"\n class=\"vpg-icon-btn\"\n title=\"Copy selection (Ctrl+C)\"\n @click=\"copySelectionToClipboard\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\" />\n </svg>\n </button>\n\n <!-- Export button - Grid export is free, Pivot export requires Pro -->\n <button\n v-if=\"enableExport && viewMode === 'grid'\"\n class=\"vpg-export-btn\"\n title=\"Export to CSV\"\n @click=\"handleExport\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Export\n </button>\n <button\n v-if=\"enableExport && viewMode === 'pivot' && pivotIsConfigured\"\n class=\"vpg-export-btn\"\n :class=\"{ 'vpg-export-btn-disabled': !isPro }\"\n :disabled=\"!isPro\"\n :title=\"isPro ? 'Export Pivot to CSV' : 'Export Pivot to CSV (Pro feature)'\"\n @click=\"isPro && handleExport()\"\n >\n <svg class=\"vpg-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n Export Pivot{{ !isPro ? ' (Pro)' : '' }}\n </button>\n </div>\n </div>\n\n <!-- AI Analyst View - use v-show to preserve state when switching tabs -->\n <div v-if=\"showAIAnalyst && aiAnalyst\" v-show=\"viewMode === 'ai'\" class=\"vpg-ai-view\">\n <AIAnalyst\n ref=\"aiAnalystRef\"\n :config=\"aiAnalyst\"\n :theme=\"currentTheme\"\n @data-loaded=\"handleAIDataLoaded\"\n @conversation-update=\"handleAIConversationUpdate\"\n @query-executed=\"handleAIQueryExecuted\"\n @error=\"handleAIError\"\n @view-results=\"handleAIViewResults\"\n />\n </div>\n\n <!-- Grid View -->\n <template v-if=\"viewMode === 'grid'\">\n <div ref=\"tableContainerRef\" class=\"vpg-grid-container\" tabindex=\"0\">\n <div v-if=\"loading\" class=\"vpg-loading\">\n <div class=\"vpg-spinner\" />\n <span>Loading data...</span>\n </div>\n\n <div v-else-if=\"displayData.length === 0\" class=\"vpg-empty\">\n <div class=\"vpg-empty-icon\">\n <svg class=\"vpg-icon-lg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\" />\n </svg>\n </div>\n <span>No data available</span>\n </div>\n\n <div v-else-if=\"filteredRowCount === 0\" class=\"vpg-empty\">\n <div class=\"vpg-empty-icon vpg-warning\">\n <svg class=\"vpg-icon-lg\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.5\" d=\"M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z\" />\n </svg>\n </div>\n <span>No matching records</span>\n <button class=\"vpg-clear-link\" @click=\"clearAllFilters\">\n Clear all filters\n </button>\n </div>\n\n <div v-else class=\"vpg-table-wrapper\">\n <table class=\"vpg-table\" :style=\"{ minWidth: `${totalTableWidth}px` }\">\n <thead>\n <tr>\n <th\n v-for=\"(colId, colIndex) in columnKeys\"\n :key=\"colId\"\n class=\"vpg-header-cell\"\n :class=\"{\n 'vpg-has-filter': hasActiveFilter(colId),\n 'vpg-is-sorted': getSortDirection(colId) !== null,\n 'vpg-is-active': activeFilterColumn === colId,\n }\"\n :style=\"{ width: `${columnWidths[colId] || MIN_COL_WIDTH}px`, minWidth: `${columnWidths[colId] || MIN_COL_WIDTH}px` }\"\n @click=\"handleHeaderClick(colIndex, $event)\"\n >\n <div class=\"vpg-header-content\">\n <span class=\"vpg-header-text\">{{ colId }}</span>\n <div class=\"vpg-header-icons\">\n <span v-if=\"getSortDirection(colId)\" class=\"vpg-sort-indicator\">\n <svg v-if=\"getSortDirection(colId) === 'asc'\" class=\"vpg-icon-sm\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z\" clip-rule=\"evenodd\" />\n </svg>\n <svg v-else class=\"vpg-icon-sm\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z\" clip-rule=\"evenodd\" />\n </svg>\n </span>\n <span v-if=\"hasActiveFilter(colId)\" class=\"vpg-filter-indicator\">\n <svg class=\"vpg-icon-xs\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n </span>\n <span class=\"vpg-dropdown-arrow\" title=\"Filter & Sort\">\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </span>\n </div>\n </div>\n <!-- Column resize handle -->\n <div\n v-if=\"enableColumnResize\"\n class=\"vpg-resize-handle\"\n @mousedown=\"startColumnResize(colId, $event)\"\n />\n </th>\n </tr>\n </thead>\n\n <tbody ref=\"tableBodyRef\">\n <tr\n v-for=\"(row, rowIndex) in paginatedRows\"\n :key=\"row.id\"\n class=\"vpg-row\"\n >\n <td\n v-for=\"(colId, colIndex) in columnKeys\"\n :key=\"colId\"\n class=\"vpg-cell\"\n :class=\"{\n 'vpg-selected': isCellSelected(rowIndex, colIndex),\n 'vpg-is-number': getColumnStats(colId).type === 'number',\n }\"\n :data-row=\"rowIndex\"\n :data-col=\"colIndex\"\n :style=\"{ width: `${columnWidths[colId] || MIN_COL_WIDTH}px`, minWidth: `${columnWidths[colId] || MIN_COL_WIDTH}px` }\"\n @mousedown=\"handleMouseDown(rowIndex, colIndex, $event)\"\n @mouseenter=\"handleMouseEnter(rowIndex, colIndex)\"\n >\n {{ formatCellValue(row.original[colId], colId) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n </template>\n\n <!-- Pivot View -->\n <template v-else-if=\"viewMode === 'pivot'\">\n <div class=\"vpg-pivot-container\">\n <div v-if=\"showPivotConfig && canUsePivot\" class=\"vpg-pivot-config-panel\">\n <PivotConfig\n :available-fields=\"pivotAvailableFields\"\n :row-fields=\"pivotRowFields\"\n :column-fields=\"pivotColumnFields\"\n :value-fields=\"pivotValueFields\"\n :show-row-totals=\"pivotShowRowTotals\"\n :show-column-totals=\"pivotShowColumnTotals\"\n :calculated-fields=\"calculatedFields\"\n @update:show-row-totals=\"pivotShowRowTotals = $event\"\n @update:show-column-totals=\"pivotShowColumnTotals = $event\"\n @clear-config=\"clearPivotConfig\"\n @drag-start=\"handlePivotDragStart\"\n @drag-end=\"handlePivotDragEnd\"\n @update-aggregation=\"updateValueFieldAggregation\"\n @add-row-field=\"addRowField\"\n @remove-row-field=\"removeRowField\"\n @add-column-field=\"addColumnField\"\n @remove-column-field=\"removeColumnField\"\n @add-value-field=\"addValueField\"\n @remove-value-field=\"removeValueField\"\n @add-calculated-field=\"handleAddCalculatedField\"\n @remove-calculated-field=\"handleRemoveCalculatedField\"\n @update-calculated-field=\"handleUpdateCalculatedField\"\n />\n </div>\n\n <div class=\"vpg-pivot-main\" :class=\"{ 'vpg-full-width': !showPivotConfig }\">\n <PivotSkeleton\n :row-fields=\"pivotRowFields\"\n :column-fields=\"pivotColumnFields\"\n :value-fields=\"pivotValueFields\"\n :calculated-fields=\"calculatedFields\"\n :is-configured=\"pivotIsConfigured\"\n :dragging-field=\"draggingField\"\n :pivot-result=\"pivotResult\"\n :font-size=\"currentFontSize\"\n :active-filters=\"activeFilterInfo\"\n :total-row-count=\"totalRowCount\"\n :filtered-row-count=\"filteredRowCount\"\n @add-row-field=\"addRowField\"\n @remove-row-field=\"removeRowField\"\n @add-column-field=\"addColumnField\"\n @remove-column-field=\"removeColumnField\"\n @add-value-field=\"addValueField\"\n @remove-value-field=\"removeValueField\"\n @update-aggregation=\"updateValueFieldAggregation\"\n @reorder-row-fields=\"reorderRowFields\"\n @reorder-column-fields=\"reorderColumnFields\"\n />\n </div>\n </div>\n </template>\n\n <!-- Chart View -->\n <template v-else-if=\"viewMode === 'chart'\">\n <div class=\"vpg-chart-view\">\n <!-- Filter indicator for chart -->\n <div v-if=\"activeFilterInfo && activeFilterInfo.length > 0\" class=\"vpg-chart-filter-bar\">\n <svg class=\"vpg-icon\" fill=\"currentColor\" viewBox=\"0 0 20 20\">\n <path fill-rule=\"evenodd\" d=\"M3 3a1 1 0 011-1h12a1 1 0 011 1v3a1 1 0 01-.293.707L12 11.414V15a1 1 0 01-.293.707l-2 2A1 1 0 018 17v-5.586L3.293 6.707A1 1 0 013 6V3z\" clip-rule=\"evenodd\" />\n </svg>\n <span>Chart showing {{ filteredRowCount.toLocaleString() }} of {{ totalRowCount.toLocaleString() }} records</span>\n <button class=\"vpg-chart-clear-filters\" @click=\"clearAllFilters\">\n Clear filters\n </button>\n </div>\n <ChartBuilder\n :data=\"filteredDataForPivot\"\n :theme=\"currentTheme\"\n :field-role-overrides=\"props.fieldRoleOverrides\"\n @config-change=\"handleChartConfigChange\"\n />\n </div>\n </template>\n\n <!-- Footer -->\n <div class=\"vpg-footer\">\n <div class=\"vpg-footer-left\">\n <template v-if=\"viewMode === 'grid'\">\n <template v-if=\"enablePagination\">\n <span>{{ paginationStart.toLocaleString() }}-{{ paginationEnd.toLocaleString() }}</span>\n <span class=\"vpg-separator\">of</span>\n <span>{{ totalSearchedRows.toLocaleString() }}</span>\n <span v-if=\"totalSearchedRows !== totalRowCount\" class=\"vpg-filtered-note\">\n ({{ totalRowCount.toLocaleString() }} total)\n </span>\n </template>\n <template v-else-if=\"filteredRowCount === totalRowCount && totalSearchedRows === totalRowCount\">\n <span>{{ totalRowCount.toLocaleString() }} records</span>\n </template>\n <template v-else>\n <span class=\"vpg-filtered-count\">{{ totalSearchedRows.toLocaleString() }}</span>\n <span class=\"vpg-separator\">of</span>\n <span>{{ totalRowCount.toLocaleString() }}</span>\n <span class=\"vpg-separator\">records</span>\n </template>\n </template>\n <template v-else-if=\"viewMode === 'pivot'\">\n <span class=\"vpg-pivot-label\">Pivot Table</span>\n <span class=\"vpg-separator\">•</span>\n <span>{{ totalRowCount.toLocaleString() }} source records</span>\n </template>\n <template v-else-if=\"viewMode === 'chart'\">\n <span class=\"vpg-chart-label\">Chart Builder</span>\n <span class=\"vpg-separator\">•</span>\n <span>{{ totalRowCount.toLocaleString() }} records</span>\n </template>\n </div>\n\n <!-- Pagination controls -->\n <div v-if=\"enablePagination && viewMode === 'grid' && totalPages > 1\" class=\"vpg-pagination\">\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === 1\"\n @click=\"currentPage = 1\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11 19l-7-7 7-7m8 14l-7-7 7-7\" />\n </svg>\n </button>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === 1\"\n @click=\"prevPage\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n <span class=\"vpg-page-info\">\n Page {{ currentPage }} of {{ totalPages }}\n </span>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === totalPages\"\n @click=\"nextPage\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </button>\n <button\n class=\"vpg-page-btn\"\n :disabled=\"currentPage === totalPages\"\n @click=\"currentPage = totalPages\"\n >\n <svg class=\"vpg-icon-sm\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M13 5l7 7-7 7M5 5l7 7-7 7\" />\n </svg>\n </button>\n </div>\n\n <div v-if=\"viewMode === 'grid' && selectionStats && selectionStats.count > 1\" class=\"vpg-selection-stats\">\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Count:</span>\n <span class=\"vpg-stat-value\">{{ selectionStats.count }}</span>\n </span>\n <template v-if=\"selectionStats.numericCount > 0\">\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Sum:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.sum) }}</span>\n </span>\n <span class=\"vpg-stat-divider\">|</span>\n <span class=\"vpg-stat\">\n <span class=\"vpg-stat-label\">Avg:</span>\n <span class=\"vpg-stat-value\">{{ formatStatValue(selectionStats.avg) }}</span>\n </span>\n </template>\n </div>\n\n <div class=\"vpg-footer-right\">\n <div v-if=\"isDemo\" class=\"vpg-demo-banner\">\n <span class=\"vpg-demo-badge\">DEMO</span>\n <span>Pro features enabled</span>\n <a href=\"https://tiny-pivot.com/#pricing\" target=\"_blank\" rel=\"noopener\">Get License →</a>\n </div>\n <span v-else-if=\"showWatermark\" class=\"vpg-watermark-inline\">\n <a href=\"https://tiny-pivot.com\" target=\"_blank\" rel=\"noopener\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" /><rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" /><rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" /><rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" /></svg>\n Powered by TinyPivot\n </a>\n </span>\n </div>\n </div>\n\n <!-- Vertical Resize Handle -->\n <div\n v-if=\"enableVerticalResize\"\n class=\"vpg-vertical-resize-handle\"\n @mousedown=\"startVerticalResize\"\n >\n <div class=\"vpg-resize-grip\">\n <span />\n <span />\n <span />\n </div>\n </div>\n\n <!-- Filter Dropdown Portal -->\n <Teleport to=\"body\">\n <div\n v-if=\"activeFilterColumn\"\n class=\"vpg-filter-portal\"\n :style=\"{\n position: 'fixed',\n top: `${filterDropdownPosition.top}px`,\n left: `${filterDropdownPosition.left}px`,\n maxHeight: `${filterDropdownPosition.maxHeight}px`,\n zIndex: 9999,\n }\"\n >\n <ColumnFilter\n :column-id=\"activeFilterColumn\"\n :column-name=\"activeFilterColumn\"\n :stats=\"getColumnStats(activeFilterColumn)\"\n :selected-values=\"getColumnFilterValues(activeFilterColumn)\"\n :sort-direction=\"getSortDirection(activeFilterColumn)\"\n :numeric-range=\"getNumericRangeFilter(activeFilterColumn)\"\n :date-range=\"getDateRangeFilter(activeFilterColumn)\"\n :number-format=\"numberFormat\"\n :date-format=\"dateFormat\"\n @filter=\"(values) => handleFilter(activeFilterColumn!, values)\"\n @range-filter=\"(range) => handleRangeFilter(activeFilterColumn!, range)\"\n @date-range-filter=\"(range) => handleDateRangeFilter(activeFilterColumn!, range)\"\n @sort=\"(dir) => handleSort(activeFilterColumn!, dir)\"\n @close=\"closeFilterDropdown\"\n />\n </div>\n </Teleport>\n </div>\n</template>\n\n<style scoped>\n.vpg-data-grid {\n display: flex;\n flex-direction: column;\n background: white;\n border-radius: 0.5rem;\n overflow: hidden;\n border: 1px solid #e2e8f0;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);\n margin-bottom: 1.5rem;\n position: relative;\n}\n\n.vpg-icon {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-icon-sm {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.vpg-icon-xs {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.vpg-icon-lg {\n width: 3rem;\n height: 3rem;\n}\n\n/* Toolbar */\n.vpg-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.5rem 1rem;\n background: #f8fafc;\n border-bottom: 1px solid #e2e8f0;\n}\n\n.vpg-toolbar-left {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.vpg-toolbar-right {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-view-toggle {\n display: flex;\n background: white;\n border-radius: 0.5rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-view-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-view-btn:hover {\n background: #f8fafc;\n}\n\n.vpg-view-btn.active {\n background: #4f46e5;\n color: white;\n box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.1);\n}\n\n.vpg-view-btn.vpg-pivot-btn.active {\n background: #10b981;\n}\n\n.vpg-font-size-control {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.vpg-label {\n font-size: 0.75rem;\n color: #64748b;\n}\n\n.vpg-font-size-toggle {\n display: flex;\n background: white;\n border-radius: 0.25rem;\n border: 1px solid #e2e8f0;\n overflow: hidden;\n}\n\n.vpg-font-size-btn {\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #64748b;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-font-size-btn:hover {\n background: #f1f5f9;\n}\n\n.vpg-font-size-btn.active {\n background: #4f46e5;\n color: white;\n}\n\n.vpg-filter-info {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: #475569;\n}\n\n.vpg-filter-info svg {\n color: #4f46e5;\n}\n\n.vpg-reset-data-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 0.375rem;\n background: #fef3c7;\n border: 1px solid #fcd34d;\n color: #92400e;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-reset-data-btn:hover {\n background: #fde68a;\n border-color: #f59e0b;\n}\n\n.vpg-reset-data-btn svg {\n width: 1rem;\n height: 1rem;\n}\n\n.vpg-config-toggle {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 0.375rem;\n background: white;\n border: 1px solid #e2e8f0;\n color: #475569;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-config-toggle:hover {\n background: #f8fafc;\n}\n\n.vpg-config-toggle.active {\n background: #ecfdf5;\n border-color: #a7f3d0;\n color: #059669;\n}\n\n.vpg-pivot-status {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n font-size: 0.875rem;\n color: #059669;\n}\n\n.vpg-clear-filters {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n font-weight: 500;\n color: #475569;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-clear-filters:hover {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n/* Grid Container */\n.vpg-grid-container {\n flex: 1;\n overflow: auto;\n position: relative;\n background: rgba(248, 250, 252, 0.3);\n isolation: isolate;\n}\n\n.vpg-grid-container:focus {\n outline: none;\n}\n\n.vpg-loading {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(255, 255, 255, 0.95);\n z-index: 10;\n}\n\n.vpg-spinner {\n width: 2rem;\n height: 2rem;\n border: 2px solid #e2e8f0;\n border-top-color: #4f46e5;\n border-radius: 50%;\n animation: vpg-spin 1s linear infinite;\n}\n\n@keyframes vpg-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n.vpg-loading span {\n margin-top: 0.5rem;\n font-size: 0.875rem;\n color: #64748b;\n}\n\n.vpg-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 5rem;\n gap: 0.75rem;\n}\n\n.vpg-empty-icon {\n width: 5rem;\n height: 5rem;\n border-radius: 50%;\n background: #f1f5f9;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #cbd5e1;\n margin-bottom: 0.5rem;\n}\n\n.vpg-empty-icon.vpg-warning {\n background: #fef3c7;\n color: #fcd34d;\n}\n\n.vpg-empty span {\n color: #64748b;\n font-weight: 500;\n}\n\n.vpg-clear-link {\n color: #4f46e5;\n font-size: 0.875rem;\n font-weight: 500;\n margin-top: 0.25rem;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n\n.vpg-clear-link:hover {\n text-decoration: underline;\n}\n\n.vpg-table-wrapper {\n min-height: 100%;\n}\n\n.vpg-table {\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n}\n\n.vpg-table thead {\n position: sticky;\n top: 0;\n z-index: 20;\n box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);\n}\n\n.vpg-header-cell {\n z-index: 10;\n padding: 0.5rem 0.75rem;\n text-align: left;\n cursor: pointer;\n user-select: none;\n background: #f8fafc;\n transition: all 0.15s;\n border-bottom: 1px solid #e2e8f0;\n border-right: 1px solid #f1f5f9;\n}\n\n.vpg-header-cell:hover {\n background: #f1f5f9;\n}\n\n.vpg-header-cell:last-child {\n border-right: none;\n}\n\n.vpg-header-cell.vpg-has-filter {\n background: #eef2ff;\n}\n\n.vpg-header-cell.vpg-is-sorted {\n background: #eff6ff;\n}\n\n.vpg-header-cell.vpg-has-filter.vpg-is-sorted {\n background: #ede9fe;\n}\n\n.vpg-header-cell.vpg-is-active {\n background: #e0e7ff;\n box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.1);\n}\n\n.vpg-header-content {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n}\n\n.vpg-header-text {\n font-size: 0.75rem;\n font-weight: 600;\n color: #475569;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.vpg-header-icons {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n flex-shrink: 0;\n}\n\n.vpg-sort-indicator {\n color: #3b82f6;\n}\n\n.vpg-filter-indicator {\n color: #4f46e5;\n}\n\n.vpg-dropdown-arrow {\n padding: 0.125rem;\n border-radius: 0.25rem;\n color: #cbd5e1;\n transition: all 0.15s;\n cursor: pointer;\n}\n\n.vpg-dropdown-arrow:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-header-cell:hover .vpg-dropdown-arrow {\n color: #94a3b8;\n}\n\n.vpg-row {\n transition: background 0.15s;\n}\n\n.vpg-row:nth-child(odd) {\n background: white;\n}\n\n.vpg-row:nth-child(even) {\n background: rgba(248, 250, 252, 0.5);\n}\n\n.vpg-row:hover {\n background: rgba(239, 246, 255, 0.4);\n}\n\n.vpg-cell {\n padding: 0.625rem 1rem;\n font-size: 0.875rem;\n color: #334155;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: cell;\n transition: all 0.15s;\n max-width: 350px;\n border-bottom: 1px solid #f1f5f9;\n border-right: 1px solid #f8fafc;\n}\n\n.vpg-cell:last-child {\n border-right: none;\n}\n\n.vpg-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(129, 140, 248, 0.4);\n}\n\n.vpg-cell.vpg-selected {\n background: rgba(224, 231, 255, 0.8);\n box-shadow: inset 0 0 0 2px #818cf8;\n}\n\n.vpg-cell.vpg-is-number {\n text-align: right;\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;\n color: #334155;\n font-variant-numeric: tabular-nums;\n}\n\n/* Font size variations */\n.vpg-data-grid.vpg-font-xs .vpg-cell {\n font-size: 0.75rem;\n padding: 0.375rem 0.75rem;\n}\n\n.vpg-data-grid.vpg-font-xs .vpg-header-text {\n font-size: 0.625rem;\n}\n\n.vpg-data-grid.vpg-font-sm .vpg-cell {\n font-size: 0.875rem;\n padding: 0.5rem 1rem;\n}\n\n.vpg-data-grid.vpg-font-base .vpg-cell {\n font-size: 1rem;\n padding: 0.625rem 1rem;\n}\n\n.vpg-data-grid.vpg-font-base .vpg-header-text {\n font-size: 0.75rem;\n}\n\n/* Pivot Container */\n.vpg-pivot-container {\n display: flex;\n flex: 1;\n gap: 1rem;\n overflow: hidden;\n min-height: 0;\n padding: 1rem;\n}\n\n.vpg-pivot-config-panel {\n width: 14rem;\n flex-shrink: 0;\n overflow: hidden;\n}\n\n.vpg-pivot-main {\n flex: 1;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.vpg-pivot-main.vpg-full-width {\n width: 100%;\n}\n\n/* Footer */\n.vpg-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n background: rgba(248, 250, 252, 0.8);\n border-top: 1px solid rgba(226, 232, 240, 0.8);\n font-size: 0.875rem;\n}\n\n.vpg-footer-left {\n display: flex;\n align-items: center;\n color: #64748b;\n}\n\n.vpg-filtered-count {\n color: #4f46e5;\n font-weight: 500;\n}\n\n.vpg-separator {\n color: #94a3b8;\n margin: 0 0.25rem;\n}\n\n.vpg-pivot-label {\n color: #10b981;\n font-weight: 500;\n}\n\n.vpg-footer-right {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.vpg-selection-stats {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.125rem 0.5rem;\n background: rgba(99, 102, 241, 0.08);\n border-radius: 0.25rem;\n border: 1px solid rgba(99, 102, 241, 0.15);\n}\n\n.vpg-stat {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-stat-label {\n font-size: 0.6875rem;\n color: #64748b;\n font-weight: 400;\n}\n\n.vpg-stat-value {\n font-size: 0.6875rem;\n color: #6366f1;\n font-weight: 500;\n font-variant-numeric: tabular-nums;\n}\n\n.vpg-stat-divider {\n color: #cbd5e1;\n}\n\n.vpg-watermark-inline a {\n font-size: 0.75rem;\n color: #94a3b8;\n text-decoration: none;\n transition: color 0.15s;\n}\n\n.vpg-watermark-inline a:hover {\n color: #64748b;\n}\n\n/* Demo Banner */\n.vpg-demo-banner {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.25rem 0.75rem;\n background: linear-gradient(135deg, #fef3c7, #fde68a);\n border: 1px solid #fcd34d;\n border-radius: 0.375rem;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-demo-badge {\n display: inline-flex;\n padding: 0.125rem 0.375rem;\n background: #f59e0b;\n color: white;\n font-size: 0.625rem;\n font-weight: 700;\n border-radius: 0.25rem;\n letter-spacing: 0.05em;\n}\n\n.vpg-demo-banner a {\n font-weight: 600;\n color: #d97706;\n text-decoration: none;\n}\n\n.vpg-demo-banner a:hover {\n color: #b45309;\n text-decoration: underline;\n}\n\n/* Scrollbar */\n.vpg-grid-container::-webkit-scrollbar {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n.vpg-grid-container::-webkit-scrollbar-track {\n background: rgba(241, 245, 249, 0.5);\n}\n\n.vpg-grid-container::-webkit-scrollbar-thumb {\n background: rgba(203, 213, 225, 0.8);\n border-radius: 9999px;\n}\n\n.vpg-grid-container::-webkit-scrollbar-thumb:hover {\n background: rgba(148, 163, 184, 0.8);\n}\n\n.vpg-grid-container::-webkit-scrollbar-corner {\n background: rgba(241, 245, 249, 0.5);\n}\n\n/* Toast notification */\n.vpg-toast {\n position: absolute;\n top: 1rem;\n right: 1rem;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #10b981;\n color: white;\n border-radius: 0.5rem;\n font-size: 0.875rem;\n font-weight: 500;\n box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);\n z-index: 100;\n}\n\n.vpg-toast-enter-active,\n.vpg-toast-leave-active {\n transition: all 0.2s ease;\n}\n\n.vpg-toast-enter-from,\n.vpg-toast-leave-to {\n opacity: 0;\n transform: translateY(-0.5rem);\n}\n\n/* Search */\n.vpg-search-container {\n display: flex;\n align-items: center;\n}\n\n.vpg-icon-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0.375rem;\n background: transparent;\n border: none;\n border-radius: 0.375rem;\n color: #64748b;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-icon-btn:hover {\n background: #f1f5f9;\n color: #475569;\n}\n\n.vpg-search-box {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.625rem;\n background: #f8fafc;\n border: 1px solid transparent;\n border-radius: 0.5rem;\n transition: all 0.15s ease;\n}\n\n.vpg-search-box:focus-within {\n background: white;\n border-color: #e2e8f0;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05);\n}\n\n.vpg-search-icon {\n width: 1rem;\n height: 1rem;\n color: #94a3b8;\n flex-shrink: 0;\n}\n\n.vpg-search-input {\n border: none;\n outline: none;\n background: transparent;\n font-size: 0.8125rem;\n color: #334155;\n width: 200px;\n}\n\n.vpg-search-input:focus {\n outline: none;\n}\n\n.vpg-search-input::placeholder {\n color: #94a3b8;\n}\n\n.vpg-search-clear {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0.125rem;\n background: #f1f5f9;\n border: none;\n border-radius: 50%;\n color: #64748b;\n cursor: pointer;\n}\n\n.vpg-search-clear:hover {\n background: #e2e8f0;\n color: #475569;\n}\n\n.vpg-search-info {\n font-size: 0.75rem;\n color: #64748b;\n font-style: italic;\n}\n\n/* Export button */\n.vpg-export-btn {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #059669;\n background: #ecfdf5;\n border: 1px solid #a7f3d0;\n border-radius: 0.375rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-export-btn:hover:not(:disabled) {\n background: #d1fae5;\n border-color: #6ee7b7;\n}\n\n.vpg-export-btn-disabled,\n.vpg-export-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n background: #f1f5f9;\n border-color: #e2e8f0;\n color: #94a3b8;\n}\n\n/* Column resize handle */\n.vpg-resize-handle {\n position: absolute;\n right: 0;\n top: 0;\n bottom: 0;\n width: 6px;\n cursor: col-resize;\n background: transparent;\n transition: background 0.15s;\n}\n\n.vpg-resize-handle:hover {\n background: rgba(79, 70, 229, 0.3);\n}\n\n.vpg-header-cell {\n position: relative;\n}\n\n.vpg-data-grid.vpg-resizing {\n cursor: col-resize;\n user-select: none;\n}\n\n.vpg-data-grid.vpg-resizing .vpg-resize-handle {\n background: rgba(79, 70, 229, 0.3);\n}\n\n/* Vertical resize handle */\n.vpg-vertical-resize-handle {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 8px;\n cursor: row-resize;\n background: transparent;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n transition: background 0.15s;\n}\n\n.vpg-vertical-resize-handle:hover {\n background: rgba(79, 70, 229, 0.1);\n}\n\n.vpg-vertical-resize-handle:hover .vpg-resize-grip span {\n background: rgba(79, 70, 229, 0.6);\n}\n\n.vpg-resize-grip {\n display: flex;\n gap: 2px;\n padding: 2px 8px;\n border-radius: 4px;\n}\n\n.vpg-resize-grip span {\n width: 16px;\n height: 2px;\n background: #cbd5e1;\n border-radius: 1px;\n transition: background 0.15s;\n}\n\n.vpg-data-grid.vpg-resizing-vertical {\n cursor: row-resize;\n user-select: none;\n}\n\n.vpg-data-grid.vpg-resizing-vertical .vpg-vertical-resize-handle {\n background: rgba(79, 70, 229, 0.15);\n}\n\n.vpg-data-grid.vpg-resizing-vertical .vpg-resize-grip span {\n background: rgba(79, 70, 229, 0.8);\n}\n\n/* Pagination */\n.vpg-pagination {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.vpg-page-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n background: white;\n border: 1px solid #e2e8f0;\n border-radius: 0.25rem;\n color: #475569;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-page-btn:hover:not(:disabled) {\n background: #f8fafc;\n border-color: #cbd5e1;\n}\n\n.vpg-page-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.vpg-page-info {\n font-size: 0.75rem;\n color: #64748b;\n padding: 0 0.5rem;\n}\n\n.vpg-filtered-note {\n font-size: 0.75rem;\n color: #94a3b8;\n margin-left: 0.25rem;\n}\n\n/* Dark theme */\n.vpg-data-grid.vpg-theme-dark {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-toolbar {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-view-toggle {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-view-btn {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-view-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-view-btn.active {\n background: #6366f1;\n color: white;\n}\n\n.vpg-theme-dark .vpg-view-btn.vpg-pivot-btn.active {\n background: #10b981;\n}\n\n.vpg-theme-dark .vpg-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-font-size-toggle {\n background: #1e293b;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-font-size-btn {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-font-size-btn:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-grid-container {\n background: rgba(15, 23, 42, 0.5);\n}\n\n.vpg-theme-dark .vpg-header-cell {\n background: #0f172a;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-header-cell:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-header-text {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-dropdown-arrow {\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-dropdown-arrow:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-row:nth-child(odd) {\n background: #1e293b;\n}\n\n.vpg-theme-dark .vpg-row:nth-child(even) {\n background: rgba(30, 41, 59, 0.7);\n}\n\n.vpg-theme-dark .vpg-row:hover {\n background: rgba(51, 65, 85, 0.5);\n}\n\n.vpg-theme-dark .vpg-cell {\n color: #e2e8f0;\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-cell:hover {\n box-shadow: inset 0 0 0 2px rgba(129, 140, 248, 0.5);\n}\n\n.vpg-theme-dark .vpg-cell.vpg-selected {\n background: rgba(99, 102, 241, 0.3);\n box-shadow: inset 0 0 0 2px #818cf8;\n}\n\n.vpg-theme-dark .vpg-footer {\n background: rgba(15, 23, 42, 0.8);\n border-color: #334155;\n}\n\n.vpg-theme-dark .vpg-footer-left {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-selection-stats {\n background: rgba(99, 102, 241, 0.1);\n border-color: rgba(99, 102, 241, 0.2);\n}\n\n.vpg-theme-dark .vpg-stat-label {\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-stat-value {\n color: #a5b4fc;\n}\n\n.vpg-theme-dark .vpg-stat-divider {\n color: #475569;\n}\n\n.vpg-theme-dark .vpg-search-box {\n background: #334155;\n border-color: transparent;\n}\n\n.vpg-theme-dark .vpg-search-box:focus-within {\n background: #1e293b;\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-search-input {\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-search-clear {\n background: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-search-clear:hover {\n background: #475569;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-clear-filters {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-clear-filters:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-page-btn {\n background: #1e293b;\n border-color: #334155;\n color: #e2e8f0;\n}\n\n.vpg-theme-dark .vpg-page-btn:hover:not(:disabled) {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-export-btn {\n background: rgba(16, 185, 129, 0.2);\n border-color: rgba(16, 185, 129, 0.4);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-export-btn:hover:not(:disabled) {\n background: rgba(16, 185, 129, 0.3);\n}\n\n.vpg-theme-dark .vpg-export-btn-disabled,\n.vpg-theme-dark .vpg-export-btn:disabled {\n opacity: 0.5;\n background: #334155;\n border-color: #475569;\n color: #64748b;\n}\n\n.vpg-theme-dark .vpg-config-toggle {\n background: #1e293b;\n border-color: #334155;\n color: #94a3b8;\n}\n\n.vpg-theme-dark .vpg-config-toggle:hover {\n background: #334155;\n}\n\n.vpg-theme-dark .vpg-config-toggle.active {\n background: rgba(16, 185, 129, 0.2);\n border-color: rgba(16, 185, 129, 0.4);\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-pivot-status {\n color: #34d399;\n}\n\n.vpg-theme-dark .vpg-reset-data-btn {\n background: rgba(251, 191, 36, 0.15);\n border-color: rgba(251, 191, 36, 0.4);\n color: #fbbf24;\n}\n\n.vpg-theme-dark .vpg-reset-data-btn:hover {\n background: rgba(251, 191, 36, 0.25);\n border-color: rgba(251, 191, 36, 0.6);\n}\n\n.vpg-theme-dark .vpg-watermark-inline a {\n color: #94a3b8;\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n border-color: #475569;\n}\n\n.vpg-theme-dark .vpg-watermark-inline a:hover {\n color: #cbd5e1;\n background: linear-gradient(135deg, #334155 0%, #475569 100%);\n border-color: #64748b;\n}\n\n.vpg-theme-dark .vpg-resize-grip span {\n background: #475569;\n}\n\n.vpg-theme-dark .vpg-vertical-resize-handle:hover .vpg-resize-grip span {\n background: rgba(129, 140, 248, 0.6);\n}\n\n.vpg-theme-dark.vpg-resizing-vertical .vpg-resize-grip span {\n background: rgba(129, 140, 248, 0.8);\n}\n\n/* Striped rows (toggleable) */\n.vpg-data-grid:not(.vpg-striped) .vpg-row:nth-child(even) {\n background: inherit;\n}\n\n.vpg-theme-dark:not(.vpg-striped) .vpg-row:nth-child(odd),\n.vpg-theme-dark:not(.vpg-striped) .vpg-row:nth-child(even) {\n background: #1e293b;\n}\n\n/* AI Analyst View */\n.vpg-ai-view {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n/* AI Analyst Button */\n.vpg-view-btn.vpg-ai-btn.active {\n background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);\n}\n\n.vpg-view-btn.vpg-ai-btn.vpg-pro-feature {\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n.vpg-pro-badge {\n display: inline-flex;\n padding: 0.0625rem 0.25rem;\n font-size: 0.5625rem;\n font-weight: 600;\n background: linear-gradient(135deg, #f59e0b 0%, #f97316 100%);\n color: white;\n border-radius: 0.25rem;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n}\n\n/* Chart View */\n.vpg-chart-view {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n.vpg-chart-filter-bar {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 1rem;\n background: #fef3c7;\n border-bottom: 1px solid #fde68a;\n font-size: 0.75rem;\n color: #92400e;\n}\n\n.vpg-chart-clear-filters {\n margin-left: auto;\n padding: 0.25rem 0.5rem;\n font-size: 0.75rem;\n font-weight: 500;\n color: #b45309;\n background: transparent;\n border: 1px solid #fcd34d;\n border-radius: 0.25rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.vpg-chart-clear-filters:hover {\n background: #fef3c7;\n}\n\n.vpg-chart-label {\n color: #f59e0b;\n font-weight: 500;\n}\n</style>\n"],"names":["DEMO_SCHEMAS","DEMO_SCENARIOS","findDemoResponse","dataSourceId","userMessage","scenario","lowerMessage","trigger","keyword","getDefaultDemoResponse","s","getDemoSchema","getInitialDemoData","buildSystemPrompt","dataSources","schemas","selectedSourceId","allSchemas","selectedSchema","selectedSource","ds","otherTables","formatDataSourcesList","formatSelectedSchemaContext","formatRelatedTablesContext","desc","source","schema","columnsWithDescriptions","col","override","_a","c","formatColumnsTable","tables","table","keyColumns","otherColumns","moreCount","moreText","columns","nullable","extractSQLFromResponse","response","sqlBlockRegex","match","sql","validateSQLSafety","upperSQL","dangerousKeywords","stripSQLFromContent","content","generateSessionId","generateMessageId","createConversation","sessionId","now","createUserMessage","createAssistantMessage","metadata","addMessageToConversation","conversation","message","setConversationDataSource","getMessagesForAPI","m","CHART_TYPES","CHART_AGGREGATIONS","CHART_COLORS","detectFieldRole","data","field","overrides","values","row","v","numericCount","jsNumberCount","dateCount","val","threshold","analyzeFieldsForChart","fields","result","role","uniqueSet","dataType","min","max","nums","n","formatFieldLabel","word","getChartTypeInfo","type","ct","isChartConfigValid","config","getChartGuidance","typeInfo","aggregateValues","aggregation","a","b","processChartData","xField","yField","yAggregation","seriesField","grouped","xValue","yValue","seriesValue","xGroup","categories","numA","numB","seriesNames","seriesName","series","seriesData","category","processChartDataForPie","entries","e","processChartDataForScatter","sizeField","_b","x","y","point","z","name","points","processChartDataForHeatmap","colorField","colorAggregation","allXCategories","colorValue","yGroup","sortedXCategories","yCategory","xCategory","aggregatedValue","createDefaultChartConfig","escapeCSV","value","delimiter","str","exportToCSV","options","filename","includeHeaders","rows","csvContent","downloadFile","exportPivotToCSV","pivotData","rowFields","_columnFields","valueFields","headers","rowHeaders","rowTotals","columnTotals","grandTotal","showRowTotals","showColumnTotals","rowHeaderColCount","level","headerRow","i","vf","rowIdx","csvRow","rowHeader","rowData","cell","totalsRow","mimeType","blob","url","link","copyToClipboard","text","onSuccess","onError","formatSelectionForClipboard","selectionBounds","minRow","maxRow","minCol","maxCol","lines","r","colId","FREE_LICENSE","INVALID_LICENSE","DEMO_LICENSE","PUBLIC_KEY_PEM","base64ToUint8Array","base64","standardBase64","binaryString","bytes","derToRaw","der","offset","rLen","sLen","padR","padS","raw","verifySignatureNoble","rawSig","msgBytes","spkiBytes","p256","rawPublicKey","hashSecretNoble","secret","sha256","hash","subtleCryptoCache","getSubtleCrypto","subtle","insecureContextWarned","warnInsecureContext","importPublicKey","pemContents","binaryKey","getSpkiBytes","verifySignature","typeCode","signature","expiry","payload","msgData","derSig","publicKey","validateLicenseKey","key","lastDashIdx","expiryStr","withoutPrefix","secondDashIdx","year","month","day","expiresAt","configureLicenseSecret","_secret","DEMO_SECRET_HASH","hashSecret","hashBuffer","getDemoLicenseInfo","getFreeLicenseInfo","canUsePivot","info","canUseCharts","canUseAIAnalyst","isPro","shouldShowWatermark","isDemo","logProRequired","feature","detectColumnType","nonNullValues","sample","numberCount","booleanCount","detectFieldType","isNumeric","getColumnUniqueValues","columnKey","maxValues","nullCount","numericMin","numericMax","dateMin","dateMax","num","dateObj","isoStr","uniqueValues","columnType","formatCellValue","numberFormat","dateFormat","formatNumber","formatDate","format","maxDigits","date","parseDateInput","input","trimmed","parts","d","getDatePlaceholder","makeKey","f","parseKey","calculateMedian","sorted","mid","calculateStdDev","mean","avgSquaredDiff","aggregate","fn","customFn","allFieldValues","sum","formatAggregatedValue","getAggregationLabel","customLabel","getAggregationSymbol","customSymbol","AGGREGATION_OPTIONS","formatCalculatedValue","formatAs","decimals","parseSimpleFormula","formula","matches","keywords","validateSimpleFormula","availableFields","referencedFields","lowerFields","testExpr","escaped","evaluateSimpleFormula","fieldNames","expression","actualField","computeAvailableFields","getUnassignedFields","columnFields","assigned","isPivotConfigured","computePivotResult","calculatedFields","calcFieldMap","cf","allDataFieldNames","rowKeySet","colKeySet","dataMap","rowKey","colKey","colMap","valueArrays","calcId","calcDef","rowKeys","colKeys","grandTotals","_i","total","getValueFieldLabel","repeatCount","valueLabels","_colKey","columnTotalsMap","rowAllValues","rawValues","fi","colTotals","vfIdx","gtValue","aggValue","formattedValue","colRawValues","allRawValues","vals","STORAGE_KEY_PREFIX","generateStorageKey","savePivotConfig","loadPivotConfig","stored","isConfigValidForFields","availableFieldNames","available","CALC_FIELDS_KEY","saveCalculatedFields","loadCalculatedFields","isNumericRange","isDateRange","useAIAnalyst","onDataLoaded","onConversationUpdate","onQueryExecuted","storageKey","loadFromStorage","parsed","saveToStorage","conv","replacer","_key","ref","isLoading","error","lastLoadedData","discoveredDataSources","isLoadingTables","effectiveDataSources","computed","selectedDataSource","selectedDataSourceInfo","messages","hasMessages","fetchTables","t","fetchAllSchemas","err","onMounted","selectDataSource","dataSource","systemMessage","demoSchema","initialData","fetchSchema","fetchSampleData","emitConversationUpdate","sendMessage","handleDemoResponse","assistantMessage","aiResponse","callAIEndpoint","sqlQuery","validation","errorMessage","aiMessage","executeQuery","errorMsg","userInput","resolve","demoTrigger","defaultResponse","systemPrompt","apiMessages","messageId","startTime","duration","updatedMessages","msg","truncatedNote","successMessage","loadFullData","clearConversation","exportConversation","importConversation","props","__props","emit","__emit","__expose","inputText","searchQuery","messagesContainerRef","selectedMessageId","showSqlPanel","filteredDataSources","q","currentSchema","previewData","fullPreviewData","previewColumns","selectedQuery","_c","watch","nextTick","latestWithData","handleSubmit","handleKeydown","event","handleViewResults","selectMessage","toggleSqlPanel","handleClearConversation","handleChangeDataSource","getColumnTypeIcon","getMessageContent","autoResizeTextarea","textarea","hasQueryResult","_createElementBlock","_normalizeClass","_unref","_openBlock","_hoisted_11","_createElementVNode","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_toDisplayString","_hoisted_16","_cache","_hoisted_17","_Fragment","_renderList","_hoisted_18","$event","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_d","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_40","_hoisted_41","_hoisted_42","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","idx","_hoisted_51","_createTextVNode","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","show","validationError","insertField","insertOperator","op","save","validationResult","_createBlock","_Teleport","_hoisted_6","VueApexCharts","defineAsyncComponent","chartConfig","fieldInfos","dimensions","measures","draggingField","dragOverZone","showChartTypeSelector","guidance","chartIsValid","selectedChartType","zoneLabels","isScatterType","isHeatmapType","handleDragStart","handleDragEnd","handleDragOver","zone","handleDragLeave","handleDrop","chartField","removeField","selectChartType","updateAggregation","updated","chartOptions","isDark","baseOptions","getApexChartType","formatValue","w","chartSeries","chartLabels","chartOptionsWithCategories","dec","getChartIcon","icons","_hoisted_19","agg","_hoisted_28","_hoisted_29","_hoisted_39","_Suspense","_e","_f","localMinText","localMaxText","minError","maxError","initFromRange","range","formattedMin","formattedMax","isFilterActive","handleMinInput","emitChange","handleMaxInput","clearFilter","setFullRange","newRange","localMin","localMax","step","minPercent","maxPercent","handleMinSlider","target","handleMaxSlider","_normalizeStyle","dropdownRef","searchInputRef","isNumericColumn","isDateColumn","filterMode","localRange","localDateRange","localSelected","hasBlankValues","filteredValues","query","allValues","ascLabel","descLabel","ascTitle","descTitle","toggleValue","selectAll","clearAll","applyFilter","sortAscending","sortDescending","handleRangeChange","applyRangeFilter","clearRangeFilter","handleDateRangeChange","applyDateRangeFilter","clearDateRangeFilter","setFilterMode","mode","handleClickOutside","onUnmounted","newValues","_createVNode","NumericRangeFilter","DateRangeFilter","multiSelectFilter","columnId","filterValue","cellValue","dateStr","cellString","useExcelGrid","enableSorting","enableFiltering","sorting","columnFilters","columnVisibility","globalFilter","columnStatsCache","columnKeys","getColumnStats","cacheKey","clearStatsCache","columnDefs","stats","useVueTable","updater","getCoreRowModel","getSortedRowModel","getFilteredRowModel","filteredRowCount","totalRowCount","activeFilters","hasActiveFilter","column","setColumnFilter","setNumericRangeFilter","getNumericRangeFilter","setDateRangeFilter","getDateRangeFilter","clearAllFilters","getColumnFilterValues","toggleSort","current","getSortDirection","sort","coreExportToCSV","coreExportPivotToCSV","coreCopyToClipboard","coreFormatSelection","usePagination","pageSize","currentPage","totalPages","paginatedData","start","end","startIndex","endIndex","goToPage","page","nextPage","prevPage","firstPage","lastPage","setPageSize","size","useGlobalSearch","searchTerm","caseSensitive","filteredData","term","clearSearch","useRowSelection","selectedRowIndices","selectedRows","allSelected","someSelected","toggleRow","index","selectRow","deselectRow","_","deselectAll","toggleAll","isSelected","selectRange","useColumnResize","initialWidths","minWidth","maxWidth","columnWidths","isResizing","resizingColumn","startResize","startX","startWidth","handleMouseMove","diff","newWidth","handleMouseUp","resetColumnWidth","resetAllWidths","licenseKey","demoMode","licenseInfo","validationPromise","setLicenseKey","enableDemoMode","demoLicense","coreConfigureLicenseSecret","useLicense","coreIsPro","coreCanUsePivot","canUseAdvancedAggregations","canUsePercentageMode","coreCanUseCharts","coreCanUseAIAnalyst","showWatermark","coreShouldShowWatermark","requirePro","usePivotTable","currentStorageKey","unassignedFields","isConfigured","pivotResult","addRowField","removeRowField","addColumnField","removeColumnField","addValueField","removeValueField","updateValueFieldAggregation","oldAgg","newAgg","clearConfig","moveField","from","to","items","removed","autoSuggestConfig","categoricalFields","numericFields","addCalculatedField","existing","removeCalculatedField","id","newData","newKeys","savedConfig","currentConfig","aggregationOptions","aggregationRequiresPro","isAggregationAvailable","showCalcModal","editingCalcField","numericFieldNames","openCalcModal","handleSaveCalcField","handleTotalsToggle","checked","calculatedFieldsAsStats","calc","allAvailableFields","assignedFields","rowSet","colSet","valueMap","valSet","assignedCount","fieldSearch","filteredUnassignedFields","search","fieldName","displayName","getFieldIcon","isCalculated","getFieldDisplayName","handleAggregationChange","currentAgg","toggleRowColumn","currentAssignment","assignedTo","valueConfig","_withModifiers","CalculatedFieldModal","getValueFieldDisplayName","calcField","isCalculatedField","dragOverArea","reorderDragSource","reorderDropTarget","currentFontSize","fontSizeOptions","hasActiveFilters","filterSummary","filterTooltipDetails","maxDisplay","displayValues","remaining","showFilterTooltip","sortDirection","sortTarget","sortedRowIndices","indices","cmp","aHeader","bHeader","colIdx","aVal","bVal","columnHeaderCells","cells","colspan","selectedCell","selectionStart","selectionEnd","isSelecting","showCopyToast","copyToastMessage","handleCellMouseDown","rowIndex","colIndex","handleCellMouseEnter","isCellSelected","copySelectionToClipboard","sortedIdx","rowValues","cellCount","selectionStats","count","avg","formatStatValue","area","existingValue","handleChipDragStart","handleChipDragEnd","handleChipDragOver","handleChipDragLeave","handleChipDrop","targetIndex","sourceIndex","movedField","isChipDragSource","isChipDropTarget","rowHeaderWidth","dataColWidth","rowHeaderColWidth","numCols","getRowHeaderLeftOffset","fieldIdx","_Transition","filter","opt","levelIdx","_hoisted_52","_hoisted_53","_hoisted_54","_hoisted_55","_hoisted_56","_hoisted_57","_hoisted_58","_hoisted_59","MIN_COL_WIDTH","MAX_COL_WIDTH","showAIAnalyst","currentTheme","globalSearchTerm","showSearchInput","resizingColumnId","resizeStartX","resizeStartWidth","gridHeight","isResizingVertically","verticalResizeStartY","verticalResizeStartHeight","aiAnalystRef","aiLoadedData","displayData","dataRef","filteredDataForPivot","activeFilterInfo","coreFormatDate","pivotRowFields","pivotColumnFields","pivotValueFields","pivotShowRowTotals","pivotShowColumnTotals","pivotAvailableFields","pivotIsConfigured","clearPivotConfig","_autoSuggestConfig","searchFilteredData","totalSearchedRows","paginatedRows","paginationStart","paginationEnd","handleExport","viewMode","handlePivotExport","dataToExport","pivotFilename","rowCount","startColumnResize","handleResizeMove","handleResizeEnd","startVerticalResize","handleVerticalResizeMove","handleVerticalResizeEnd","newHeight","handleAIDataLoaded","isShowingAIData","isLoadingFullData","resetToFullData","fullData","handleAIConversationUpdate","handleAIQueryExecuted","handleAIError","handleAIViewResults","handleChartConfigChange","showPivotConfig","handleAddCalculatedField","handleRemoveCalculatedField","calcFieldKey","handleUpdateCalculatedField","handlePivotDragStart","handlePivotDragEnd","reorderRowFields","reorderColumnFields","tableContainerRef","tableBodyRef","activeFilterColumn","filterDropdownPosition","calculateColumnWidths","widths","sampleSize","ctx","width","openFilterDropdown","headerCell","rect","dropdownWidth","padding","left","spaceBelow","spaceAbove","top","maxHeight","closeFilterDropdown","handleFilter","handleRangeFilter","handleDateRangeFilter","handleSort","direction","activeFilterCount","selectColumn","handleHeaderClick","isCellInSelection","coreFormatNumber","updateSelection","newRow","newCol","scrollCellIntoView","handleMouseDown","handleMouseEnter","noFormatPatterns","shouldFormatNumber","handleTableScroll","handleWindowScroll","totalTableWidth","handleContainerClick","_withKeys","args","_withDirectives","AIAnalyst","PivotConfig","PivotSkeleton","ChartBuilder","ColumnFilter","dir"],"mappings":"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"}