{"version":3,"sources":["../../src/features/rowSpanning.ts"],"names":[],"mappings":";;;AA+BA,SAAS,OAAA,CAAQ,UAAkB,QAAA,EAA0B;AAC3D,EAAA,OAAO,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAA;AAChC;AAiBO,SAAS,eAAA,CACd,MACA,UAAA,EACY;AACZ,EAAA,MAAM,GAAA,uBAAsB,GAAA,EAAI;AAEhC,EAAA,KAAA,MAAW,UAAU,UAAA,EAAY;AAE/B,IAAA,MAAM,YAAa,MAAA,CAA6D,OAAA;AAChF,IAAA,IAAI,CAAC,SAAA,EAAW;AAEhB,IAAA,MAAM,WACJ,MAAA,CAAO,EAAA,KAAO,aAAA,IAAiB,MAAA,GAAU,OAAO,WAAA,GAAyB,MAAA,CAAA;AAC3E,IAAA,IAAI,CAAC,QAAA,EAAU;AAEf,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,OAAO,CAAA,GAAI,KAAK,MAAA,EAAQ;AACtB,MAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAGlB,MAAA,IAAI,IAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAA,GAAO,SAAA,CAAU,GAAA,EAAK,IAAA,EAAM,CAAC,CAAA,IAAK,CAAA;AAAA,MACpC,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,MAAM,CAAA,oCAAA,EAAuC,QAAQ,CAAA,aAAA,EAAgB,CAAC,KAAK,GAAG,CAAA;AACtF,QAAA,IAAA,GAAO,CAAA;AAAA,MACT;AAEA,MAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,IAAA,EAAM,IAAA,CAAK,MAAA,GAAS,CAAC,CAAC,CAAA;AAE/D,MAAA,IAAI,cAAc,CAAA,EAAG;AAEnB,QAAA,GAAA,CAAI,GAAA,CAAI,OAAA,CAAQ,CAAA,EAAG,QAAQ,GAAG,WAAW,CAAA;AAGzC,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,WAAA,EAAa,CAAA,EAAA,EAAK;AACpC,UAAA,GAAA,CAAI,IAAI,OAAA,CAAQ,CAAA,GAAI,CAAA,EAAG,QAAQ,GAAG,CAAC,CAAA;AAAA,QACrC;AAEA,QAAA,CAAA,IAAK,WAAA;AAAA,MACP,CAAA,MAAO;AAGL,QAAA,CAAA,EAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,GAAA;AACT;AAYO,SAAS,UAAA,CACd,GAAA,EACA,QAAA,EACA,QAAA,EACoB;AACpB,EAAA,OAAO,GAAA,CAAI,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAU,QAAQ,CAAC,CAAA;AAC5C;AAKO,SAAS,aAAA,CAAc,GAAA,EAAiB,QAAA,EAAkB,QAAA,EAA2B;AAC1F,EAAA,OAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAU,QAAQ,CAAC,CAAA,KAAM,CAAA;AAClD","file":"rowSpanning.cjs","sourcesContent":["// @zvndev/yable-core — Row Spanning Feature\n// Allows a single cell to span multiple contiguous rows when adjacent rows\n// have the same value. Controlled via `rowSpan` callback on column def.\n\nimport type { RowData, Row, ColumnDef } from '../types'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Map from `${rowIndex}:${columnId}` to the number of rows to span.\n * A value of 0 means \"this cell is consumed by a span above — skip it.\"\n * A value >= 1 is the actual rowSpan attribute value.\n */\nexport type RowSpanMap = Map<string, number>\n\n/**\n * Callback on a column def that returns the number of rows to span\n * starting from the current row.  Return 1 (or undefined) for no spanning.\n */\nexport type RowSpanFn<TData extends RowData> = (\n  row: Row<TData>,\n  rows: Row<TData>[],\n  rowIndex: number,\n) => number | undefined\n\n// ---------------------------------------------------------------------------\n// Key Helpers\n// ---------------------------------------------------------------------------\n\nfunction spanKey(rowIndex: number, columnId: string): string {\n  return `${rowIndex}:${columnId}`\n}\n\n// ---------------------------------------------------------------------------\n// resolveRowSpans\n// ---------------------------------------------------------------------------\n\n/**\n * Pre-process visible rows and column definitions to compute a RowSpanMap.\n *\n * For each column that defines a `rowSpan` callback, iterate through the rows\n * and determine how many contiguous rows should be merged.  The first row in\n * the span gets the total count; subsequent rows get 0 (skip).\n *\n * @param rows - The visible (rendered) rows in order.\n * @param columnDefs - All column definitions for the table.\n * @returns A RowSpanMap that renderers can consult per-cell.\n */\nexport function resolveRowSpans<TData extends RowData>(\n  rows: Row<TData>[],\n  columnDefs: ColumnDef<TData, unknown>[],\n): RowSpanMap {\n  const map: RowSpanMap = new Map()\n\n  for (const colDef of columnDefs) {\n    // Access rowSpan via the column def extensions (it's a custom extension, not in ColumnDefExtensions)\n    const rowSpanFn = (colDef as ColumnDef<TData> & { rowSpan?: RowSpanFn<TData> }).rowSpan\n    if (!rowSpanFn) continue\n\n    const columnId =\n      colDef.id ?? ('accessorKey' in colDef ? (colDef.accessorKey as string) : undefined)\n    if (!columnId) continue\n\n    let i = 0\n    while (i < rows.length) {\n      const row = rows[i]!\n\n      // T1-09: Wrap user rowSpanFn callback in try-catch\n      let span: number\n      try {\n        span = rowSpanFn(row, rows, i) ?? 1\n      } catch (err) {\n        console.error(`[yable] rowSpanFn threw for column \"${columnId}\", row index ${i}:`, err)\n        span = 1 // safe default: no spanning\n      }\n\n      const clampedSpan = Math.max(1, Math.min(span, rows.length - i))\n\n      if (clampedSpan > 1) {\n        // First row gets the full span\n        map.set(spanKey(i, columnId), clampedSpan)\n\n        // Subsequent rows in the span are marked as consumed (0 = skip)\n        for (let j = 1; j < clampedSpan; j++) {\n          map.set(spanKey(i + j, columnId), 0)\n        }\n\n        i += clampedSpan\n      } else {\n        // Explicit 1 only if we already have entries in this column\n        // (optional — renderers default to 1 when key is absent)\n        i++\n      }\n    }\n  }\n\n  return map\n}\n\n// ---------------------------------------------------------------------------\n// Query helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Get the rowSpan value for a specific cell.\n * - Returns undefined if no spanning applies (render normally).\n * - Returns 0 if the cell is consumed by a span above (skip rendering).\n * - Returns n > 1 if this cell should span n rows.\n */\nexport function getRowSpan(\n  map: RowSpanMap,\n  rowIndex: number,\n  columnId: string,\n): number | undefined {\n  return map.get(spanKey(rowIndex, columnId))\n}\n\n/**\n * Check if a cell should be skipped because a span from above covers it.\n */\nexport function isCellSpanned(map: RowSpanMap, rowIndex: number, columnId: string): boolean {\n  return map.get(spanKey(rowIndex, columnId)) === 0\n}\n"]}