{"version":3,"sources":["../src/columnHelper.ts","../src/features/cellFlash.ts","../src/features/export.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["// @zvndev/yable-core — createColumnHelper\n\nimport type {\n  RowData,\n  ColumnDef,\n  ColumnHelper,\n  AccessorKeyColumnDef,\n  AccessorFnColumnDef,\n  DisplayColumnDef,\n  GroupColumnDef,\n} from './types'\n\nexport function createColumnHelper<TData extends RowData>(): ColumnHelper<TData> {\n  return {\n    accessor: ((\n      accessorOrKey: string | ((row: TData, index: number) => unknown),\n      column: Record<string, unknown>,\n    ): ColumnDef<TData, unknown> => {\n      if (typeof accessorOrKey === 'function') {\n        return {\n          ...column,\n          accessorFn: accessorOrKey,\n          id: column.id ?? (typeof column.header === 'string' ? column.header : undefined),\n        } as unknown as AccessorFnColumnDef<TData, unknown>\n      }\n\n      return {\n        ...column,\n        accessorKey: accessorOrKey,\n        id: column?.id ?? String(accessorOrKey),\n      } as unknown as AccessorKeyColumnDef<TData, unknown>\n    }) as ColumnHelper<TData>['accessor'],\n\n    display: (column: DisplayColumnDef<TData, unknown>): ColumnDef<TData, unknown> => {\n      return column\n    },\n\n    group: (column: GroupColumnDef<TData, unknown>): ColumnDef<TData, unknown> => {\n      return column\n    },\n\n    columns: (columns: ReadonlyArray<ColumnDef<TData, unknown>>): ColumnDef<TData, unknown>[] => {\n      return [...columns]\n    },\n  }\n}\n","// @zvndev/yable-core — Cell Flash Feature\n// Detects data changes and produces flash metadata for cells whose values changed.\n\nimport type { RowData } from '../types'\n\nexport interface CellFlashConfig {\n  /** Enable cell flashing for this column */\n  enableCellFlash?: boolean\n  /** Flash duration in ms. Default: 700 */\n  flashDuration?: number\n  /** Color for increasing values. Default: 'green' */\n  flashUpColor?: string\n  /** Color for decreasing values. Default: 'red' */\n  flashDownColor?: string\n  /** Color for other changes. Default: 'blue' */\n  flashChangeColor?: string\n}\n\nexport interface CellFlashInfo {\n  columnId: string\n  rowId: string\n  direction: 'up' | 'down' | 'change'\n  previousValue: unknown\n  newValue: unknown\n  timestamp: number\n}\n\n/**\n * Compares old and new data arrays to find cells that changed value.\n * Returns a map of \"rowId:columnId\" -> CellFlashInfo for cells that changed.\n */\nexport function detectCellChanges<TData extends RowData>(\n  oldData: TData[],\n  newData: TData[],\n  columns: { id: string; enableCellFlash?: boolean }[],\n  getRowId: (row: TData, index: number) => string,\n): Map<string, CellFlashInfo> {\n  const flashes = new Map<string, CellFlashInfo>()\n\n  if (!oldData || !newData) return flashes\n\n  // Build old data map by row ID\n  const oldMap = new Map<string, TData>()\n  for (let i = 0; i < oldData.length; i++) {\n    const row = oldData[i]\n    if (row === undefined) continue\n    const id = getRowId(row, i)\n    oldMap.set(id, row)\n  }\n\n  // Compare new data with old\n  for (let i = 0; i < newData.length; i++) {\n    const newRow = newData[i]\n    if (newRow === undefined) continue\n    const rowId = getRowId(newRow, i)\n    const oldRow = oldMap.get(rowId)\n    if (!oldRow) continue\n\n    for (const col of columns) {\n      if (!col.enableCellFlash) continue\n\n      const oldVal = (oldRow as Record<string, unknown>)[col.id]\n      const newVal = (newRow as Record<string, unknown>)[col.id]\n\n      if (oldVal !== newVal && oldVal !== undefined) {\n        let direction: 'up' | 'down' | 'change' = 'change'\n        if (typeof oldVal === 'number' && typeof newVal === 'number') {\n          direction = newVal > oldVal ? 'up' : 'down'\n        }\n\n        flashes.set(`${rowId}:${col.id}`, {\n          columnId: col.id,\n          rowId,\n          direction,\n          previousValue: oldVal,\n          newValue: newVal,\n          timestamp: Date.now(),\n        })\n      }\n    }\n  }\n\n  return flashes\n}\n","// @zvndev/yable-core — Export Utilities\n// Export table data as CSV or JSON strings.\n\nimport type { RowData, Table, Column, Row } from '../types'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ExportOptions {\n  /** Which columns to include (default: all visible) */\n  columns?: string[]\n  /** Whether to include column headers (default: true) */\n  includeHeaders?: boolean\n  /** Custom value formatter per column */\n  formatters?: Record<string, (value: unknown) => string>\n  /** File name without extension */\n  fileName?: string\n}\n\nexport interface CsvExportOptions extends ExportOptions {\n  /** Delimiter character (default: ',') */\n  delimiter?: string\n  /** Add BOM for Excel compatibility (default: true) */\n  bom?: boolean\n  /** Quote character (default: '\"') */\n  quoteChar?: string\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the header text for a column. Falls back to the column id if\n * the `header` property is a function or missing.\n */\nfunction getHeaderText<TData extends RowData>(col: Column<TData, unknown>): string {\n  const header = col.columnDef.header\n  return typeof header === 'string' ? header : col.id\n}\n\n/**\n * Get the cell value for a row/column, applying a formatter if one exists.\n */\nfunction getCellString<TData extends RowData>(\n  row: Row<TData>,\n  col: Column<TData, unknown>,\n  formatters?: Record<string, (value: unknown) => string>,\n): string {\n  const raw = row.getValue(col.id)\n  if (formatters && col.id in formatters) {\n    return formatters[col.id]!(raw)\n  }\n  if (raw === null || raw === undefined) return ''\n  return String(raw)\n}\n\n/**\n * Resolve which columns to export from the table.\n */\nfunction resolveColumns<TData extends RowData>(\n  table: Table<TData>,\n  columnIds?: string[],\n): Column<TData, unknown>[] {\n  if (columnIds && columnIds.length > 0) {\n    return columnIds\n      .map((id) => table.getColumn(id))\n      .filter((col): col is Column<TData, unknown> => col !== undefined)\n  }\n  return table.getVisibleLeafColumns()\n}\n\nconst CSV_FORMULA_PREFIX = /^[=+\\-@\\t\\r]/\n\n/**\n * Sanitize a value that could be interpreted as a formula by spreadsheet\n * software (Excel, Google Sheets). Prefixes with a tab character to\n * neutralise formula interpretation while preserving the displayed value.\n */\nfunction sanitizeFormulaInjection(value: string): string {\n  if (CSV_FORMULA_PREFIX.test(value)) {\n    return '\\t' + value\n  }\n  return value\n}\n\n/**\n * Quote a CSV value if it contains the delimiter, a newline, or the quote\n * character. Escape quote characters by doubling them.\n */\nfunction quoteCsvValue(value: string, delimiter: string, quoteChar: string): string {\n  if (\n    value.includes(delimiter) ||\n    value.includes('\\n') ||\n    value.includes('\\r') ||\n    value.includes(quoteChar)\n  ) {\n    const escaped = value.replace(\n      new RegExp(quoteChar.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n      quoteChar + quoteChar,\n    )\n    return quoteChar + escaped + quoteChar\n  }\n  return value\n}\n\n// ---------------------------------------------------------------------------\n// exportToCsv\n// ---------------------------------------------------------------------------\n\n/**\n * Export table data as a CSV string.\n * Handles quoting (values containing delimiter, newline, or quote char),\n * and optionally prepends a UTF-8 BOM for Excel.\n */\nexport function exportToCsv<TData extends RowData>(\n  table: Table<TData>,\n  options?: CsvExportOptions,\n): string {\n  const delimiter = options?.delimiter ?? ','\n  const bom = options?.bom ?? true\n  const quoteChar = options?.quoteChar ?? '\"'\n  const includeHeaders = options?.includeHeaders ?? true\n\n  const columns = resolveColumns(table, options?.columns)\n  const rows = table.getRowModel().rows\n\n  const lines: string[] = []\n\n  // Header row\n  if (includeHeaders) {\n    const headerLine = columns\n      .map((col) => quoteCsvValue(getHeaderText(col), delimiter, quoteChar))\n      .join(delimiter)\n    lines.push(headerLine)\n  }\n\n  // Data rows\n  for (const row of rows) {\n    const line = columns\n      .map((col) => {\n        const value = sanitizeFormulaInjection(getCellString(row, col, options?.formatters))\n        return quoteCsvValue(value, delimiter, quoteChar)\n      })\n      .join(delimiter)\n    lines.push(line)\n  }\n\n  const csv = lines.join('\\n')\n  return bom ? '﻿' + csv : csv\n}\n\n// ---------------------------------------------------------------------------\n// exportToJson\n// ---------------------------------------------------------------------------\n\n/**\n * Export table data as a JSON string.\n * Returns an array of objects keyed by column header text.\n */\nexport function exportToJson<TData extends RowData>(\n  table: Table<TData>,\n  options?: ExportOptions,\n): string {\n  const columns = resolveColumns(table, options?.columns)\n  const rows = table.getRowModel().rows\n  const includeHeaders = options?.includeHeaders ?? true\n\n  const data = rows.map((row) => {\n    const obj: Record<string, unknown> = {}\n    for (const col of columns) {\n      const key = includeHeaders ? getHeaderText(col) : col.id\n      const raw = row.getValue(col.id)\n      if (options?.formatters && col.id in options.formatters) {\n        obj[key] = options.formatters[col.id]!(raw)\n      } else {\n        obj[key] = raw ?? null\n      }\n    }\n    return obj\n  })\n\n  return JSON.stringify(data, null, 2)\n}\n"]}