@smallwebco/tinypivot-vue 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tinypivot-vue.js","sources":["../../core/dist/types/index.js","../../core/dist/utils/index.js","../../core/dist/pivot/index.js","../../core/dist/license/index.js","../../core/dist/export/index.js","../src/composables/useExcelGrid.ts","../src/composables/useLicense.ts","../src/composables/usePivotTable.ts","../src/composables/useGridFeatures.ts","../src/components/NumericRangeFilter.vue","../src/components/ColumnFilter.vue","../src/components/CalculatedFieldModal.vue","../src/components/PivotConfig.vue","../src/components/PivotSkeleton.vue","../src/components/DataGrid.vue"],"sourcesContent":["/**\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 return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n ('min' in value || 'max' in value);\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 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 }\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 };\n}\n/**\n * Format cell value for display\n */\nexport function formatCellValue(value, type) {\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 // Format with commas for large numbers\n if (Math.abs(num) >= 1000) {\n return num.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n return num.toLocaleString('en-US', { maximumFractionDigits: 4 });\n }\n case 'date': {\n const date = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(date.getTime()))\n return String(value);\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n }\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, options) {\n if (value === null)\n return '-';\n const maxDigits = options?.maximumFractionDigits ?? (Math.abs(value) >= 1000 ? 2 : 4);\n return value.toLocaleString('en-US', { maximumFractionDigits: maxDigits });\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, 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) {\n if (value === null)\n return '-';\n if (fn === 'count' || fn === 'countDistinct') {\n return Math.round(value).toLocaleString();\n }\n if (fn === 'percentOfTotal') {\n return `${value.toFixed(1)}%`;\n }\n if (fn === 'stdDev') {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n return value.toLocaleString('en-US', { maximumFractionDigits: 4 });\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) {\n if (value === null)\n return '-';\n switch (formatAs) {\n case 'percent':\n return `${value.toFixed(decimals)}%`;\n case 'currency':\n return value.toLocaleString('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n });\n default:\n return value.toLocaleString('en-US', {\n minimumFractionDigits: 0,\n maximumFractionDigits: decimals,\n });\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-zA-Z_][a-zA-Z0-9_]*/g) || [];\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 // eslint-disable-next-line no-new-func\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 // eslint-disable-next-line no-new-func\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","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 },\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 },\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 },\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 * Import the public key for verification\n */\nasync function importPublicKey() {\n try {\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 crypto.subtle.importKey('spki', new Uint8Array(binaryKey).buffer, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);\n }\n catch {\n return null;\n }\n}\n/**\n * ECDSA P-256 signature verification\n * Verifies that the license was signed with our private key\n */\nasync function verifySignature(typeCode, signature, expiry) {\n const payload = `TP-${typeCode}-${expiry}`;\n try {\n const publicKey = await importPublicKey();\n if (!publicKey)\n return false;\n const encoder = new TextEncoder();\n const msgData = encoder.encode(payload);\n // Convert DER-encoded signature to raw format for Web Crypto\n const derSig = base64ToUint8Array(signature);\n const rawSig = derToRaw(derSig);\n return await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, publicKey, new Uint8Array(rawSig).buffer, msgData);\n }\n catch {\n // Fallback for environments without crypto.subtle (SSR, older browsers)\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 },\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 encoder = new TextEncoder();\n const data = encoder.encode(secret);\n const hashBuffer = await crypto.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 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 * 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","/**\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 {\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useVueTable,\n} from '@tanstack/vue-table'\nimport { type Ref, computed, ref, watch } from 'vue'\nimport type { ColumnStats, NumericRange, ColumnFilterValue } from '@smallwebco/tinypivot-core'\nimport { getColumnUniqueValues, formatCellValue, isNumericRange } from '@smallwebco/tinypivot-core'\n\n// Re-export for convenience\nexport { getColumnUniqueValues, formatCellValue, 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 and numeric range filtering\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst multiSelectFilter: FilterFn<any> = (row, columnId, filterValue: ColumnFilterValue | undefined) => {\n if (!filterValue) 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)) return false\n \n const { min, max } = filterValue\n if (min !== null && num < min) return false\n if (max !== null && num > max) 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) 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\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 both array values and numeric 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 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 }\n })\n })\n\n // Check if column has active filter (handles both array and numeric range)\n function hasActiveFilter(columnId: string): boolean {\n const column = table.getColumn(columnId)\n if (!column) return false\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (!filterValue) 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 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 } 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) 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 // 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) 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 } else if (!current.desc) {\n sorting.value = [{ id: columnId, desc: true }]\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) 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 }\n}\n\n\n","/**\n * License Management Composable for Vue\n * Wraps core license logic with Vue reactivity\n */\nimport { computed, ref } from 'vue'\nimport type { LicenseInfo } from '@smallwebco/tinypivot-core'\nimport {\n validateLicenseKey,\n configureLicenseSecret as coreConfigureLicenseSecret,\n getDemoLicenseInfo,\n getFreeLicenseInfo,\n canUsePivot as coreCanUsePivot,\n isPro as coreIsPro,\n shouldShowWatermark as coreShouldShowWatermark,\n logProRequired,\n} from '@smallwebco/tinypivot-core'\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] Invalid or expired license key. Running in free mode.')\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 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 showWatermark,\n requirePro,\n }\n}\n\n\n","/**\n * Pivot Table Composable for Vue\n * Wraps core pivot logic with Vue reactivity\n */\nimport { type Ref, computed, ref, watch } from 'vue'\nimport type { AggregationFunction, CalculatedField, FieldStats, PivotConfig, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n computeAvailableFields,\n getUnassignedFields,\n isPivotConfigured,\n computePivotResult,\n generateStorageKey,\n savePivotConfig,\n loadPivotConfig,\n isConfigValidForFields,\n getAggregationLabel,\n loadCalculatedFields,\n saveCalculatedFields,\n} from '@smallwebco/tinypivot-core'\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) return null\n\n // Check license for pivot feature\n if (!canUsePivot.value) 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 } 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 } 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')) return\n if (availableFields.value.length === 0) 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 } 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) 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 } 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 } 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) 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\n\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'\nimport type { PaginationOptions, SelectionBounds, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n exportToCSV as coreExportToCSV,\n exportPivotToCSV as coreExportPivotToCSV,\n copyToClipboard as coreCopyToClipboard,\n formatSelectionForClipboard as coreFormatSelection,\n} from '@smallwebco/tinypivot-core'\nimport type { PivotExportData, ExportOptions } from '@smallwebco/tinypivot-core'\n\n// Re-export core functions\nexport {\n exportToCSV,\n exportPivotToCSV,\n copyToClipboard,\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) 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 } 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 } 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\n\n","<script setup lang=\"ts\">\n/**\n * Numeric Range Filter Component\n * Provides an intuitive dual-handle slider and input fields for filtering numeric data\n */\nimport { computed, ref, watch } from 'vue'\nimport type { NumericRange } from '@smallwebco/tinypivot-core'\n\nconst props = defineProps<{\n dataMin: number\n dataMax: number\n currentRange: NumericRange | null\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) return 1\n if (range <= 1) return 0.01\n if (range <= 10) return 0.1\n if (range <= 100) return 1\n if (range <= 1000) return 10\n return Math.pow(10, Math.floor(Math.log10(range)) - 2)\n})\n\n// Format numbers for display\nconst formatValue = (val: number | null): string => {\n if (val === null) return ''\n if (Number.isInteger(val)) return val.toLocaleString()\n return val.toLocaleString(undefined, { maximumFractionDigits: 2 })\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) 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) 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 } 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 } 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 } 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 } 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 } 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\n","<script setup lang=\"ts\">\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 */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport type { ColumnStats, NumericRange } from '@smallwebco/tinypivot-core'\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}>()\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}>()\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 columns\nconst isNumericColumn = computed(() => props.stats.type === 'number' && \n props.stats.numericMin !== undefined && \n props.stats.numericMax !== undefined)\n\n// Determine initial mode based on existing filters\nconst filterMode = ref<FilterMode>(props.numericRange ? 'range' : 'values')\n\n// Local range for the numeric filter\nconst localRange = ref<NumericRange | null>(props.numericRange ?? null)\n\n// Get all possible values including blank\nconst allPossibleValues = computed(() => {\n const values = [...props.stats.uniqueValues]\n if (props.stats.nullCount > 0) {\n values.unshift('(blank)')\n }\n return values\n})\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// Check states\nconst isAllSelected = computed(() => {\n return allValues.value.every(v => localSelected.value.has(v))\n})\n\nconst isNoneSelected = computed(() => {\n return localSelected.value.size === 0\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// 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</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=\"isNumericColumn ? 'Sort Low to High' : 'Sort A to Z'\"\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>{{ isNumericColumn ? '1→9' : 'A→Z' }}</span>\n </button>\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'desc' }\"\n :title=\"isNumericColumn ? 'Sort High to Low' : 'Sort Z to A'\"\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>{{ isNumericColumn ? '9→1' : 'Z→A' }}</span>\n </button>\n </div>\n\n <div class=\"vpg-divider\" />\n\n <!-- Filter Mode Tabs (only for numeric columns) -->\n <div v-if=\"isNumericColumn\" 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 || 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 <!-- Range Filter Mode -->\n <template v-else>\n <NumericRangeFilter\n :data-min=\"stats.numericMin!\"\n :data-max=\"stats.numericMax!\"\n :current-range=\"localRange\"\n @change=\"handleRangeChange\"\n />\n\n <!-- Footer for Range Mode -->\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 </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\n","<script setup lang=\"ts\">\n/**\n * Calculated Field Modal\n * UI for creating custom calculated fields with formulas\n */\nimport { ref, computed, watch } from 'vue'\nimport type { CalculatedField } from '@smallwebco/tinypivot-core'\nimport {\n validateSimpleFormula,\n} from '@smallwebco/tinypivot-core'\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 } 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()) 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')\">×</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\">Use field names with math operators: + - * / ( )</div>\n <div v-if=\"validationError\" class=\"vpg-error\">{{ validationError }}</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('+')\">+</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('-')\">−</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('*')\">×</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('/')\">÷</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('(')\">(</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator(')')\">)</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\">Number</option>\n <option value=\"percent\">Percentage</option>\n <option value=\"currency\">Currency ($)</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\">{{ error }}</div>\n </div>\n\n <div class=\"vpg-modal-footer\">\n <button class=\"vpg-btn vpg-btn-secondary\" @click=\"emit('close')\">Cancel</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\n","<script setup lang=\"ts\">\n/**\n * Pivot Table Configuration Panel\n * Draggable fields with aggregation selection\n */\nimport { computed, ref } from 'vue'\nimport type { AggregationFunction, PivotValueField, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { AGGREGATION_OPTIONS, getAggregationSymbol } from '@smallwebco/tinypivot-core'\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\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 } 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(() => {\n if (!props.calculatedFields) 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(() => [\n ...props.availableFields.map(f => ({ ...f, isCalculated: false })),\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) 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\">Active</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 >✎</button>\n <button\n class=\"vpg-field-delete\"\n title=\"Delete calculated field\"\n @click.stop=\"emit('removeCalculatedField', field.calcId)\"\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\" @click=\"openCalcModal()\" title=\"Add calculated field (e.g. Profit Margin %)\">\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\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\n</style>\n\n","<script setup lang=\"ts\">\n/**\n * Pivot Table Skeleton + Data Display\n * Visual layout for pivot configuration and results\n */\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\nimport type { AggregationFunction, PivotResult, PivotValueField, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { getAggregationLabel, getAggregationSymbol } from '@smallwebco/tinypivot-core'\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\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 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\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) 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) 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) 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 } 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) 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) 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) 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) 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) 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) 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) return `${(val / 1_000_000).toFixed(2)}M`\n if (Math.abs(val) >= 1_000) 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 } 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</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\">Active Filters</div>\n <div v-for=\"filter in filterTooltipDetails\" :key=\"filter.column\" class=\"vpg-tooltip-filter\">\n <div class=\"vpg-tooltip-column\">{{ filter.column }}</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)\">×</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)\">×</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)\">×</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 <th\n v-if=\"levelIdx === 0\"\n class=\"vpg-row-header-label\"\n :rowspan=\"columnHeaderCells.length\"\n :style=\"{ width: `${rowHeaderWidth}px` }\"\n @click=\"toggleSort('row')\"\n >\n <div class=\"vpg-header-content\">\n <span>{{ rowFields.join(' / ') || 'Rows' }}</span>\n <span class=\"vpg-sort-indicator\" :class=\"{ active: sortTarget === 'row' }\">\n {{ sortTarget === 'row' ? (sortDirection === 'asc' ? '↑' : '↓') : '⇅' }}\n </span>\n </div>\n </th>\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 class=\"vpg-row-header-cell\"\n :style=\"{ width: `${rowHeaderWidth}px` }\"\n >\n <span v-for=\"(val, idx) in pivotResult.rowHeaders[sortedIdx]\" :key=\"idx\" class=\"vpg-row-value\">\n {{ val }}\n </span>\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 class=\"vpg-row-header-cell vpg-total-label\" :style=\"{ width: `${rowHeaderWidth}px` }\">\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}\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: 0;\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: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: 0;\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.vpg-row-value + .vpg-row-value::before {\n content: ' / ';\n color: #94a3b8;\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\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\n","<script setup lang=\"ts\">\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 { usePivotTable } from '../composables/usePivotTable'\nimport { useLicense } from '../composables/useLicense'\nimport {\n exportToCSV,\n exportPivotToCSV,\n copyToClipboard,\n formatSelectionForClipboard,\n} from '../composables/useGridFeatures'\nimport type { ColumnStats, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { loadCalculatedFields, saveCalculatedFields } from '@smallwebco/tinypivot-core'\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}>(), {\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})\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}>()\n\nconst { showWatermark, canUsePivot, isDemo, isPro } = useLicense()\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// Grid composable\nconst dataRef = computed(() => props.data)\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} = 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) 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) parts.push(`≥ ${f.range.min}`)\n if (f.range.max !== null) 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 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,\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) 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) return 1\n return Math.max(1, Math.ceil(totalSearchedRows.value / props.pageSize))\n})\n\nconst paginatedRows = computed(() => {\n if (!props.enablePagination) 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) 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\n// Pagination methods\nfunction goToPage(page: number) {\n currentPage.value = Math.max(1, Math.min(page, totalPages.value))\n}\n\nfunction nextPage() {\n if (currentPage.value < totalPages.value) currentPage.value++\n}\n\nfunction prevPage() {\n if (currentPage.value > 1) 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) 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) 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) 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) 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) 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) 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<'grid' | 'pivot'>('grid')\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 (props.data.length === 0)\n return\n\n const widths: Record<string, number> = {}\n const sampleSize = Math.min(100, props.data.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 = props.data[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 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 if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n return value.toLocaleString('en-US', { maximumFractionDigits: 4 })\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 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 num.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n\n if (Number.isInteger(num)) {\n return String(num)\n }\n return num.toLocaleString('en-US', { maximumFractionDigits: 4, useGrouping: false })\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\nwatch(() => props.data, () => {\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 <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 </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 <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 <!-- 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=\"data.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>\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 <!-- 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>\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 </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></span>\n <span></span>\n <span></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 @filter=\"(values) => handleFilter(activeFilterColumn!, values)\"\n @range-filter=\"(range) => handleRangeFilter(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-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}\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-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</style>\n\n"],"names":["isNumericRange","value","detectColumnType","values","nonNullValues","v","sample","numberCount","dateCount","booleanCount","val","threshold","detectFieldType","data","field","row","uniqueSet","isNumeric","getColumnUniqueValues","columnKey","maxValues","nullCount","numericMin","numericMax","num","uniqueValues","a","b","numA","numB","columnType","formatCellValue","type","date","makeKey","fields","f","parseKey","key","calculateMedian","sorted","mid","calculateStdDev","mean","avgSquaredDiff","aggregate","fn","grandTotal","customFn","allFieldValues","sum","formatAggregatedValue","getAggregationLabel","customLabel","getAggregationSymbol","customSymbol","AGGREGATION_OPTIONS","formatCalculatedValue","formatAs","decimals","parseSimpleFormula","formula","matches","keywords","m","validateSimpleFormula","availableFields","referencedFields","lowerFields","testExpr","escaped","evaluateSimpleFormula","fieldNames","expression","actualField","result","computeAvailableFields","getUnassignedFields","rowFields","columnFields","valueFields","assigned","isPivotConfigured","config","computePivotResult","showRowTotals","showColumnTotals","calculatedFields","calcFieldMap","cf","allDataFieldNames","rowKeySet","colKeySet","dataMap","rowKey","colKey","colMap","valueArrays","i","vf","calcId","calcDef","rowKeys","colKeys","grandTotals","total","getValueFieldLabel","headers","repeatCount","level","headerRow","parts","valueLabels","rowHeaders","pivotData","rowTotals","columnTotalsMap","rowData","rowAllValues","rawValues","fi","colTotals","vfIdx","gtValue","aggValue","formattedValue","columnTotals","colRawValues","allRawValues","vals","STORAGE_KEY_PREFIX","generateStorageKey","columns","hash","savePivotConfig","loadPivotConfig","stored","isConfigValidForFields","availableFieldNames","available","CALC_FIELDS_KEY","saveCalculatedFields","loadCalculatedFields","FREE_LICENSE","INVALID_LICENSE","DEMO_LICENSE","PUBLIC_KEY_PEM","base64ToUint8Array","base64","standardBase64","binaryString","bytes","derToRaw","der","offset","rLen","r","sLen","s","padR","padS","raw","importPublicKey","pemContents","binaryKey","verifySignature","typeCode","signature","expiry","payload","publicKey","msgData","derSig","rawSig","validateLicenseKey","lastDashIdx","expiryStr","withoutPrefix","secondDashIdx","year","month","day","expiresAt","configureLicenseSecret","_secret","DEMO_SECRET_HASH","hashSecret","secret","hashBuffer","getDemoLicenseInfo","getFreeLicenseInfo","canUsePivot","info","isPro","shouldShowWatermark","isDemo","logProRequired","feature","escapeCSV","delimiter","str","exportToCSV","options","filename","includeHeaders","rows","col","csvContent","downloadFile","exportPivotToCSV","_columnFields","rowHeaderColCount","rowIdx","csvRow","rowHeader","cell","totalsRow","content","mimeType","blob","url","link","copyToClipboard","text","onSuccess","onError","formatSelectionForClipboard","selectionBounds","minRow","maxRow","minCol","maxCol","lines","c","colId","multiSelectFilter","columnId","filterValue","cellValue","min","max","cellString","useExcelGrid","enableSorting","enableFiltering","sorting","ref","columnFilters","columnVisibility","globalFilter","columnStatsCache","columnKeys","computed","getColumnStats","cacheKey","clearStatsCache","columnDefs","stats","table","useVueTable","updater","getCoreRowModel","getSortedRowModel","getFilteredRowModel","filteredRowCount","totalRowCount","activeFilters","hasActiveFilter","column","setColumnFilter","setNumericRangeFilter","range","getNumericRangeFilter","clearAllFilters","getColumnFilterValues","toggleSort","current","getSortDirection","sort","watch","licenseKey","demoMode","licenseInfo","validationPromise","setLicenseKey","enableDemoMode","demoLicense","coreConfigureLicenseSecret","useLicense","coreIsPro","coreCanUsePivot","canUseAdvancedAggregations","canUsePercentageMode","showWatermark","coreShouldShowWatermark","requirePro","usePivotTable","currentStorageKey","unassignedFields","isConfigured","pivotResult","addRowField","removeRowField","addColumnField","removeColumnField","addValueField","aggregation","removeValueField","updateValueFieldAggregation","oldAgg","newAgg","clearConfig","moveField","from","to","items","removed","autoSuggestConfig","categoricalFields","numericFields","addCalculatedField","existing","removeCalculatedField","id","newData","newKeys","storageKey","savedConfig","currentConfig","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","idx","allSelected","someSelected","toggleRow","index","selectRow","deselectRow","selectAll","_","deselectAll","toggleAll","isSelected","selectRange","useColumnResize","initialWidths","minWidth","maxWidth","columnWidths","isResizing","resizingColumn","startResize","event","startX","startWidth","handleMouseMove","e","diff","newWidth","handleMouseUp","resetColumnWidth","resetAllWidths","props","__props","emit","__emit","localMin","_a","localMax","_b","step","formatValue","isFilterActive","minPercent","maxPercent","handleMinSlider","target","handleMaxSlider","handleMinInput","handleMaxInput","clearFilter","emitChange","setFullRange","newRange","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","_normalizeStyle","_hoisted_8","_hoisted_9","_hoisted_11","_hoisted_13","_hoisted_15","_createTextVNode","searchQuery","dropdownRef","searchInputRef","isNumericColumn","filterMode","localRange","localSelected","hasBlankValues","filteredValues","query","allValues","toggleValue","clearAll","applyFilter","sortAscending","sortDescending","handleRangeChange","applyRangeFilter","clearRangeFilter","setFilterMode","mode","handleClickOutside","handleKeydown","onMounted","nextTick","onUnmounted","newValues","_normalizeClass","_hoisted_7","_Fragment","$event","_renderList","_createVNode","NumericRangeFilter","name","error","show","validationError","insertField","insertOperator","op","save","validationResult","_createBlock","_Teleport","_hoisted_6","_hoisted_10","_hoisted_12","_hoisted_14","_hoisted_16","_hoisted_17","aggregationOptions","aggregationRequiresPro","agg","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","handleDragStart","handleDragEnd","handleAggregationChange","currentAgg","toggleRowColumn","currentAssignment","removeField","assignedTo","valueConfig","_unref","_withModifiers","_hoisted_18","_hoisted_19","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","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","_d","_c","bVal","_f","_e","columnHeaderCells","cells","colspan","selectedCell","selectionStart","selectionEnd","isSelecting","showCopyToast","copyToastMessage","handleCellMouseDown","rowIndex","colIndex","handleCellMouseEnter","isCellSelected","copySelectionToClipboard","sortedIdx","rowValues","cellCount","err","selectionStats","count","avg","formatStatValue","handleDragOver","area","handleDragLeave","handleDrop","existingValue","handleChipDragStart","zone","handleChipDragEnd","handleChipDragOver","handleChipDragLeave","handleChipDrop","targetIndex","sourceIndex","movedField","isChipDragSource","isChipDropTarget","rowHeaderWidth","dataColWidth","_Transition","filter","opt","_hoisted_20","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_39","levelIdx","_hoisted_41","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","_hoisted_51","_hoisted_52","_hoisted_53","_hoisted_54","_hoisted_55","_hoisted_56","_hoisted_57","_hoisted_58","MIN_COL_WIDTH","MAX_COL_WIDTH","currentTheme","globalSearchTerm","showSearchInput","resizingColumnId","resizeStartX","resizeStartWidth","gridHeight","isResizingVertically","verticalResizeStartY","verticalResizeStartHeight","dataRef","filteredDataForPivot","activeFilterInfo","pivotRowFields","pivotColumnFields","pivotValueFields","pivotShowRowTotals","pivotShowColumnTotals","pivotAvailableFields","pivotIsConfigured","clearPivotConfig","searchFilteredData","totalSearchedRows","paginatedRows","paginationStart","paginationEnd","handleExport","viewMode","handlePivotExport","dataToExport","pivotFilename","rowCount","startColumnResize","handleResizeMove","handleResizeEnd","startVerticalResize","handleVerticalResizeMove","handleVerticalResizeEnd","newHeight","showPivotConfig","draggingField","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","handleSort","direction","activeFilterCount","selectColumn","handleHeaderClick","isCellInSelection","input","updateSelection","newRow","newCol","scrollCellIntoView","handleMouseDown","handleMouseEnter","noFormatPatterns","shouldFormatNumber","handleTableScroll","handleWindowScroll","totalTableWidth","handleContainerClick","_withKeys","args","PivotConfig","PivotSkeleton","_hoisted_42","ColumnFilter","dir"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tinypivot-vue.js","sources":["../../core/dist/types/index.js","../../core/dist/utils/index.js","../../core/dist/pivot/index.js","../../core/dist/license/index.js","../../core/dist/export/index.js","../src/composables/useExcelGrid.ts","../src/composables/useLicense.ts","../src/composables/usePivotTable.ts","../src/composables/useGridFeatures.ts","../src/components/NumericRangeFilter.vue","../src/components/ColumnFilter.vue","../src/components/CalculatedFieldModal.vue","../src/components/PivotConfig.vue","../src/components/PivotSkeleton.vue","../src/components/DataGrid.vue"],"sourcesContent":["/**\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 return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n ('min' in value || 'max' in value);\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 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 }\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 };\n}\n/**\n * Format cell value for display\n */\nexport function formatCellValue(value, type) {\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 // Format with commas for large numbers\n if (Math.abs(num) >= 1000) {\n return num.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n return num.toLocaleString('en-US', { maximumFractionDigits: 4 });\n }\n case 'date': {\n const date = value instanceof Date ? value : new Date(String(value));\n if (Number.isNaN(date.getTime()))\n return String(value);\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n }\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, options) {\n if (value === null)\n return '-';\n const maxDigits = options?.maximumFractionDigits ?? (Math.abs(value) >= 1000 ? 2 : 4);\n return value.toLocaleString('en-US', { maximumFractionDigits: maxDigits });\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, 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) {\n if (value === null)\n return '-';\n if (fn === 'count' || fn === 'countDistinct') {\n return Math.round(value).toLocaleString();\n }\n if (fn === 'percentOfTotal') {\n return `${value.toFixed(1)}%`;\n }\n if (fn === 'stdDev') {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 });\n }\n return value.toLocaleString('en-US', { maximumFractionDigits: 4 });\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) {\n if (value === null)\n return '-';\n switch (formatAs) {\n case 'percent':\n return `${value.toFixed(decimals)}%`;\n case 'currency':\n return value.toLocaleString('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n });\n default:\n return value.toLocaleString('en-US', {\n minimumFractionDigits: 0,\n maximumFractionDigits: decimals,\n });\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-zA-Z_][a-zA-Z0-9_]*/g) || [];\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 // eslint-disable-next-line no-new-func\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 // eslint-disable-next-line no-new-func\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","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 },\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 },\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 },\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 * Import the public key for verification\n */\nasync function importPublicKey() {\n try {\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 crypto.subtle.importKey('spki', new Uint8Array(binaryKey).buffer, { name: 'ECDSA', namedCurve: 'P-256' }, false, ['verify']);\n }\n catch {\n return null;\n }\n}\n/**\n * ECDSA P-256 signature verification\n * Verifies that the license was signed with our private key\n */\nasync function verifySignature(typeCode, signature, expiry) {\n const payload = `TP-${typeCode}-${expiry}`;\n try {\n const publicKey = await importPublicKey();\n if (!publicKey)\n return false;\n const encoder = new TextEncoder();\n const msgData = encoder.encode(payload);\n // Convert DER-encoded signature to raw format for Web Crypto\n const derSig = base64ToUint8Array(signature);\n const rawSig = derToRaw(derSig);\n return await crypto.subtle.verify({ name: 'ECDSA', hash: 'SHA-256' }, publicKey, new Uint8Array(rawSig).buffer, msgData);\n }\n catch {\n // Fallback for environments without crypto.subtle (SSR, older browsers)\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 },\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 encoder = new TextEncoder();\n const data = encoder.encode(secret);\n const hashBuffer = await crypto.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 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 * 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","/**\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 {\n getCoreRowModel,\n getFilteredRowModel,\n getSortedRowModel,\n useVueTable,\n} from '@tanstack/vue-table'\nimport { type Ref, computed, ref, watch } from 'vue'\nimport type { ColumnStats, NumericRange, ColumnFilterValue } from '@smallwebco/tinypivot-core'\nimport { getColumnUniqueValues, formatCellValue, isNumericRange } from '@smallwebco/tinypivot-core'\n\n// Re-export for convenience\nexport { getColumnUniqueValues, formatCellValue, 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 and numeric range filtering\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst multiSelectFilter: FilterFn<any> = (row, columnId, filterValue: ColumnFilterValue | undefined) => {\n if (!filterValue) 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)) return false\n \n const { min, max } = filterValue\n if (min !== null && num < min) return false\n if (max !== null && num > max) 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) 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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\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 both array values and numeric 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 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 }\n })\n })\n\n // Check if column has active filter (handles both array and numeric range)\n function hasActiveFilter(columnId: string): boolean {\n const column = table.getColumn(columnId)\n if (!column) return false\n const filterValue = column.getFilterValue() as ColumnFilterValue | undefined\n if (!filterValue) 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 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 } 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) 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 // 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) 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 } else if (!current.desc) {\n sorting.value = [{ id: columnId, desc: true }]\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) 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 }\n}\n\n\n","/**\n * License Management Composable for Vue\n * Wraps core license logic with Vue reactivity\n */\nimport { computed, ref } from 'vue'\nimport type { LicenseInfo } from '@smallwebco/tinypivot-core'\nimport {\n validateLicenseKey,\n configureLicenseSecret as coreConfigureLicenseSecret,\n getDemoLicenseInfo,\n getFreeLicenseInfo,\n canUsePivot as coreCanUsePivot,\n isPro as coreIsPro,\n shouldShowWatermark as coreShouldShowWatermark,\n logProRequired,\n} from '@smallwebco/tinypivot-core'\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] Invalid or expired license key. Running in free mode.')\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 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 showWatermark,\n requirePro,\n }\n}\n\n\n","/**\n * Pivot Table Composable for Vue\n * Wraps core pivot logic with Vue reactivity\n */\nimport { type Ref, computed, ref, watch } from 'vue'\nimport type { AggregationFunction, CalculatedField, FieldStats, PivotConfig, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n computeAvailableFields,\n getUnassignedFields,\n isPivotConfigured,\n computePivotResult,\n generateStorageKey,\n savePivotConfig,\n loadPivotConfig,\n isConfigValidForFields,\n getAggregationLabel,\n loadCalculatedFields,\n saveCalculatedFields,\n} from '@smallwebco/tinypivot-core'\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) return null\n\n // Check license for pivot feature\n if (!canUsePivot.value) 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 } 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 } 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')) return\n if (availableFields.value.length === 0) 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 } 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) 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 } 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 } 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) 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\n\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'\nimport type { PaginationOptions, SelectionBounds, PivotValueField } from '@smallwebco/tinypivot-core'\nimport {\n exportToCSV as coreExportToCSV,\n exportPivotToCSV as coreExportPivotToCSV,\n copyToClipboard as coreCopyToClipboard,\n formatSelectionForClipboard as coreFormatSelection,\n} from '@smallwebco/tinypivot-core'\nimport type { PivotExportData, ExportOptions } from '@smallwebco/tinypivot-core'\n\n// Re-export core functions\nexport {\n exportToCSV,\n exportPivotToCSV,\n copyToClipboard,\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) 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 } 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 } 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\n\n","<script setup lang=\"ts\">\n/**\n * Numeric Range Filter Component\n * Provides an intuitive dual-handle slider and input fields for filtering numeric data\n */\nimport { computed, ref, watch } from 'vue'\nimport type { NumericRange } from '@smallwebco/tinypivot-core'\n\nconst props = defineProps<{\n dataMin: number\n dataMax: number\n currentRange: NumericRange | null\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) return 1\n if (range <= 1) return 0.01\n if (range <= 10) return 0.1\n if (range <= 100) return 1\n if (range <= 1000) return 10\n return Math.pow(10, Math.floor(Math.log10(range)) - 2)\n})\n\n// Format numbers for display\nconst formatValue = (val: number | null): string => {\n if (val === null) return ''\n if (Number.isInteger(val)) return val.toLocaleString()\n return val.toLocaleString(undefined, { maximumFractionDigits: 2 })\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) 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) 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 } 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 } 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 } 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 } 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 } 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\n","<script setup lang=\"ts\">\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 */\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport type { ColumnStats, NumericRange } from '@smallwebco/tinypivot-core'\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}>()\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}>()\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 columns\nconst isNumericColumn = computed(() => props.stats.type === 'number' && \n props.stats.numericMin !== undefined && \n props.stats.numericMax !== undefined)\n\n// Determine initial mode based on existing filters\nconst filterMode = ref<FilterMode>(props.numericRange ? 'range' : 'values')\n\n// Local range for the numeric filter\nconst localRange = ref<NumericRange | null>(props.numericRange ?? null)\n\n// Get all possible values including blank\nconst allPossibleValues = computed(() => {\n const values = [...props.stats.uniqueValues]\n if (props.stats.nullCount > 0) {\n values.unshift('(blank)')\n }\n return values\n})\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// Check states\nconst isAllSelected = computed(() => {\n return allValues.value.every(v => localSelected.value.has(v))\n})\n\nconst isNoneSelected = computed(() => {\n return localSelected.value.size === 0\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// 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</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=\"isNumericColumn ? 'Sort Low to High' : 'Sort A to Z'\"\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>{{ isNumericColumn ? '1→9' : 'A→Z' }}</span>\n </button>\n <button\n class=\"vpg-sort-btn\"\n :class=\"{ active: sortDirection === 'desc' }\"\n :title=\"isNumericColumn ? 'Sort High to Low' : 'Sort Z to A'\"\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>{{ isNumericColumn ? '9→1' : 'Z→A' }}</span>\n </button>\n </div>\n\n <div class=\"vpg-divider\" />\n\n <!-- Filter Mode Tabs (only for numeric columns) -->\n <div v-if=\"isNumericColumn\" 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 || 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 <!-- Range Filter Mode -->\n <template v-else>\n <NumericRangeFilter\n :data-min=\"stats.numericMin!\"\n :data-max=\"stats.numericMax!\"\n :current-range=\"localRange\"\n @change=\"handleRangeChange\"\n />\n\n <!-- Footer for Range Mode -->\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 </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\n","<script setup lang=\"ts\">\n/**\n * Calculated Field Modal\n * UI for creating custom calculated fields with formulas\n */\nimport { ref, computed, watch } from 'vue'\nimport type { CalculatedField } from '@smallwebco/tinypivot-core'\nimport {\n validateSimpleFormula,\n} from '@smallwebco/tinypivot-core'\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 } 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()) 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')\">×</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\">Use field names with math operators: + - * / ( )</div>\n <div v-if=\"validationError\" class=\"vpg-error\">{{ validationError }}</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('+')\">+</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('-')\">−</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('*')\">×</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('/')\">÷</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator('(')\">(</button>\n <button class=\"vpg-insert-btn vpg-op-btn\" @click=\"insertOperator(')')\">)</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\">Number</option>\n <option value=\"percent\">Percentage</option>\n <option value=\"currency\">Currency ($)</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\">{{ error }}</div>\n </div>\n\n <div class=\"vpg-modal-footer\">\n <button class=\"vpg-btn vpg-btn-secondary\" @click=\"emit('close')\">Cancel</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\n","<script setup lang=\"ts\">\n/**\n * Pivot Table Configuration Panel\n * Draggable fields with aggregation selection\n */\nimport { computed, ref } from 'vue'\nimport type { AggregationFunction, PivotValueField, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { AGGREGATION_OPTIONS, getAggregationSymbol } from '@smallwebco/tinypivot-core'\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\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 } 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(() => {\n if (!props.calculatedFields) 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(() => [\n ...props.availableFields.map(f => ({ ...f, isCalculated: false })),\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) 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\">Active</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 >✎</button>\n <button\n class=\"vpg-field-delete\"\n title=\"Delete calculated field\"\n @click.stop=\"emit('removeCalculatedField', field.calcId)\"\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\" @click=\"openCalcModal()\" title=\"Add calculated field (e.g. Profit Margin %)\">\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\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\n</style>\n\n","<script setup lang=\"ts\">\n/**\n * Pivot Table Skeleton + Data Display\n * Visual layout for pivot configuration and results\n */\nimport { computed, ref, onMounted, onUnmounted } from 'vue'\nimport type { AggregationFunction, PivotResult, PivotValueField, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { getAggregationLabel, getAggregationSymbol } from '@smallwebco/tinypivot-core'\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\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 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\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) 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) 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) 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 } 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) 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) 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) 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) 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) 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) 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) return `${(val / 1_000_000).toFixed(2)}M`\n if (Math.abs(val) >= 1_000) 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 } 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\">Active Filters</div>\n <div v-for=\"filter in filterTooltipDetails\" :key=\"filter.column\" class=\"vpg-tooltip-filter\">\n <div class=\"vpg-tooltip-column\">{{ filter.column }}</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)\">×</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)\">×</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)\">×</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}\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\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\n","<script setup lang=\"ts\">\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 { usePivotTable } from '../composables/usePivotTable'\nimport { useLicense } from '../composables/useLicense'\nimport {\n exportToCSV,\n exportPivotToCSV,\n copyToClipboard,\n formatSelectionForClipboard,\n} from '../composables/useGridFeatures'\nimport type { ColumnStats, CalculatedField } from '@smallwebco/tinypivot-core'\nimport { loadCalculatedFields, saveCalculatedFields } from '@smallwebco/tinypivot-core'\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}>(), {\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})\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}>()\n\nconst { showWatermark, canUsePivot, isDemo, isPro } = useLicense()\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// Grid composable\nconst dataRef = computed(() => props.data)\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} = 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) 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) parts.push(`≥ ${f.range.min}`)\n if (f.range.max !== null) 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 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,\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) 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) return 1\n return Math.max(1, Math.ceil(totalSearchedRows.value / props.pageSize))\n})\n\nconst paginatedRows = computed(() => {\n if (!props.enablePagination) 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) 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\n// Pagination methods\nfunction goToPage(page: number) {\n currentPage.value = Math.max(1, Math.min(page, totalPages.value))\n}\n\nfunction nextPage() {\n if (currentPage.value < totalPages.value) currentPage.value++\n}\n\nfunction prevPage() {\n if (currentPage.value > 1) 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) 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) 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) 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) 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) 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) 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<'grid' | 'pivot'>('grid')\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 (props.data.length === 0)\n return\n\n const widths: Record<string, number> = {}\n const sampleSize = Math.min(100, props.data.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 = props.data[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 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 if (Math.abs(value) >= 1000) {\n return value.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n return value.toLocaleString('en-US', { maximumFractionDigits: 4 })\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 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 num.toLocaleString('en-US', { maximumFractionDigits: 2 })\n }\n\n if (Number.isInteger(num)) {\n return String(num)\n }\n return num.toLocaleString('en-US', { maximumFractionDigits: 4, useGrouping: false })\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\nwatch(() => props.data, () => {\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 <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 </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 <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 <!-- 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=\"data.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>\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 <!-- 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>\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 </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></span>\n <span></span>\n <span></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 @filter=\"(values) => handleFilter(activeFilterColumn!, values)\"\n @range-filter=\"(range) => handleRangeFilter(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-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}\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-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</style>\n\n"],"names":["isNumericRange","value","detectColumnType","values","nonNullValues","v","sample","numberCount","dateCount","booleanCount","val","threshold","detectFieldType","data","field","row","uniqueSet","isNumeric","getColumnUniqueValues","columnKey","maxValues","nullCount","numericMin","numericMax","num","uniqueValues","a","b","numA","numB","columnType","formatCellValue","type","date","makeKey","fields","f","parseKey","key","calculateMedian","sorted","mid","calculateStdDev","mean","avgSquaredDiff","aggregate","fn","grandTotal","customFn","allFieldValues","sum","formatAggregatedValue","getAggregationLabel","customLabel","getAggregationSymbol","customSymbol","AGGREGATION_OPTIONS","formatCalculatedValue","formatAs","decimals","parseSimpleFormula","formula","matches","keywords","m","validateSimpleFormula","availableFields","referencedFields","lowerFields","testExpr","escaped","evaluateSimpleFormula","fieldNames","expression","actualField","result","computeAvailableFields","getUnassignedFields","rowFields","columnFields","valueFields","assigned","isPivotConfigured","config","computePivotResult","showRowTotals","showColumnTotals","calculatedFields","calcFieldMap","cf","allDataFieldNames","rowKeySet","colKeySet","dataMap","rowKey","colKey","colMap","valueArrays","i","vf","calcId","calcDef","rowKeys","colKeys","grandTotals","total","getValueFieldLabel","headers","repeatCount","level","headerRow","parts","valueLabels","rowHeaders","pivotData","rowTotals","columnTotalsMap","rowData","rowAllValues","rawValues","fi","colTotals","vfIdx","gtValue","aggValue","formattedValue","columnTotals","colRawValues","allRawValues","vals","STORAGE_KEY_PREFIX","generateStorageKey","columns","hash","savePivotConfig","loadPivotConfig","stored","isConfigValidForFields","availableFieldNames","available","CALC_FIELDS_KEY","saveCalculatedFields","loadCalculatedFields","FREE_LICENSE","INVALID_LICENSE","DEMO_LICENSE","PUBLIC_KEY_PEM","base64ToUint8Array","base64","standardBase64","binaryString","bytes","derToRaw","der","offset","rLen","r","sLen","s","padR","padS","raw","importPublicKey","pemContents","binaryKey","verifySignature","typeCode","signature","expiry","payload","publicKey","msgData","derSig","rawSig","validateLicenseKey","lastDashIdx","expiryStr","withoutPrefix","secondDashIdx","year","month","day","expiresAt","configureLicenseSecret","_secret","DEMO_SECRET_HASH","hashSecret","secret","hashBuffer","getDemoLicenseInfo","getFreeLicenseInfo","canUsePivot","info","isPro","shouldShowWatermark","isDemo","logProRequired","feature","escapeCSV","delimiter","str","exportToCSV","options","filename","includeHeaders","rows","col","csvContent","downloadFile","exportPivotToCSV","_columnFields","rowHeaderColCount","rowIdx","csvRow","rowHeader","cell","totalsRow","content","mimeType","blob","url","link","copyToClipboard","text","onSuccess","onError","formatSelectionForClipboard","selectionBounds","minRow","maxRow","minCol","maxCol","lines","c","colId","multiSelectFilter","columnId","filterValue","cellValue","min","max","cellString","useExcelGrid","enableSorting","enableFiltering","sorting","ref","columnFilters","columnVisibility","globalFilter","columnStatsCache","columnKeys","computed","getColumnStats","cacheKey","clearStatsCache","columnDefs","stats","table","useVueTable","updater","getCoreRowModel","getSortedRowModel","getFilteredRowModel","filteredRowCount","totalRowCount","activeFilters","hasActiveFilter","column","setColumnFilter","setNumericRangeFilter","range","getNumericRangeFilter","clearAllFilters","getColumnFilterValues","toggleSort","current","getSortDirection","sort","watch","licenseKey","demoMode","licenseInfo","validationPromise","setLicenseKey","enableDemoMode","demoLicense","coreConfigureLicenseSecret","useLicense","coreIsPro","coreCanUsePivot","canUseAdvancedAggregations","canUsePercentageMode","showWatermark","coreShouldShowWatermark","requirePro","usePivotTable","currentStorageKey","unassignedFields","isConfigured","pivotResult","addRowField","removeRowField","addColumnField","removeColumnField","addValueField","aggregation","removeValueField","updateValueFieldAggregation","oldAgg","newAgg","clearConfig","moveField","from","to","items","removed","autoSuggestConfig","categoricalFields","numericFields","addCalculatedField","existing","removeCalculatedField","id","newData","newKeys","storageKey","savedConfig","currentConfig","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","idx","allSelected","someSelected","toggleRow","index","selectRow","deselectRow","selectAll","_","deselectAll","toggleAll","isSelected","selectRange","useColumnResize","initialWidths","minWidth","maxWidth","columnWidths","isResizing","resizingColumn","startResize","event","startX","startWidth","handleMouseMove","e","diff","newWidth","handleMouseUp","resetColumnWidth","resetAllWidths","props","__props","emit","__emit","localMin","_a","localMax","_b","step","formatValue","isFilterActive","minPercent","maxPercent","handleMinSlider","target","handleMaxSlider","handleMinInput","handleMaxInput","clearFilter","emitChange","setFullRange","newRange","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_cache","_hoisted_3","_toDisplayString","_hoisted_4","_hoisted_5","_normalizeStyle","_hoisted_8","_hoisted_9","_hoisted_11","_hoisted_13","_hoisted_15","_createTextVNode","searchQuery","dropdownRef","searchInputRef","isNumericColumn","filterMode","localRange","localSelected","hasBlankValues","filteredValues","query","allValues","toggleValue","clearAll","applyFilter","sortAscending","sortDescending","handleRangeChange","applyRangeFilter","clearRangeFilter","setFilterMode","mode","handleClickOutside","handleKeydown","onMounted","nextTick","onUnmounted","newValues","_normalizeClass","_hoisted_7","_Fragment","$event","_renderList","_createVNode","NumericRangeFilter","name","error","show","validationError","insertField","insertOperator","op","save","validationResult","_createBlock","_Teleport","_hoisted_6","_hoisted_10","_hoisted_12","_hoisted_14","_hoisted_16","_hoisted_17","aggregationOptions","aggregationRequiresPro","agg","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","handleDragStart","handleDragEnd","handleAggregationChange","currentAgg","toggleRowColumn","currentAssignment","removeField","assignedTo","valueConfig","_unref","_withModifiers","_hoisted_18","_hoisted_19","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","_hoisted_28","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","_d","_c","bVal","_f","_e","columnHeaderCells","cells","colspan","selectedCell","selectionStart","selectionEnd","isSelecting","showCopyToast","copyToastMessage","handleCellMouseDown","rowIndex","colIndex","handleCellMouseEnter","isCellSelected","copySelectionToClipboard","sortedIdx","rowValues","cellCount","err","selectionStats","count","avg","formatStatValue","handleDragOver","area","handleDragLeave","handleDrop","existingValue","handleChipDragStart","zone","handleChipDragEnd","handleChipDragOver","handleChipDragLeave","handleChipDrop","targetIndex","sourceIndex","movedField","isChipDragSource","isChipDropTarget","rowHeaderWidth","dataColWidth","rowHeaderColWidth","numCols","getRowHeaderLeftOffset","fieldIdx","_Transition","filter","opt","_hoisted_20","_hoisted_29","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_33","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_39","levelIdx","_hoisted_41","_hoisted_43","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","_hoisted_48","_hoisted_49","_hoisted_50","_hoisted_51","_hoisted_52","_hoisted_53","_hoisted_54","_hoisted_55","_hoisted_56","_hoisted_57","_hoisted_58","_hoisted_59","MIN_COL_WIDTH","MAX_COL_WIDTH","currentTheme","globalSearchTerm","showSearchInput","resizingColumnId","resizeStartX","resizeStartWidth","gridHeight","isResizingVertically","verticalResizeStartY","verticalResizeStartHeight","dataRef","filteredDataForPivot","activeFilterInfo","pivotRowFields","pivotColumnFields","pivotValueFields","pivotShowRowTotals","pivotShowColumnTotals","pivotAvailableFields","pivotIsConfigured","clearPivotConfig","searchFilteredData","totalSearchedRows","paginatedRows","paginationStart","paginationEnd","handleExport","viewMode","handlePivotExport","dataToExport","pivotFilename","rowCount","startColumnResize","handleResizeMove","handleResizeEnd","startVerticalResize","handleVerticalResizeMove","handleVerticalResizeEnd","newHeight","showPivotConfig","draggingField","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","handleSort","direction","activeFilterCount","selectColumn","handleHeaderClick","isCellInSelection","input","updateSelection","newRow","newCol","scrollCellIntoView","handleMouseDown","handleMouseEnter","noFormatPatterns","shouldFormatNumber","handleTableScroll","handleWindowScroll","totalTableWidth","handleContainerClick","_withKeys","args","PivotConfig","PivotSkeleton","_hoisted_42","ColumnFilter","dir"],"mappings":"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"}
|