{"version":3,"file":"apgrid.mjs","mappings":"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","sources":["webpack://@avi-pathak/apgrid/webpack/bootstrap","webpack://@avi-pathak/apgrid/webpack/runtime/define property getters","webpack://@avi-pathak/apgrid/webpack/runtime/hasOwnProperty shorthand","webpack://@avi-pathak/apgrid/webpack/runtime/make namespace object","webpack://@avi-pathak/apgrid/./src/models/DataMapEditor.ts","webpack://@avi-pathak/apgrid/./src/events/EventBus.ts","webpack://@avi-pathak/apgrid/./src/data/CollectionViewGroup.ts","webpack://@avi-pathak/apgrid/./src/data/compareValues.ts","webpack://@avi-pathak/apgrid/./src/data/buildGroups.ts","webpack://@avi-pathak/apgrid/./src/data/CollectionView.ts","webpack://@avi-pathak/apgrid/./src/models/DataMap.ts","webpack://@avi-pathak/apgrid/./src/models/Column.ts","webpack://@avi-pathak/apgrid/./src/core/GridState.ts","webpack://@avi-pathak/apgrid/./src/core/GridViewport.ts","webpack://@avi-pathak/apgrid/./src/models/ColumnGroup.ts","webpack://@avi-pathak/apgrid/./src/data/buildColumnGroups.ts","webpack://@avi-pathak/apgrid/./src/data/GroupRowModel.ts","webpack://@avi-pathak/apgrid/./src/data/DataView.ts","webpack://@avi-pathak/apgrid/./src/models/SortDescription.ts","webpack://@avi-pathak/apgrid/./src/models/GroupDescription.ts","webpack://@avi-pathak/apgrid/./src/utils/BinarySearch.ts","webpack://@avi-pathak/apgrid/./src/utils/Math.ts","webpack://@avi-pathak/apgrid/./src/virtualization/LayoutEngine.ts","webpack://@avi-pathak/apgrid/./src/utils/DOM.ts","webpack://@avi-pathak/apgrid/./src/rendering/ViewportRenderer.ts","webpack://@avi-pathak/apgrid/./src/utils/icons.ts","webpack://@avi-pathak/apgrid/./src/utils/ObjectPool.ts","webpack://@avi-pathak/apgrid/./src/data/aggregate.ts","webpack://@avi-pathak/apgrid/./src/rendering/RowRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/HeaderRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/ColumnGroupRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/RowHeaderRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/CellRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/FrozenRenderer.ts","webpack://@avi-pathak/apgrid/./src/models/Cell.ts","webpack://@avi-pathak/apgrid/./src/rendering/MergeRenderer.ts","webpack://@avi-pathak/apgrid/./src/rendering/Renderer.ts","webpack://@avi-pathak/apgrid/./src/scrolling/ScrollManager.ts","webpack://@avi-pathak/apgrid/./src/selection/SelectionModel.ts","webpack://@avi-pathak/apgrid/./src/events/MouseHandler.ts","webpack://@avi-pathak/apgrid/./src/events/KeyboardHandler.ts","webpack://@avi-pathak/apgrid/./src/events/ColumnResizer.ts","webpack://@avi-pathak/apgrid/./src/events/ColumnDragger.ts","webpack://@avi-pathak/apgrid/./src/events/ClipboardHandler.ts","webpack://@avi-pathak/apgrid/./src/export/formats/csv.ts","webpack://@avi-pathak/apgrid/./src/export/zip/crc32.ts","webpack://@avi-pathak/apgrid/./src/export/zip/zip.ts","webpack://@avi-pathak/apgrid/./src/export/formats/xlsx.ts","webpack://@avi-pathak/apgrid/./src/export/formats/pdf.ts","webpack://@avi-pathak/apgrid/./src/export/registry.ts","webpack://@avi-pathak/apgrid/./src/export/buildExportData.ts","webpack://@avi-pathak/apgrid/./src/export/ProgressOverlay.ts","webpack://@avi-pathak/apgrid/./src/export/ExportManager.ts","webpack://@avi-pathak/apgrid/./src/export/download.ts","webpack://@avi-pathak/apgrid/./src/rendering/ContextMenu.ts","webpack://@avi-pathak/apgrid/./src/rendering/GroupPanel.ts","webpack://@avi-pathak/apgrid/./src/models/ColumnFilter.ts","webpack://@avi-pathak/apgrid/./src/data/FilterModel.ts","webpack://@avi-pathak/apgrid/./src/rendering/FilterEditor.ts","webpack://@avi-pathak/apgrid/./src/commands/UndoStack.ts","webpack://@avi-pathak/apgrid/./src/commands/ResizeColumnAction.ts","webpack://@avi-pathak/apgrid/./src/commands/EditAction.ts","webpack://@avi-pathak/apgrid/./src/commands/BatchAction.ts","webpack://@avi-pathak/apgrid/./src/commands/MoveColumnAction.ts","webpack://@avi-pathak/apgrid/./src/editing/TextEditor.ts","webpack://@avi-pathak/apgrid/./src/editing/DropDownEditor.ts","webpack://@avi-pathak/apgrid/./src/editing/RadioEditor.ts","webpack://@avi-pathak/apgrid/./src/editing/EditorManager.ts","webpack://@avi-pathak/apgrid/./src/models/MergeManager.ts","webpack://@avi-pathak/apgrid/./src/core/Grid.ts","webpack://@avi-pathak/apgrid/./src/core/GridOptions.ts","webpack://@avi-pathak/apgrid/./src/data/ODataCollectionView.ts","webpack://@avi-pathak/apgrid/./src/data/ODataVirtualCollectionView.ts","webpack://@avi-pathak/apgrid/./src/index.ts"],"sourcesContent":["// The require scope\nconst __webpack_require__ = {};\n\n","// define getter/value functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tif(Array.isArray(definition)) {\n\t\tvar i = 0;\n\t\twhile(i < definition.length) {\n\t\t\tvar key = definition[i++];\n\t\t\tvar binding = definition[i++];\n\t\t\tif(!__webpack_require__.o(exports, key)) {\n\t\t\t\tif(binding === 0) {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, value: definition[i++] });\n\t\t\t\t} else {\n\t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: binding });\n\t\t\t\t}\n\t\t\t} else if(binding === 0) { i++; }\n\t\t}\n\t} else {\n\t\tfor(var key in definition) {\n\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t\t}\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Editor types for a data-mapped column. The grid picks the matching editor when\n * a column with a {@link DataMap} enters edit mode.\n */\nexport enum DataMapEditor {\n  /** Input with an autocomplete list; accepts typed values when the map is editable. */\n  AutoComplete = 0,\n  /** Dropdown list (a native select). The default. */\n  DropDownList = 1,\n  /** Radio buttons with mouse and keyboard support. */\n  RadioButtons = 2,\n  /** Dropdown only, no accompanying input. */\n  Menu = 3,\n}\n","export type EventHandler<T> = (payload: T) => void;\n\n/**\n * Minimal typed pub/sub. `Events` maps an event name to its payload type, so\n * `on`/`emit` are checked against the same shape. Replaces the old stringly-typed\n * event bus.\n */\nexport class EventBus<Events> {\n  private handlers = new Map<keyof Events, Set<EventHandler<unknown>>>();\n\n  on<K extends keyof Events>(type: K, handler: EventHandler<Events[K]>): () => void {\n    let set = this.handlers.get(type);\n    if (!set) {\n      set = new Set();\n      this.handlers.set(type, set);\n    }\n    set.add(handler as EventHandler<unknown>);\n    return () => {\n      this.handlers.get(type)?.delete(handler as EventHandler<unknown>);\n    };\n  }\n\n  emit<K extends keyof Events>(type: K, payload: Events[K]): void {\n    const set = this.handlers.get(type);\n    if (!set) return;\n    for (const handler of set) (handler as EventHandler<Events[K]>)(payload);\n  }\n\n  clear(): void {\n    this.handlers.clear();\n  }\n}\n","/**\n * A node in the group tree built by a CollectionView. A group either holds child\n * groups (when more than one grouping level is active) or sits at the bottom\n * level over its own leaf items. `items` always holds every leaf beneath the\n * group in view order, so aggregates and counts read straight from it.\n */\nexport class CollectionViewGroup<T = Record<string, unknown>> {\n  readonly groups: CollectionViewGroup<T>[] = [];\n\n  constructor(\n    /** Display text for the group key, e.g. the country name. */\n    readonly name: string,\n    /** Raw group key before formatting. */\n    readonly key: unknown,\n    readonly level: number,\n    /** Every leaf under this group, in view order. */\n    readonly items: T[] = [],\n  ) {}\n\n  get isBottomLevel(): boolean {\n    return this.groups.length === 0;\n  }\n\n  get itemCount(): number {\n    return this.items.length;\n  }\n}\n","/**\n * Default value ordering shared by sorting and grouping: nulls last, then\n * numbers/dates numerically, booleans false-first, everything else by\n * locale-aware string comparison.\n */\nexport function compareValues(a: unknown, b: unknown): number {\n  if (a === b) return 0;\n  if (a == null) return 1;\n  if (b == null) return -1;\n  if (typeof a === 'number' && typeof b === 'number') return a - b;\n  if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();\n  if (typeof a === 'boolean' && typeof b === 'boolean') return a === b ? 0 : a ? 1 : -1;\n  return String(a).localeCompare(String(b));\n}\n","import { PropertyGroupDescription } from '../models/GroupDescription';\nimport { SortDescription } from '../models/SortDescription';\nimport { CollectionViewGroup } from './CollectionViewGroup';\nimport { compareValues } from './compareValues';\n\nexport interface GroupResult<T> {\n  groups: CollectionViewGroup<T>[];\n  /** Leaves reordered so items of the same group are contiguous. */\n  leaves: T[];\n}\n\n/**\n * Build the group tree for `items` (already filtered and sorted) against the\n * given descriptions. Groups within a level are ordered by their key, honoring\n * the sort direction of any {@link SortDescription} on that level's property\n * (so sorting a grouped column reverses its groups). Leaves keep the incoming\n * order. Returns the tree and the leaves reordered to match, so a caller can use\n * the reordered array as its view.\n */\nexport function buildGroups<T>(\n  items: T[],\n  descriptions: PropertyGroupDescription<T>[],\n  sorts: SortDescription[] = [],\n): GroupResult<T> {\n  return groupLevel(items, descriptions, sorts, 0);\n}\n\nfunction groupLevel<T>(\n  items: T[],\n  descriptions: PropertyGroupDescription<T>[],\n  sorts: SortDescription[],\n  level: number,\n): GroupResult<T> {\n  if (level >= descriptions.length) return { groups: [], leaves: items };\n\n  const desc = descriptions[level];\n  const buckets = new Map<string, { key: unknown; items: T[] }>();\n  for (const item of items) {\n    const key = desc.groupKey(item);\n    const id = bucketId(key);\n    let bucket = buckets.get(id);\n    if (!bucket) {\n      bucket = { key, items: [] };\n      buckets.set(id, bucket);\n    }\n    bucket.items.push(item);\n  }\n\n  const descending = sorts.some((s) => s.property === desc.property && !s.ascending);\n  const dir = descending ? -1 : 1;\n  const ordered = [...buckets.values()].sort((a, b) => compareValues(a.key, b.key) * dir);\n  const groups: CollectionViewGroup<T>[] = [];\n  const leaves: T[] = [];\n  for (const bucket of ordered) {\n    const child = groupLevel(bucket.items, descriptions, sorts, level + 1);\n    const group = new CollectionViewGroup<T>(\n      groupName(bucket.key),\n      bucket.key,\n      level,\n      child.leaves,\n    );\n    group.groups.push(...child.groups);\n    groups.push(group);\n    for (const leaf of child.leaves) leaves.push(leaf);\n  }\n  return { groups, leaves };\n}\n\n// Stable map id for a key. Dates compare by time and the type prefix keeps\n// numbers and their string forms in separate buckets.\nfunction bucketId(key: unknown): string {\n  if (key == null) return 'n';\n  if (key instanceof Date) return `d${key.getTime()}`;\n  return `${typeof key}:${String(key)}`;\n}\n\nfunction groupName(key: unknown): string {\n  if (key == null) return '(Blanks)';\n  if (key instanceof Date) return key.toLocaleDateString();\n  return String(key);\n}\n","import { EventBus, EventHandler } from '../events/EventBus';\nimport { SortDescription } from '../models/SortDescription';\nimport { PropertyGroupDescription } from '../models/GroupDescription';\nimport { CollectionViewGroup } from './CollectionViewGroup';\nimport { buildGroups } from './buildGroups';\nimport { compareValues } from './compareValues';\n\nexport type ChangeAction = 'add' | 'remove' | 'change' | 'reset';\n\nexport interface CollectionChange<T> {\n  action: ChangeAction;\n  item?: T;\n  index?: number;\n}\n\ninterface CollectionViewEvents<T> {\n  collectionChanged: CollectionChange<T>;\n  currentChanged: void;\n  pageChanged: void;\n}\n\nexport interface CollectionViewOptions<T> {\n  trackChanges?: boolean;\n  newItemCreator?: () => T;\n  pageSize?: number;\n}\n\n/**\n * Exposes a plain array as an editable view and, when {@link trackChanges} is on,\n * records which items were added, removed, or edited so callers can sync a server.\n * Supports sorting, filtering, current-item navigation, and change tracking. The\n * view mirrors the source order until a filter or sort is applied.\n */\nexport class CollectionView<T = Record<string, unknown>> {\n  /** Items added since tracking was enabled (via addNew/commitNew). */\n  readonly itemsAdded: T[] = [];\n  /** Items removed since tracking was enabled (via remove/removeAt). */\n  readonly itemsRemoved: T[] = [];\n  /** Items edited since tracking was enabled (via editItem/commitEdit). */\n  readonly itemsEdited: T[] = [];\n\n  newItemCreator?: () => T;\n\n  /**\n   * Converts a value before sorting. The grid uses it to sort data-mapped\n   * columns by their display text instead of the raw key.\n   */\n  sortConverter?: (sd: SortDescription, item: T, value: unknown) => unknown;\n\n  protected source: T[];\n  protected view: T[] = [];\n  protected events = new EventBus<CollectionViewEvents<T>>();\n  protected _position = -1;\n  protected _filter: ((item: T) => boolean) | null = null;\n  protected _sorts: SortDescription[] = [];\n  protected _groups: PropertyGroupDescription<T>[] = [];\n  protected _groupTree: CollectionViewGroup<T>[] = [];\n  protected _pageSize = 0;\n  protected _pageIndex = 0;\n  protected _totalItemCount = 0;\n\n  private _trackChanges: boolean;\n  private editTarget: T | null = null;\n  private editSnapshot: Record<string, unknown> | null = null;\n  private addTarget: T | null = null;\n\n  private updateDepth = 0;\n  private refreshPending = false;\n\n  constructor(source: T[] = [], options: CollectionViewOptions<T> = {}) {\n    this.source = source;\n    this._trackChanges = options.trackChanges ?? false;\n    this.newItemCreator = options.newItemCreator;\n    this._pageSize = options.pageSize ?? 0;\n    this.refresh();\n  }\n\n  on<K extends keyof CollectionViewEvents<T>>(\n    type: K,\n    handler: EventHandler<CollectionViewEvents<T>[K]>,\n  ): () => void {\n    return this.events.on(type, handler);\n  }\n\n  /** The items in view order. Holds the same object references as the source. */\n  get items(): T[] {\n    return this.view;\n  }\n\n  get sourceCollection(): T[] {\n    return this.source;\n  }\n\n  set sourceCollection(value: T[]) {\n    this.source = value ?? [];\n    this.clearChanges();\n    this.refresh();\n  }\n\n  get trackChanges(): boolean {\n    return this._trackChanges;\n  }\n\n  set trackChanges(value: boolean) {\n    this._trackChanges = value;\n  }\n\n  get canSort(): boolean {\n    return true;\n  }\n\n  get canFilter(): boolean {\n    return true;\n  }\n\n  /** Predicate that keeps an item in the view, or null to show everything. */\n  get filter(): ((item: T) => boolean) | null {\n    return this._filter;\n  }\n\n  set filter(value: ((item: T) => boolean) | null) {\n    this._filter = value;\n    this.refresh();\n  }\n\n  /** Sort order applied to the view. Assigning a new array re-sorts. */\n  get sortDescriptions(): SortDescription[] {\n    return this._sorts;\n  }\n\n  set sortDescriptions(value: SortDescription[]) {\n    this._sorts = value ?? [];\n    this.refresh();\n  }\n\n  /** Group-by descriptors applied to the view. Assigning rebuilds the group tree. */\n  get groupDescriptions(): PropertyGroupDescription<T>[] {\n    return this._groups;\n  }\n\n  set groupDescriptions(value: PropertyGroupDescription<T>[]) {\n    this._groups = value ?? [];\n    this.refresh();\n  }\n\n  /** The root groups, or an empty array when the view isn't grouped. */\n  get groups(): CollectionViewGroup<T>[] {\n    return this._groupTree;\n  }\n\n  get canChangePage(): boolean {\n    return true;\n  }\n\n  /** Items per page. 0 disables paging (the default). */\n  get pageSize(): number {\n    return this._pageSize;\n  }\n\n  set pageSize(value: number) {\n    value = Math.max(0, value);\n    if (value === this._pageSize) return;\n    this._pageSize = value;\n    this._pageIndex = 0;\n    this.refresh();\n  }\n\n  /** Zero-based index of the current page. */\n  get pageIndex(): number {\n    return this._pageIndex;\n  }\n\n  /** Total number of pages given the page size and total item count. */\n  get pageCount(): number {\n    return this._pageSize > 0 ? Math.max(1, Math.ceil(this._totalItemCount / this._pageSize)) : 1;\n  }\n\n  /** Total items across all pages (before paging). */\n  get totalItemCount(): number {\n    return this._totalItemCount;\n  }\n\n  moveToPage(index: number): boolean {\n    const target = Math.max(0, Math.min(index, this.pageCount - 1));\n    if (target === this._pageIndex) return false;\n    this._pageIndex = target;\n    this.refresh();\n    this.events.emit('pageChanged', undefined);\n    return true;\n  }\n\n  moveToFirstPage(): boolean {\n    return this.moveToPage(0);\n  }\n\n  moveToLastPage(): boolean {\n    return this.moveToPage(this.pageCount - 1);\n  }\n\n  moveToNextPage(): boolean {\n    return this.moveToPage(this._pageIndex + 1);\n  }\n\n  moveToPreviousPage(): boolean {\n    return this.moveToPage(this._pageIndex - 1);\n  }\n\n  get isEmpty(): boolean {\n    return this.view.length === 0;\n  }\n\n  get itemCount(): number {\n    return this.view.length;\n  }\n\n  get currentItem(): T | null {\n    return this._position >= 0 && this._position < this.view.length\n      ? this.view[this._position]\n      : null;\n  }\n\n  get currentPosition(): number {\n    return this._position;\n  }\n\n  get isAddingNew(): boolean {\n    return this.addTarget != null;\n  }\n\n  get isEditingItem(): boolean {\n    return this.editTarget != null;\n  }\n\n  get currentAddItem(): T | null {\n    return this.addTarget;\n  }\n\n  get currentEditItem(): T | null {\n    return this.editTarget;\n  }\n\n  contains(item: T): boolean {\n    return this.view.indexOf(item) >= 0;\n  }\n\n  moveCurrentToPosition(index: number): boolean {\n    if (index >= -1 && index < this.view.length && index !== this._position) {\n      this._position = index;\n      this.events.emit('currentChanged', undefined);\n    }\n    return true;\n  }\n\n  moveCurrentToFirst(): boolean {\n    return this.moveCurrentToPosition(this.view.length ? 0 : -1);\n  }\n\n  moveCurrentToLast(): boolean {\n    return this.moveCurrentToPosition(this.view.length - 1);\n  }\n\n  moveCurrentToNext(): boolean {\n    return this._position < this.view.length - 1 && this.moveCurrentToPosition(this._position + 1);\n  }\n\n  moveCurrentToPrevious(): boolean {\n    return this._position > 0 && this.moveCurrentToPosition(this._position - 1);\n  }\n\n  moveCurrentTo(item: T): boolean {\n    return this.moveCurrentToPosition(this.view.indexOf(item));\n  }\n\n  /** Begin an edit transaction. Snapshots the item so cancelEdit can restore it. */\n  editItem(item: T): void {\n    if (this.editTarget === item) return;\n    if (this.editTarget) this.commitEdit();\n    this.editTarget = item;\n    this.editSnapshot = { ...(item as Record<string, unknown>) };\n  }\n\n  commitEdit(): void {\n    const item = this.editTarget;\n    if (!item) return;\n    this.editTarget = null;\n    this.editSnapshot = null;\n    if (this._trackChanges) this.trackEdit(item);\n    this.onChanged('change', item, this.view.indexOf(item));\n  }\n\n  cancelEdit(): void {\n    const item = this.editTarget;\n    if (!item) return;\n    if (this.editSnapshot) Object.assign(item as Record<string, unknown>, this.editSnapshot);\n    this.editTarget = null;\n    this.editSnapshot = null;\n    this.onChanged('change', item, this.view.indexOf(item));\n  }\n\n  /** Add an item to the collection. Defers tracking until commitNew unless commit is true. */\n  addNew(item?: T, commit = false): T {\n    const created = item ?? (this.newItemCreator ? this.newItemCreator() : ({} as T));\n    this.source.push(created);\n    this.addTarget = created;\n    this.refresh();\n    this._position = this.view.indexOf(created);\n    if (commit) this.commitNew();\n    return created;\n  }\n\n  commitNew(): void {\n    const item = this.addTarget;\n    if (!item) return;\n    this.addTarget = null;\n    if (this._trackChanges && this.itemsAdded.indexOf(item) < 0) this.itemsAdded.push(item);\n    this.onChanged('add', item, this.view.indexOf(item));\n  }\n\n  cancelNew(): void {\n    const item = this.addTarget;\n    if (!item) return;\n    this.addTarget = null;\n    const i = this.source.indexOf(item);\n    if (i >= 0) this.source.splice(i, 1);\n    this.refresh();\n    this.onChanged('remove', item);\n  }\n\n  remove(item: T): void {\n    if (this.addTarget === item) {\n      this.cancelNew();\n      return;\n    }\n    const i = this.source.indexOf(item);\n    if (i < 0) return;\n    this.source.splice(i, 1);\n    if (this._trackChanges) this.trackRemove(item);\n    this.refresh();\n    this.onChanged('remove', item, i);\n  }\n\n  removeAt(index: number): void {\n    const item = this.view[index];\n    if (item != null) this.remove(item);\n  }\n\n  /** Drop all tracked changes. Call after pushing them to a server. */\n  clearChanges(): void {\n    this.itemsAdded.length = 0;\n    this.itemsRemoved.length = 0;\n    this.itemsEdited.length = 0;\n  }\n\n  beginUpdate(): void {\n    this.updateDepth++;\n  }\n\n  endUpdate(): void {\n    if (this.updateDepth > 0) this.updateDepth--;\n    if (this.updateDepth === 0 && this.refreshPending) {\n      this.refreshPending = false;\n      this.refresh();\n    }\n  }\n\n  get isUpdating(): boolean {\n    return this.updateDepth > 0;\n  }\n\n  deferUpdate(fn: () => void): void {\n    this.beginUpdate();\n    try {\n      fn();\n    } finally {\n      this.endUpdate();\n    }\n  }\n\n  refresh(): void {\n    if (this.updateDepth > 0) {\n      this.refreshPending = true;\n      return;\n    }\n    const current = this.currentItem;\n    const arranged = this.arrange();\n    this._totalItemCount = arranged.length;\n    // Grouping reorders the leaves and overrides paging so a group never splits\n    // across pages.\n    if (this._groups.length) {\n      const result = buildGroups(arranged, this._groups, this._sorts);\n      this._groupTree = result.groups;\n      this.view = result.leaves;\n    } else {\n      this._groupTree = [];\n      this.view = this.page(arranged);\n    }\n    // Keep the same item current across the rebuild when it's still visible.\n    const idx = current != null ? this.view.indexOf(current) : -1;\n    this._position = idx >= 0 ? idx : Math.min(this._position, this.view.length - 1);\n    this.onChanged('reset');\n  }\n\n  // Filter then sort the source. Split out so server-backed views can override\n  // just the data source while keeping currency and paging behavior.\n  protected arrange(): T[] {\n    let view = this.source.slice();\n    if (this._filter) view = view.filter(this._filter);\n    if (this._sorts.length) this.applySort(view);\n    return view;\n  }\n\n  private page(arranged: T[]): T[] {\n    if (this._pageSize <= 0) return arranged;\n    const start = this._pageIndex * this._pageSize;\n    return arranged.slice(start, start + this._pageSize);\n  }\n\n  private applySort(items: T[]): void {\n    items.sort((a, b) => {\n      for (const sd of this._sorts) {\n        const c = compareValues(this.sortValue(sd, a), this.sortValue(sd, b));\n        if (c !== 0) return sd.ascending ? c : -c;\n      }\n      return 0;\n    });\n  }\n\n  private sortValue(sd: SortDescription, item: T): unknown {\n    const raw = (item as Record<string, unknown>)[sd.property];\n    return this.sortConverter ? this.sortConverter(sd, item, raw) : raw;\n  }\n\n  private trackEdit(item: T): void {\n    if (this.itemsAdded.indexOf(item) >= 0) return; // new items count as added, not edited\n    if (this.itemsEdited.indexOf(item) < 0) this.itemsEdited.push(item);\n  }\n\n  private trackRemove(item: T): void {\n    const added = this.itemsAdded.indexOf(item);\n    if (added >= 0) {\n      this.itemsAdded.splice(added, 1);\n      return; // added then removed in the same session: a no-op for the server\n    }\n    const edited = this.itemsEdited.indexOf(item);\n    if (edited >= 0) this.itemsEdited.splice(edited, 1);\n    if (this.itemsRemoved.indexOf(item) < 0) this.itemsRemoved.push(item);\n  }\n\n  protected onChanged(action: ChangeAction, item?: T, index?: number): void {\n    if (this.updateDepth > 0) return;\n    this.events.emit('collectionChanged', { action, item, index });\n  }\n}\n","import { CollectionView } from '../data/CollectionView';\nimport { EventBus, EventHandler } from '../events/EventBus';\n\ninterface DataMapEvents {\n  mapChanged: void;\n}\n\n/** Compare keys by string form, so 123 (number) and '123' (string) match. */\nfunction sameKey(a: unknown, b: unknown): boolean {\n  return String(a) === String(b);\n}\n\n/**\n * Maps stored key values to display values for a column, so the grid can show a\n * friendly label (a country name) while the cell holds a raw value (a code).\n * Build it from a plain array of strings, an array of objects plus value/display\n * paths, or a {@link CollectionView}.\n */\nexport class DataMap {\n  readonly collectionView: CollectionView;\n  selectedValuePath: string;\n  displayMemberPath: string;\n  /** Allow values that are not on the map (free text). Default false. */\n  isEditable = false;\n  /** Order the lookup list by display value. Default true. */\n  sortByDisplayValues = true;\n  /**\n   * Optional hook for dynamic data maps: given the row being edited, return the\n   * subset of source items allowed for it. Lets one column's choices depend on\n   * another (e.g. cities filtered by the row's country).\n   */\n  itemsFilter?: (dataItem: unknown) => unknown[];\n\n  private events = new EventBus<DataMapEvents>();\n\n  constructor(\n    itemsSource: unknown[] | CollectionView,\n    selectedValuePath = '',\n    displayMemberPath = '',\n  ) {\n    this.collectionView =\n      itemsSource instanceof CollectionView\n        ? itemsSource\n        : new CollectionView(itemsSource as Record<string, unknown>[]);\n    this.selectedValuePath = selectedValuePath;\n    this.displayMemberPath = displayMemberPath || selectedValuePath;\n    this.collectionView.on('collectionChanged', () => this.onMapChanged());\n  }\n\n  on(type: 'mapChanged', handler: EventHandler<void>): () => void {\n    return this.events.on(type, handler);\n  }\n\n  onMapChanged(): void {\n    this.events.emit('mapChanged', undefined);\n  }\n\n  /** All keys, ordered by display value when sortByDisplayValues is on. */\n  getKeyValues(dataItem?: unknown): unknown[] {\n    return this.ordered(dataItem).map((item) => this.keyOf(item));\n  }\n\n  /** All display values, in the same order as getKeyValues. */\n  getDisplayValues(dataItem?: unknown): string[] {\n    return this.ordered(dataItem).map((item) => this.displayOf(item));\n  }\n\n  getDisplayValue(key: unknown): string {\n    const item = this.items.find((i) => sameKey(this.keyOf(i), key));\n    return item !== undefined ? this.displayOf(item) : '';\n  }\n\n  getKeyValue(displayValue: string): unknown {\n    const item = this.items.find((i) => this.displayOf(i) === displayValue);\n    return item !== undefined ? this.keyOf(item) : null;\n  }\n\n  getDataItem(key: unknown): unknown {\n    return this.items.find((i) => sameKey(this.keyOf(i), key)) ?? null;\n  }\n\n  private get items(): unknown[] {\n    return this.collectionView.items;\n  }\n\n  // The candidate items for a row: the filtered subset for dynamic maps, else all.\n  private itemsFor(dataItem?: unknown): unknown[] {\n    if (this.itemsFilter && dataItem !== undefined) return this.itemsFilter(dataItem);\n    return this.items;\n  }\n\n  private keyOf(item: unknown): unknown {\n    return this.selectedValuePath\n      ? (item as Record<string, unknown>)[this.selectedValuePath]\n      : item;\n  }\n\n  private displayOf(item: unknown): string {\n    const value = this.displayMemberPath\n      ? (item as Record<string, unknown>)[this.displayMemberPath]\n      : item;\n    return value == null ? '' : String(value);\n  }\n\n  private ordered(dataItem?: unknown): unknown[] {\n    const items = this.itemsFor(dataItem).slice();\n    if (this.sortByDisplayValues) {\n      items.sort((a, b) => this.displayOf(a).localeCompare(this.displayOf(b)));\n    }\n    return items;\n  }\n}\n","import { DataMap } from './DataMap';\nimport { DataMapEditor } from './DataMapEditor';\n\nexport type DataType = 'String' | 'Number' | 'Boolean' | 'Date';\nexport type CellAlign = 'left' | 'center' | 'right';\nexport type AggregateType = 'sum' | 'avg' | 'min' | 'max' | 'count';\n\n/** An entry in a column's dataMap (combo box choices). */\nexport type DataMapEntry = string | { value: unknown; text: string };\n\nexport interface CellTemplateContext<T = Record<string, unknown>> {\n  value: unknown;\n  item: T;\n  row: number;\n  column: Column<T>;\n}\n\n/** Inline styles as a plain object, e.g. `{ color: 'red', backgroundColor: '#fee' }`. */\nexport type CellStyle = Partial<CSSStyleDeclaration> & Record<string, string>;\n\n/** Resolves a cell's CSS classes from its value/row. Return one or more class names. */\nexport type CellClassFn<T = Record<string, unknown>> = (\n  ctx: CellTemplateContext<T>,\n) => string | string[] | null | undefined;\n\n/** Resolves a cell's inline styles from its value/row. */\nexport type CellStyleFn<T = Record<string, unknown>> = (\n  ctx: CellTemplateContext<T>,\n) => CellStyle | null | undefined;\n\n/** Map of class name to a predicate; each class is applied when its predicate is true. */\nexport type CellClassRules<T = Record<string, unknown>> = Record<\n  string,\n  (ctx: CellTemplateContext<T>) => boolean\n>;\n\nexport interface ColumnDef<T = Record<string, unknown>> {\n  /** Field to bind to. Optional for calculated columns that use `valueGetter`. */\n  binding?: string;\n  header?: string;\n  width?: number;\n  editable?: boolean;\n  dataType?: DataType;\n  align?: CellAlign;\n  /** Compute the value from the row. Makes the column calculated (read-only). */\n  valueGetter?: (item: T) => unknown;\n  valueFormatter?: (value: unknown, item: T) => string;\n  /** Choices for a combo-box cell. Accepts a simple list, value/text pairs, or a DataMap. */\n  dataMap?: DataMapEntry[] | DataMap;\n  /** Which editor a data-mapped cell uses. Default DropDownList. */\n  dataMapEditor?: DataMapEditor;\n  /** Aggregate shown for this column on group-header rows. */\n  aggregate?: AggregateType;\n  /** Allow a filter dialog on this column. Overrides the grid's `allowFiltering`. */\n  filter?: boolean;\n  /** Let this column merge adjacent equal-valued cells. Overrides the grid's `allowMerging`. */\n  allowMerging?: boolean;\n  /** CSS class(es) for the cell. A function receives the cell context for conditional styling. */\n  cellClass?: string | string[] | CellClassFn<T>;\n  /** Inline styles for the cell. A function receives the cell context for conditional styling. */\n  cellStyle?: CellStyle | CellStyleFn<T>;\n  /** Class-name → predicate map; each class is applied when its predicate returns true. */\n  cellClassRules?: CellClassRules<T>;\n  /** Return custom cell HTML. Overrides the default text/checkbox rendering. */\n  cellTemplate?: (ctx: CellTemplateContext<T>) => string;\n}\n\nconst DEFAULT_WIDTH = 100;\n\nfunction defaultAlign(dataType: DataType): CellAlign {\n  if (dataType === 'Number' || dataType === 'Date') return 'right';\n  if (dataType === 'Boolean') return 'center';\n  return 'left';\n}\n\nfunction toDataMap(map: DataMapEntry[] | DataMap): DataMap {\n  if (map instanceof DataMap) return map;\n  if (map.length > 0 && typeof map[0] === 'object') {\n    return new DataMap(map as { value: unknown; text: string }[], 'value', 'text');\n  }\n  return new DataMap(map as string[]);\n}\n\nexport class Column<T = Record<string, unknown>> {\n  readonly binding: string;\n  readonly header: string;\n  width: number;\n  editable: boolean;\n  readonly dataType: DataType;\n  readonly align: CellAlign;\n  readonly dataMapEditor: DataMapEditor;\n  readonly aggregate?: AggregateType;\n  /** Whether the header shows a filter button. Resolved from the grid + column options. */\n  filterable = false;\n  /** Whether this column participates in cell merging. Resolved from the grid + column options. */\n  allowMerging = false;\n  /** Excluded from layout/rendering/selection when true. Driven by collapsed column groups. */\n  hidden = false;\n  readonly cellTemplate?: (ctx: CellTemplateContext<T>) => string;\n\n  private readonly valueGetter?: (item: T) => unknown;\n  private readonly valueFormatter?: (value: unknown, item: T) => string;\n  private readonly map?: DataMap;\n  private readonly cellClassDef?: string | string[] | CellClassFn<T>;\n  private readonly cellStyleDef?: CellStyle | CellStyleFn<T>;\n  private readonly cellClassRules?: CellClassRules<T>;\n\n  constructor(def: ColumnDef<T>) {\n    this.binding = def.binding ?? '';\n    this.header = def.header ?? def.binding ?? '';\n    this.width = def.width ?? DEFAULT_WIDTH;\n    this.dataType = def.dataType ?? 'String';\n    this.align = def.align ?? defaultAlign(this.dataType);\n    this.valueGetter = def.valueGetter;\n    this.valueFormatter = def.valueFormatter;\n    this.cellTemplate = def.cellTemplate;\n    this.map = def.dataMap ? toDataMap(def.dataMap) : undefined;\n    this.dataMapEditor = def.dataMapEditor ?? DataMapEditor.DropDownList;\n    this.aggregate = def.aggregate;\n    this.cellClassDef = def.cellClass;\n    this.cellStyleDef = def.cellStyle;\n    this.cellClassRules = def.cellClassRules;\n    // Calculated columns are read-only; combo cells stay editable.\n    this.editable = (def.editable ?? false) && !this.isCalculated;\n  }\n\n  /** A column driven by `valueGetter` has no writable field, so it can't be edited. */\n  get isCalculated(): boolean {\n    return this.valueGetter != null;\n  }\n\n  get dataMap(): DataMap | undefined {\n    return this.map;\n  }\n\n  getValue(item: T): unknown {\n    if (this.valueGetter) return this.valueGetter(item);\n    return (item as Record<string, unknown>)[this.binding];\n  }\n\n  setValue(item: T, value: unknown): void {\n    (item as Record<string, unknown>)[this.binding] = value;\n  }\n\n  /** Turn editor text into a typed value matching the column's dataType or dataMap. */\n  parse(text: string): unknown {\n    if (this.map) {\n      const key = this.map.getKeyValue(text);\n      return key != null ? key : text;\n    }\n    switch (this.dataType) {\n      case 'Number': {\n        if (text.trim() === '') return null;\n        const n = Number(text);\n        return Number.isNaN(n) ? null : n;\n      }\n      case 'Boolean':\n        return text === 'true' || text === '1';\n      case 'Date': {\n        const d = new Date(text);\n        return Number.isNaN(d.getTime()) ? null : d;\n      }\n      default:\n        return text;\n    }\n  }\n\n  format(item: T): string {\n    return this.formatValue(this.getValue(item), item);\n  }\n\n  /** Format a raw value the way this column formats cells. Also used for aggregates. */\n  formatValue(value: unknown, item?: T): string {\n    if (this.valueFormatter) return this.valueFormatter(value, item as T);\n    if (this.map) {\n      const text = this.map.getDisplayValue(value);\n      return text !== '' ? text : value == null ? '' : String(value);\n    }\n    if (value == null) return '';\n    if (this.dataType === 'Boolean') return ''; // rendered as a checkbox\n    if (this.dataType === 'Date' && value instanceof Date) return value.toLocaleDateString();\n    return String(value);\n  }\n\n  /** The CSS classes for a cell, from `cellClass` plus any matching `cellClassRules`. */\n  cellClasses(item: T, row: number): string[] {\n    if (!this.cellClassDef && !this.cellClassRules) return [];\n    const ctx = this.cellContext(item, row);\n    const out: string[] = [];\n    const cc = typeof this.cellClassDef === 'function' ? this.cellClassDef(ctx) : this.cellClassDef;\n    addClasses(out, cc);\n    if (this.cellClassRules) {\n      for (const name in this.cellClassRules) {\n        if (this.cellClassRules[name](ctx)) addClasses(out, name);\n      }\n    }\n    return out;\n  }\n\n  /** The inline styles for a cell, or null when `cellStyle` is unset or returns nothing. */\n  cellInlineStyle(item: T, row: number): CellStyle | null {\n    if (!this.cellStyleDef) return null;\n    if (typeof this.cellStyleDef !== 'function') return this.cellStyleDef;\n    return this.cellStyleDef(this.cellContext(item, row)) ?? null;\n  }\n\n  private cellContext(item: T, row: number): CellTemplateContext<T> {\n    return { value: this.getValue(item), item, row, column: this };\n  }\n}\n\n// Push class name(s) as individual tokens (space-separated strings are split).\nfunction addClasses(out: string[], value: string | string[] | null | undefined): void {\n  if (!value) return;\n  const list = Array.isArray(value) ? value : [value];\n  for (const entry of list) {\n    for (const token of entry.split(/\\s+/)) if (token) out.push(token);\n  }\n}\n","import { CellAddress, CellRange } from '../models/Cell';\n\nexport type StateListener = () => void;\n\n/**\n * Shared, observable grid state. Subsystems read these fields and subscribe to\n * changes rather than keeping their own copy of the scroll position or visible\n * range. Editing and focus state move in here as those features land.\n */\nexport class GridState {\n  scrollTop = 0;\n  scrollLeft = 0;\n\n  firstRow = 0;\n  lastRow = 0;\n  firstCol = 0;\n  lastCol = 0;\n\n  /** Leading columns pinned to the left. */\n  frozenCols = 0;\n  /** Leading rows pinned to the top. */\n  frozenRows = 0;\n\n  selection: CellRange | null = null;\n  activeCell: CellAddress | null = null;\n  alternatingRowStep = 1;\n  /** Which column the view is sorted by, and the direction. Null when unsorted. */\n  sort: { col: number; ascending: boolean } | null = null;\n  /** Column indices that currently have an active filter. */\n  activeFilters = new Set<number>();\n\n  private listeners = new Set<StateListener>();\n\n  subscribe(listener: StateListener): () => void {\n    this.listeners.add(listener);\n    return () => {\n      this.listeners.delete(listener);\n    };\n  }\n\n  emitChange(): void {\n    for (const listener of this.listeners) listener();\n  }\n}\n","import { GridState } from './GridState';\nimport { LayoutEngine } from '../virtualization/LayoutEngine';\n\n// Extra rows/cols kept in the DOM beyond the visible window, so a fast drag has\n// pre-rendered rows to show instead of flashing blank for a frame.\nconst BUFFER_ROWS = 6;\nconst BUFFER_COLS = 2;\n\n/**\n * Turns a scroll position into the buffered range of rows and columns that\n * should be in the DOM, and writes it into shared state. `update` returns true\n * only when that range actually changed, so the renderer can skip work on small\n * sub-row scrolls.\n */\nexport class GridViewport {\n  width = 0;\n  height = 0;\n\n  constructor(\n    private state: GridState,\n    private layout: LayoutEngine,\n  ) {}\n\n  setSize(width: number, height: number): void {\n    this.width = width;\n    this.height = height;\n  }\n\n  update(scrollTop: number, scrollLeft: number): boolean {\n    const rows = this.layout.getVisibleRows(scrollTop, this.height);\n    const cols = this.layout.getVisibleCols(scrollLeft, this.width);\n\n    const firstRow = Math.max(0, rows.first - BUFFER_ROWS);\n    const lastRow = Math.min(this.layout.rowCount - 1, rows.last + BUFFER_ROWS);\n    const firstCol = Math.max(0, cols.first - BUFFER_COLS);\n    const lastCol = Math.min(this.layout.colCount - 1, cols.last + BUFFER_COLS);\n\n    const s = this.state;\n    const rangeChanged =\n      firstRow !== s.firstRow ||\n      lastRow !== s.lastRow ||\n      firstCol !== s.firstCol ||\n      lastCol !== s.lastCol;\n\n    s.scrollTop = scrollTop;\n    s.scrollLeft = scrollLeft;\n    s.firstRow = firstRow;\n    s.lastRow = lastRow;\n    s.firstCol = firstCol;\n    s.lastCol = lastCol;\n\n    return rangeChanged;\n  }\n}\n","/**\n * Declares a node in the column-group header tree. A node is either:\n *  - a **leaf**, referencing a grid column by `binding`, or\n *  - a **group**, with a nested `columns` array of child nodes.\n *\n * A plain string in a group's `columns` is shorthand for `{ binding }`, so the\n * flat form `{ header: 'Perf', columns: ['ytd', 'm1'] }` still means a group of\n * two leaf columns.\n */\nexport interface ColumnGroupDef {\n  header?: string;\n  /** Leaf: the column binding this node maps to. Mutually exclusive with `columns`. */\n  binding?: string;\n  /** Group: child nodes (nested groups and/or leaf bindings), in order. */\n  columns?: (string | ColumnGroupDef)[];\n  /** Start collapsed (group only). Default false. */\n  collapsed?: boolean;\n  /** Allow the user to collapse/expand via the chevron (group only). Default true. */\n  collapsible?: boolean;\n  /**\n   * Binding of the one **descendant** leaf column that stays visible when this\n   * group is collapsed, carrying the header + chevron. Defaults to the first\n   * descendant leaf. `null` hides every column (no in-header expand affordance).\n   */\n  collapseTo?: string | null;\n  /** Stable identity for events/persistence. Defaults to a slug of `header`. */\n  key?: string;\n}\n\n/** A resolved leaf node: a reference to a grid column by binding. */\nexport class ColumnGroupLeaf {\n  readonly kind = 'leaf';\n  constructor(readonly binding: string) {}\n}\n\n/** A resolved node in the group tree: either a nested group or a leaf. */\nexport type ColumnGroupNode = ColumnGroup | ColumnGroupLeaf;\n\n/**\n * A resolved column group: a named header band over a subtree of leaf columns.\n * Groups nest recursively (a group's children may be groups or leaves), giving\n * a multi-row header. Collapsing a group hides all its descendant leaf columns\n * except `collapseTo`, which stays visible carrying the header and its expand\n * chevron — mirroring Wijmo FlexGrid's `collapseTo`.\n */\nexport class ColumnGroup {\n  readonly kind = 'group';\n  readonly key: string;\n  readonly header: string;\n  readonly collapsible: boolean;\n  readonly collapseTo: string | null;\n  readonly children: ColumnGroupNode[];\n  collapsed: boolean;\n\n  constructor(def: ColumnGroupDef, children: ColumnGroupNode[]) {\n    this.header = def.header ?? '';\n    this.key = def.key ?? slug(this.header);\n    this.collapsible = def.collapsible ?? true;\n    this.children = children;\n    this.collapsed = def.collapsed ?? false;\n\n    const leaves = this.leafBindings();\n    if (def.collapseTo === null) {\n      this.collapseTo = null;\n    } else if (def.collapseTo != null && leaves.includes(def.collapseTo)) {\n      this.collapseTo = def.collapseTo;\n    } else {\n      this.collapseTo = leaves[0] ?? null;\n    }\n  }\n\n  /** All descendant leaf bindings, depth-first, in order. */\n  leafBindings(): string[] {\n    const out: string[] = [];\n    collectLeaves(this, out);\n    return out;\n  }\n\n  /** Number of header rows this group's subtree needs (its own row + deepest child). */\n  depth(): number {\n    let max = 0;\n    for (const child of this.children) {\n      if (child.kind === 'group') max = Math.max(max, child.depth());\n    }\n    return max + 1;\n  }\n\n  /** This group and every nested group beneath it, depth-first. */\n  descendantGroups(): ColumnGroup[] {\n    const out: ColumnGroup[] = [this];\n    for (const child of this.children) {\n      if (child.kind === 'group') out.push(...child.descendantGroups());\n    }\n    return out;\n  }\n}\n\nfunction collectLeaves(node: ColumnGroupNode, out: string[]): void {\n  if (node.kind === 'leaf') {\n    out.push(node.binding);\n    return;\n  }\n  for (const child of node.children) collectLeaves(child, out);\n}\n\n/** Lowercase, hyphenated identifier derived from a group's header text. */\nfunction slug(header: string): string {\n  const base = header\n    .trim()\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '');\n  return base || 'group';\n}\n","import { Column } from '../models/Column';\nimport {\n  ColumnGroup,\n  ColumnGroupDef,\n  ColumnGroupLeaf,\n  ColumnGroupNode,\n} from '../models/ColumnGroup';\n\n/**\n * Resolve raw {@link ColumnGroupDef}s (a tree of groups and leaves) against the\n * grid's authored columns. A leaf binding must reference a real column and may\n * belong to only one group; unknown or already-claimed bindings are dropped\n * with a console warning. A group left with no valid leaf descendants is\n * dropped. Returns the top-level groups in def order.\n */\nexport function buildColumnGroups<T>(columns: Column<T>[], defs: ColumnGroupDef[]): ColumnGroup[] {\n  const known = new Set(columns.map((c) => c.binding));\n  const claimed = new Set<string>();\n  const groups: ColumnGroup[] = [];\n  for (const def of defs) {\n    const node = resolveNode(def, known, claimed);\n    // A bare leaf at the top level isn't a group band; skip it (its column still\n    // renders normally). Only groups form header bands.\n    if (node && node.kind === 'group') groups.push(node);\n  }\n  return groups;\n}\n\n// Resolve one def node. Returns a leaf, a group, or null when nothing valid\n// survives (unknown/claimed leaf, or an empty group).\nfunction resolveNode(\n  def: string | ColumnGroupDef,\n  known: Set<string>,\n  claimed: Set<string>,\n): ColumnGroupNode | null {\n  if (typeof def === 'string') return resolveLeaf(def, def, known, claimed);\n\n  // Leaf def: has a binding, no children.\n  if (def.binding != null && !def.columns) {\n    return resolveLeaf(def.binding, def.header ?? def.binding, known, claimed);\n  }\n\n  // Group def: resolve children recursively.\n  const children: ColumnGroupNode[] = [];\n  for (const child of def.columns ?? []) {\n    const node = resolveNode(child, known, claimed);\n    if (node) children.push(node);\n  }\n  if (children.length === 0) return null;\n  return new ColumnGroup(def, children);\n}\n\nfunction resolveLeaf(\n  binding: string,\n  label: string,\n  known: Set<string>,\n  claimed: Set<string>,\n): ColumnGroupLeaf | null {\n  if (!known.has(binding)) {\n    warn(`column group references unknown column \"${binding}\" (in \"${label}\"); ignored`);\n    return null;\n  }\n  if (claimed.has(binding)) {\n    warn(`column \"${binding}\" is already claimed by another group; ignored`);\n    return null;\n  }\n  claimed.add(binding);\n  return new ColumnGroupLeaf(binding);\n}\n\n/** One rendered header cell in the multi-row column-group band. */\nexport interface ColumnGroupCell {\n  /** The group this cell renders, or null when it is a leaf's own header (see `leafCol`). */\n  group: ColumnGroup | null;\n  /** Visible-column indices the cell spans, inclusive. */\n  startCol: number;\n  endCol: number;\n  /** Header row, 0 = topmost. */\n  row: number;\n  /** How many header rows the cell spans down (shallow leaves reach the bottom). */\n  rowSpan: number;\n  /**\n   * For a `group: null` cell, the visible-column index whose leaf header this\n   * cell carries. Such a cell is a real, full-height column header (text, sort,\n   * filter) rendered up here instead of in the leaf-header row below — so a\n   * column shallower than the deepest group still shows one tall header. Always\n   * equals `startCol` (fillers are one column wide).\n   */\n  leafCol?: number;\n  /** Stable pooling identity. */\n  key: string;\n}\n\nexport interface ColumnGroupLayout {\n  /** Number of header rows (max group depth; at least 1 when any group exists). */\n  rows: number;\n  cells: ColumnGroupCell[];\n  /**\n   * Visible-column indices whose leaf header is drawn in the group band (as a\n   * tall `leafCol` cell) rather than the leaf-header row. The leaf HeaderRenderer\n   * skips these so the header isn't drawn twice.\n   */\n  leafHeaderCols: Set<number>;\n}\n\n/**\n * Build the multi-row header layout for the current **visible** columns. Because\n * collapsed groups already dropped their hidden columns upstream, this only ever\n * sees visible columns — a collapsed group shows up as its single `collapseTo`\n * column, whose ancestor chain still names the collapsed group, so its header\n * cell (and chevron) render with no special-casing here.\n *\n * For each header row it emits one cell per maximal run of consecutive columns\n * sharing the same ancestor group at that depth. A column whose group chain is\n * shorter than the total depth gets a single cell that row-spans down to the\n * bottom (top-level leaves like Name/Curr span the whole header height).\n */\nexport function buildColumnGroupLayout<T>(\n  columns: Column<T>[],\n  groups: ColumnGroup[],\n): ColumnGroupLayout {\n  // Map each leaf binding to its ancestor chain (root group → ... → leaf's group).\n  const chains = new Map<string, ColumnGroup[]>();\n  for (const group of groups) indexChains(group, [], chains);\n\n  const rows = groups.reduce((m, g) => Math.max(m, g.depth()), 0);\n  if (rows === 0) return { rows: 0, cells: [], leafHeaderCols: new Set() };\n\n  const cells: ColumnGroupCell[] = [];\n  const leafHeaderCols = new Set<number>();\n  const colChain = (col: number): ColumnGroup[] => chains.get(columns[col]?.binding ?? '') ?? [];\n\n  for (let row = 0; row < rows; row++) {\n    let col = 0;\n    while (col < columns.length) {\n      const chain = colChain(col);\n      const group = chain[row] ?? null;\n\n      if (group) {\n        // Extend the run while the same group occupies this row.\n        let end = col;\n        while (end + 1 < columns.length && colChain(end + 1)[row] === group) end++;\n        cells.push({\n          group,\n          startCol: col,\n          endCol: end,\n          row,\n          rowSpan: 1,\n          key: `${group.key}@${row}:${col}`,\n        });\n        col = end + 1;\n      } else {\n        // No group at this depth: a leaf shallower than the deepest group (or a\n        // fully ungrouped column). Emit ONE full-height cell for it, at the row\n        // where its group-chain ends, carrying the leaf's own header. It spans\n        // down through the remaining header rows, so the column shows a single\n        // tall header instead of a blank gap above the leaf row.\n        if (chain.length === row) {\n          cells.push({\n            group: null,\n            startCol: col,\n            endCol: col,\n            row,\n            rowSpan: rows - row,\n            leafCol: col,\n            key: `leaf@${row}:${col}`,\n          });\n          leafHeaderCols.add(col);\n        }\n        col++;\n      }\n    }\n  }\n  return { rows, cells, leafHeaderCols };\n}\n\n// Record, for each descendant leaf binding, the chain of groups from the root\n// group down to (but not including) the leaf.\nfunction indexChains(\n  node: ColumnGroupNode,\n  ancestors: ColumnGroup[],\n  out: Map<string, ColumnGroup[]>,\n): void {\n  if (node.kind === 'leaf') {\n    out.set(node.binding, ancestors);\n    return;\n  }\n  const next = [...ancestors, node];\n  for (const child of node.children) indexChains(child, next, out);\n}\n\nfunction warn(message: string): void {\n  if (typeof console !== 'undefined') console.warn(`apgrid: ${message}`);\n}\n","import { CollectionViewGroup } from './CollectionViewGroup';\n\nexport interface GroupDisplayRow<T> {\n  kind: 'group';\n  group: CollectionViewGroup<T>;\n  level: number;\n  /** Stable identity across rebuilds, used to remember collapse state. */\n  pathKey: string;\n  collapsed: boolean;\n}\n\nexport interface DataDisplayRow {\n  kind: 'data';\n  /** Index into the collection view's leaf array. */\n  viewIndex: number;\n}\n\nexport type DisplayRow<T> = GroupDisplayRow<T> | DataDisplayRow;\n\n/**\n * Flattens a collection view's group tree into the linear list of rows the grid\n * actually renders: a header row per group followed by its data rows, with the\n * subtree omitted when a group is collapsed. Collapse state is keyed by group\n * path so it survives rebuilds (re-sort, filter, regroup).\n */\nexport class GroupRowModel<T = Record<string, unknown>> {\n  private rows: DisplayRow<T>[] = [];\n  private collapsed = new Set<string>();\n  private allKeys = new Set<string>();\n\n  get length(): number {\n    return this.rows.length;\n  }\n\n  get active(): boolean {\n    return this.rows.length > 0;\n  }\n\n  rebuild(groups: CollectionViewGroup<T>[]): void {\n    this.rows = [];\n    this.allKeys = new Set();\n    if (groups.length === 0) return;\n    let cursor = 0;\n    const walk = (group: CollectionViewGroup<T>, parentPath: string): void => {\n      const pathKey = `${parentPath}\\u0000${group.name}`;\n      this.allKeys.add(pathKey);\n      const collapsed = this.collapsed.has(pathKey);\n      this.rows.push({ kind: 'group', group, level: group.level, pathKey, collapsed });\n      if (collapsed) {\n        cursor += group.items.length; // leaves stay in the view; skip past them\n        return;\n      }\n      if (group.isBottomLevel) {\n        for (let i = 0; i < group.items.length; i++) {\n          this.rows.push({ kind: 'data', viewIndex: cursor++ });\n        }\n      } else {\n        for (const child of group.groups) walk(child, pathKey);\n      }\n    };\n    for (const group of groups) walk(group, '');\n  }\n\n  rowAt(index: number): DisplayRow<T> | undefined {\n    return this.rows[index];\n  }\n\n  isCollapsed(pathKey: string): boolean {\n    return this.collapsed.has(pathKey);\n  }\n\n  toggle(pathKey: string): void {\n    if (this.collapsed.has(pathKey)) this.collapsed.delete(pathKey);\n    else this.collapsed.add(pathKey);\n  }\n\n  collapseAll(): void {\n    this.collapsed = new Set(this.allKeys);\n  }\n\n  expandAll(): void {\n    this.collapsed.clear();\n  }\n\n  /** The path keys of every collapsed group, for saving state. */\n  collapsedKeys(): string[] {\n    return [...this.collapsed];\n  }\n\n  /** Replace the collapsed set (used when restoring saved state). */\n  setCollapsed(keys: string[]): void {\n    this.collapsed = new Set(keys);\n  }\n}\n","import { CollectionView } from './CollectionView';\nimport { GroupRowModel, GroupDisplayRow } from './GroupRowModel';\n\n/**\n * Read-only window over the grid's items. Everything reads rows through this\n * class instead of touching the source array. It is backed by a\n * {@link CollectionView}, so edits routed through {@link applyEdit} are tracked\n * when the view has trackChanges enabled.\n *\n * When the view is grouped, the grid renders a flattened list of display rows\n * (group headers interleaved with data rows). This class maps a display-row\n * index to the underlying leaf item and reports which rows are group headers.\n */\nexport class DataView<T = Record<string, unknown>> {\n  private view: CollectionView<T>;\n  private groupModel = new GroupRowModel<T>();\n\n  constructor(source: T[] | CollectionView<T> = []) {\n    this.view = source instanceof CollectionView ? source : new CollectionView<T>(source);\n  }\n\n  get collectionView(): CollectionView<T> {\n    return this.view;\n  }\n\n  /** Rebuild the display-row list from the view's current group tree. */\n  refreshGroups(): void {\n    this.groupModel.rebuild(this.view.groups);\n  }\n\n  get grouped(): boolean {\n    return this.groupModel.active;\n  }\n\n  /** Number of rows the grid renders (data rows plus visible group headers). */\n  get length(): number {\n    return this.grouped ? this.groupModel.length : this.view.items.length;\n  }\n\n  /** The leaf item at a display-row index, or undefined for group-header rows. */\n  item(index: number): T {\n    if (!this.grouped) return this.view.items[index];\n    const leaf = this.dataIndexAt(index);\n    return leaf >= 0 ? this.view.items[leaf] : (undefined as unknown as T);\n  }\n\n  rowType(index: number): 'group' | 'data' {\n    if (!this.grouped) return 'data';\n    return this.groupModel.rowAt(index)?.kind === 'group' ? 'group' : 'data';\n  }\n\n  /** The group-header descriptor at a display-row index, or null for data rows. */\n  groupRow(index: number): GroupDisplayRow<T> | null {\n    if (!this.grouped) return null;\n    const row = this.groupModel.rowAt(index);\n    return row && row.kind === 'group' ? row : null;\n  }\n\n  /** Map a display-row index to a leaf index in the view, or -1 for group rows. */\n  dataIndexAt(index: number): number {\n    if (!this.grouped) return index;\n    const row = this.groupModel.rowAt(index);\n    return row && row.kind === 'data' ? row.viewIndex : -1;\n  }\n\n  toggleGroup(pathKey: string): void {\n    this.groupModel.toggle(pathKey);\n    this.refreshGroups();\n  }\n\n  collapseAllGroups(): void {\n    this.groupModel.collapseAll();\n    this.refreshGroups();\n  }\n\n  expandAllGroups(): void {\n    this.groupModel.expandAll();\n    this.refreshGroups();\n  }\n\n  /** Path keys of the currently collapsed groups. */\n  collapsedGroups(): string[] {\n    return this.groupModel.collapsedKeys();\n  }\n\n  /** Restore the collapsed groups from saved path keys. */\n  setCollapsedGroups(keys: string[]): void {\n    this.groupModel.setCollapsed(keys);\n    this.refreshGroups();\n  }\n\n  setItems(items: T[]): void {\n    this.view.sourceCollection = items;\n  }\n\n  /** Run a mutation inside an edit transaction so the change view can record it. */\n  applyEdit(item: T, mutate: () => void): void {\n    this.view.editItem(item);\n    mutate();\n    this.view.commitEdit();\n  }\n}\n","/** Describes how a CollectionView sorts on one property. */\nexport class SortDescription {\n  constructor(\n    public readonly property: string,\n    public readonly ascending = true,\n  ) {}\n}\n","/**\n * Describes how a CollectionView groups items on one property. The optional\n * `converter` turns a raw cell value into a group key, so callers can group\n * dates by year or numbers into ranges instead of by exact value.\n */\nexport class PropertyGroupDescription<T = Record<string, unknown>> {\n  constructor(\n    public readonly property: string,\n    private readonly converter?: (item: T, value: unknown) => unknown,\n  ) {}\n\n  /** The key an item belongs under. Items with equal keys share a group. */\n  groupKey(item: T): unknown {\n    const value = (item as Record<string, unknown>)[this.property];\n    return this.converter ? this.converter(item, value) : value;\n  }\n}\n","// Both helpers assume `arr` is sorted ascending. They power the virtualization\n// lookups, so they take number arrays directly rather than a generic comparator.\n\n/** First index where `arr[index] >= target`, or `arr.length` if none. */\nexport function lowerBound(arr: number[], target: number): number {\n  let lo = 0;\n  let hi = arr.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    if (arr[mid] < target) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n\n/** First index where `arr[index] > target`, or `arr.length` if none. */\nexport function upperBound(arr: number[], target: number): number {\n  let lo = 0;\n  let hi = arr.length;\n  while (lo < hi) {\n    const mid = (lo + hi) >>> 1;\n    if (arr[mid] <= target) lo = mid + 1;\n    else hi = mid;\n  }\n  return lo;\n}\n","export function clamp(value: number, min: number, max: number): number {\n  if (value < min) return min;\n  if (value > max) return max;\n  return value;\n}\n","import { Column } from '../models/Column';\nimport { upperBound } from '../utils/BinarySearch';\nimport { clamp } from '../utils/Math';\n\nexport interface IndexRange {\n  first: number;\n  /** Inclusive. `last < first` means the range is empty. */\n  last: number;\n}\n\n/**\n * Maps between pixels and row/column indices.\n *\n * Rows use a uniform height, so row math is O(1) and scales to millions of rows\n * without allocating a per-row array. Columns have individual widths, so their\n * left edges are kept as a cumulative array and located with binary search.\n */\nexport class LayoutEngine {\n  private _rowCount: number;\n  private rowHeight: number;\n  private colLefts: number[];\n\n  constructor(rowCount: number, rowHeight: number, columns: Column[]) {\n    this._rowCount = rowCount;\n    this.rowHeight = rowHeight;\n    this.colLefts = buildColLefts(columns);\n  }\n\n  get rowCount(): number {\n    return this._rowCount;\n  }\n\n  get colCount(): number {\n    return this.colLefts.length - 1;\n  }\n\n  get totalHeight(): number {\n    return this._rowCount * this.rowHeight;\n  }\n\n  get totalWidth(): number {\n    return this.colLefts[this.colLefts.length - 1];\n  }\n\n  getRowTop(row: number): number {\n    return row * this.rowHeight;\n  }\n\n  getRowHeight(_row: number): number {\n    return this.rowHeight;\n  }\n\n  getColLeft(col: number): number {\n    return this.colLefts[col];\n  }\n\n  getColWidth(col: number): number {\n    return this.colLefts[col + 1] - this.colLefts[col];\n  }\n\n  /** Total width of the first `count` columns (the frozen band). */\n  frozenColsWidth(count: number): number {\n    const c = clamp(count, 0, this.colCount);\n    return this.colLefts[c];\n  }\n\n  /** Total height of the first `count` rows (the frozen band). */\n  frozenRowsHeight(count: number): number {\n    return clamp(count, 0, this._rowCount) * this.rowHeight;\n  }\n\n  getVisibleRows(scrollTop: number, viewportHeight: number): IndexRange {\n    if (this._rowCount === 0) return { first: 0, last: -1 };\n    const first = Math.floor(scrollTop / this.rowHeight);\n    const last = Math.floor((scrollTop + viewportHeight - 1) / this.rowHeight);\n    return {\n      first: clamp(first, 0, this._rowCount - 1),\n      last: clamp(last, 0, this._rowCount - 1),\n    };\n  }\n\n  getVisibleCols(scrollLeft: number, viewportWidth: number): IndexRange {\n    const count = this.colCount;\n    if (count === 0) return { first: 0, last: -1 };\n    const first = upperBound(this.colLefts, scrollLeft) - 1;\n    const last = upperBound(this.colLefts, scrollLeft + viewportWidth - 1) - 1;\n    return {\n      first: clamp(first, 0, count - 1),\n      last: clamp(last, 0, count - 1),\n    };\n  }\n\n  rowAtY(y: number): number {\n    return clamp(Math.floor(y / this.rowHeight), 0, this._rowCount - 1);\n  }\n\n  colAtX(x: number): number {\n    return clamp(upperBound(this.colLefts, x) - 1, 0, this.colCount - 1);\n  }\n\n  setRowCount(rowCount: number): void {\n    this._rowCount = rowCount;\n  }\n\n  setColumns(columns: Column[]): void {\n    this.colLefts = buildColLefts(columns);\n  }\n}\n\nfunction buildColLefts(columns: Column[]): number[] {\n  const lefts = new Array<number>(columns.length + 1);\n  lefts[0] = 0;\n  for (let i = 0; i < columns.length; i++) {\n    lefts[i + 1] = lefts[i] + columns[i].width;\n  }\n  return lefts;\n}\n","export function createEl<K extends keyof HTMLElementTagNameMap>(\n  tag: K,\n  className?: string,\n): HTMLElementTagNameMap[K] {\n  const el = document.createElement(tag);\n  if (className) el.className = className;\n  return el;\n}\n\nexport function setTransform(el: HTMLElement, x: number, y: number): void {\n  el.style.transform = `translate3d(${x}px, ${y}px, 0)`;\n}\n\n// Remembers which inline-style properties conditional styling last set on each\n// element, so pooled cells/rows reset cleanly instead of accumulating styles.\nconst conditionalStyleKeys = new WeakMap<HTMLElement, string[]>();\n\n/**\n * Apply conditional inline styles to an element, first clearing any this helper\n * set on a previous pass. Pass null (or an empty object) to just clear.\n */\nexport function setConditionalStyle(el: HTMLElement, style: Record<string, string> | null): void {\n  const prev = conditionalStyleKeys.get(el);\n  if (prev) {\n    for (const key of prev) el.style[key as never] = '' as never;\n    conditionalStyleKeys.delete(el);\n  }\n  if (style) {\n    const keys = Object.keys(style);\n    if (keys.length) {\n      Object.assign(el.style, style);\n      conditionalStyleKeys.set(el, keys);\n    }\n  }\n}\n","import { createEl } from '../utils/DOM';\n\nexport interface ScaffoldConfig {\n  showColumnHeader: boolean;\n  showRowHeader: boolean;\n  headerHeight: number;\n  rowHeaderWidth: number;\n  showGroupPanel: boolean;\n  groupPanelHeight: number;\n  /** Height of the multi-level column-group header band. 0 (default) when there are no groups. */\n  columnGroupHeight?: number;\n}\n\n/**\n * Builds and owns the static DOM scaffold using a single-scroller model:\n * one scroll container holds everything, so the native scrollbars span the whole\n * grid. The data cells scroll normally; the column header, row header, and\n * top-left corner are `position: sticky` panels that the browser keeps pinned on\n * the compositor as the canvas scrolls (header pins vertically, row header\n * horizontally, corner both) — no per-frame JS, so they never flicker. A gutter\n * (rowHeaderWidth × headerHeight) is reserved at the top-left so the cells start\n * past the headers.\n */\nexport class ViewportRenderer {\n  readonly viewport: HTMLElement;\n  readonly canvas: HTMLElement;\n  readonly cells: HTMLElement;\n  readonly mergeLayer: HTMLElement;\n  readonly headerInner: HTMLElement;\n  /** Top header band holding multi-level column-group cells. Present only when there are groups. */\n  readonly columnGroupInner?: HTMLElement;\n  readonly rowHeaderInner: HTMLElement;\n  readonly gutterLeft: number;\n  readonly gutterTop: number;\n  /** Host bar for the grouping panel, present only when it is enabled. */\n  readonly groupPanel?: HTMLElement;\n\n  // Pinned bands. Each is a sticky panel the browser keeps on the compositor:\n  // frozen columns pin left, frozen rows pin top, and the corner pins both.\n  readonly frozenCols: HTMLElement;\n  readonly frozenColsHeader: HTMLElement;\n  readonly frozenRows: HTMLElement;\n  readonly frozenRowsHeader: HTMLElement;\n  readonly frozenCorner: HTMLElement;\n\n  private corner: HTMLElement;\n\n  constructor(\n    private host: HTMLElement,\n    config: ScaffoldConfig,\n  ) {\n    host.classList.add('apg');\n    this.gutterLeft = config.showRowHeader ? config.rowHeaderWidth : 0;\n    // The group band (when present) stacks above the leaf header, so both\n    // heights make up the top gutter.\n    const groupHeight = config.showColumnHeader ? (config.columnGroupHeight ?? 0) : 0;\n    const leafHeaderHeight = config.showColumnHeader ? config.headerHeight : 0;\n    this.gutterTop = groupHeight + leafHeaderHeight;\n\n    this.viewport = createEl('div', 'apg-viewport');\n    this.canvas = createEl('div', 'apg-canvas');\n\n    this.cells = createEl('div', 'apg-cells');\n    this.cells.style.marginLeft = `${this.gutterLeft}px`;\n    this.cells.style.marginTop = `${this.gutterTop}px`;\n    this.cells.style.top = `${this.gutterTop}px`;\n\n    // Spanning cells paint on top of the normal rows, so their layer lives inside\n    // the cells container and is added last.\n    this.mergeLayer = createEl('div', 'apg-merge-layer');\n    this.cells.appendChild(this.mergeLayer);\n\n    // Optional multi-level column-group band, pinned to the very top. The leaf\n    // header sits directly below it.\n    if (config.showColumnHeader && groupHeight > 0) {\n      const groupInner = createEl('div', 'apg-columngroup-inner');\n      groupInner.style.marginLeft = `${this.gutterLeft}px`;\n      groupInner.style.height = `${groupHeight}px`;\n      this.columnGroupInner = groupInner;\n    }\n\n    this.headerInner = createEl('div', 'apg-header-inner');\n    this.headerInner.style.marginLeft = `${this.gutterLeft}px`;\n    this.headerInner.style.height = `${leafHeaderHeight}px`;\n    // Push the leaf header below the group band and pin it there while scrolling.\n    this.headerInner.style.marginTop = `${groupHeight}px`;\n    this.headerInner.style.top = `${groupHeight}px`;\n    this.headerInner.style.display = config.showColumnHeader ? '' : 'none';\n\n    this.rowHeaderInner = createEl('div', 'apg-rowheader-inner');\n    this.rowHeaderInner.style.marginTop = `${this.gutterTop}px`;\n    this.rowHeaderInner.style.top = `${this.gutterTop}px`;\n    this.rowHeaderInner.style.width = `${this.gutterLeft}px`;\n    this.rowHeaderInner.style.display = config.showRowHeader ? '' : 'none';\n\n    this.corner = createEl('div', 'apg-corner');\n    this.corner.style.width = `${this.gutterLeft}px`;\n    this.corner.style.height = `${this.gutterTop}px`;\n    this.corner.style.display = config.showColumnHeader && config.showRowHeader ? '' : 'none';\n\n    // Frozen bands start hidden; Grid sizes and shows them when a freeze is set.\n    this.frozenCols = createEl('div', 'apg-frozen-cols');\n    this.frozenCols.style.left = `${this.gutterLeft}px`;\n    this.frozenCols.style.top = `${this.gutterTop}px`;\n    this.frozenCols.style.marginTop = `${this.gutterTop}px`;\n\n    this.frozenColsHeader = createEl('div', 'apg-frozen-cols-header');\n    this.frozenColsHeader.style.left = `${this.gutterLeft}px`;\n    this.frozenColsHeader.style.marginLeft = `${this.gutterLeft}px`;\n    this.frozenColsHeader.style.height = `${this.gutterTop}px`;\n\n    this.frozenRows = createEl('div', 'apg-frozen-rows');\n    this.frozenRows.style.top = `${this.gutterTop}px`;\n    this.frozenRows.style.marginLeft = `${this.gutterLeft}px`;\n\n    this.frozenRowsHeader = createEl('div', 'apg-frozen-rows-header');\n    this.frozenRowsHeader.style.top = `${this.gutterTop}px`;\n    this.frozenRowsHeader.style.width = `${this.gutterLeft}px`;\n\n    this.frozenCorner = createEl('div', 'apg-frozen-corner');\n    this.frozenCorner.style.top = `${this.gutterTop}px`;\n    this.frozenCorner.style.left = `${this.gutterLeft}px`;\n\n    for (const el of [\n      this.frozenCols,\n      this.frozenColsHeader,\n      this.frozenRows,\n      this.frozenRowsHeader,\n      this.frozenCorner,\n    ]) {\n      el.style.display = 'none';\n    }\n\n    this.canvas.append(\n      this.cells,\n      this.frozenCols,\n      this.frozenRows,\n      this.headerInner,\n      this.rowHeaderInner,\n      this.frozenColsHeader,\n      this.frozenRowsHeader,\n      this.corner,\n      this.frozenCorner,\n    );\n    if (this.columnGroupInner) this.canvas.appendChild(this.columnGroupInner);\n    this.viewport.appendChild(this.canvas);\n\n    if (config.showGroupPanel) {\n      // A bar above the scroll area; the viewport starts below it.\n      const panel = createEl('div', 'apg-grouppanel');\n      panel.style.height = `${config.groupPanelHeight}px`;\n      this.viewport.style.top = `${config.groupPanelHeight}px`;\n      host.appendChild(panel);\n      this.groupPanel = panel;\n    }\n\n    host.appendChild(this.viewport);\n  }\n\n  resize(totalWidth: number, totalHeight: number): void {\n    this.canvas.style.width = `${this.gutterLeft + totalWidth}px`;\n    this.canvas.style.height = `${this.gutterTop + totalHeight}px`;\n    this.headerInner.style.width = `${totalWidth}px`;\n    if (this.columnGroupInner) this.columnGroupInner.style.width = `${totalWidth}px`;\n    this.cells.style.width = `${totalWidth}px`;\n    this.frozenRows.style.width = `${totalWidth}px`;\n  }\n\n  /**\n   * Size the pinned body/row-header/frozen-column panels to the visible viewport\n   * so they clip their translated content. Called on mount and on resize.\n   */\n  setViewport(width: number, height: number): void {\n    void width;\n    const bodyH = Math.max(0, height - this.gutterTop);\n    this.cells.style.height = `${bodyH}px`;\n    this.rowHeaderInner.style.height = `${bodyH}px`;\n    this.frozenCols.style.height = `${bodyH}px`;\n  }\n\n  /** Size and show/hide the frozen bands for the current freeze counts. */\n  setFrozen(colsWidth: number, rowsHeight: number): void {\n    const show = (el: HTMLElement, on: boolean): void => {\n      el.style.display = on ? '' : 'none';\n    };\n    show(this.frozenCols, colsWidth > 0);\n    show(this.frozenColsHeader, colsWidth > 0 && this.gutterTop > 0);\n    show(this.frozenRows, rowsHeight > 0);\n    show(this.frozenRowsHeader, rowsHeight > 0 && this.gutterLeft > 0);\n    show(this.frozenCorner, colsWidth > 0 && rowsHeight > 0);\n\n    this.frozenCols.style.width = `${colsWidth}px`;\n    this.frozenColsHeader.style.width = `${colsWidth}px`;\n    this.frozenRows.style.height = `${rowsHeight}px`;\n    this.frozenRowsHeader.style.height = `${rowsHeight}px`;\n    this.frozenCorner.style.width = `${colsWidth}px`;\n    this.frozenCorner.style.height = `${rowsHeight}px`;\n  }\n\n  dispose(): void {\n    this.groupPanel?.remove();\n    this.viewport.remove();\n    this.host.classList.remove('apg');\n  }\n}\n","import { createEl } from './DOM';\n\n/**\n * Inline SVG icons shared across the grid. Each uses a 16×16 viewBox and\n * `currentColor`, so size and color come from CSS on the wrapping element.\n * They are static markup (no interpolation), so injecting them with innerHTML\n * is safe.\n */\nexport const icons = {\n  // Right-pointing chevron. Rotate it with CSS for expand/collapse or to point\n  // in another direction.\n  chevron:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M6 3.5 10.5 8 6 12.5\"/></svg>',\n  // Six-dot grip shown on draggable chips.\n  dragHandle:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"6\" cy=\"4\" r=\"1.15\"/><circle cx=\"10\" cy=\"4\" r=\"1.15\"/><circle cx=\"6\" cy=\"8\" r=\"1.15\"/><circle cx=\"10\" cy=\"8\" r=\"1.15\"/><circle cx=\"6\" cy=\"12\" r=\"1.15\"/><circle cx=\"10\" cy=\"12\" r=\"1.15\"/></svg>',\n  close:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M4.5 4.5 11.5 11.5M11.5 4.5 4.5 11.5\"/></svg>',\n  sortAsc:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M8 4.5 12 10.5H4z\"/></svg>',\n  sortDesc:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M8 11.5 4 5.5h8z\"/></svg>',\n  // Outline carets used in menus for expand/collapse actions.\n  caretUp:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M4 10.5 8 5.5l4 5\"/></svg>',\n  caretRight:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M6 4l5 4-5 4\"/></svg>',\n  // Filled dot — reads as \"clear/remove sort\".\n  dot: '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"8\" cy=\"8\" r=\"3\"/></svg>',\n  // Stacked, indented bars — reads as \"grouping\".\n  group:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><rect x=\"2\" y=\"3\" width=\"12\" height=\"2\" rx=\"1\"/><rect x=\"5\" y=\"7\" width=\"9\" height=\"2\" rx=\"1\"/><rect x=\"5\" y=\"11\" width=\"9\" height=\"2\" rx=\"1\"/></svg>',\n  // Funnel outline — a column filter that isn't active yet.\n  filter:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M2.5 3.5h11l-4.2 5v4l-2.6 1.3V8.5z\"/></svg>',\n  // Funnel filled — shown when the column has an active filter.\n  filterActive:\n    '<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M2.5 3.5h11l-4.2 5v4l-2.6 1.3V8.5z\"/></svg>',\n} as const;\n\nexport type IconName = keyof typeof icons;\n\n/** Build a span holding an inline SVG icon. Extra classes are appended. */\nexport function iconEl(name: IconName, className?: string): HTMLSpanElement {\n  const span = createEl('span', className ? `apg-icon ${className}` : 'apg-icon');\n  span.innerHTML = icons[name];\n  return span;\n}\n","/**\n * A simple reuse pool. The renderer pulls row/cell elements from here while\n * scrolling instead of creating new DOM, and returns them when they leave the\n * viewport. `reset` runs on release so recycled items come back clean.\n */\nexport class ObjectPool<T> {\n  private free: T[] = [];\n\n  constructor(\n    private readonly create: () => T,\n    private readonly reset?: (item: T) => void,\n  ) {}\n\n  acquire(): T {\n    return this.free.pop() ?? this.create();\n  }\n\n  release(item: T): void {\n    this.reset?.(item);\n    this.free.push(item);\n  }\n\n  get available(): number {\n    return this.free.length;\n  }\n}\n","import { AggregateType } from '../models/Column';\n\n/**\n * Reduce a set of item values to a single aggregate. `count` returns the item\n * count; the numeric aggregates read each value through `getValue`, skip\n * null/non-numeric entries, and return null when nothing numeric is present.\n */\nexport function computeAggregate<T>(\n  items: T[],\n  type: AggregateType,\n  getValue: (item: T) => unknown,\n): number | null {\n  if (type === 'count') return items.length;\n\n  let sum = 0;\n  let count = 0;\n  let min = Infinity;\n  let max = -Infinity;\n  for (const item of items) {\n    const raw = getValue(item);\n    if (raw == null || raw === '') continue; // Number(null)/Number('') are 0, so skip first\n    const n = Number(raw);\n    if (!Number.isFinite(n)) continue;\n    sum += n;\n    count++;\n    if (n < min) min = n;\n    if (n > max) max = n;\n  }\n  if (count === 0) return null;\n\n  switch (type) {\n    case 'sum':\n      return sum;\n    case 'avg':\n      return sum / count;\n    case 'min':\n      return min;\n    case 'max':\n      return max;\n  }\n}\n","import { RenderContext } from './RenderContext';\nimport { CellRenderer } from './CellRenderer';\nimport { createEl, setTransform, setConditionalStyle } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\nimport { ObjectPool } from '../utils/ObjectPool';\nimport { computeAggregate } from '../data/aggregate';\n\ninterface RowView {\n  el: HTMLElement;\n  cells: Map<number, HTMLElement>;\n  kind: 'data' | 'group';\n  label?: HTMLElement;\n}\n\n/**\n * Keeps one pooled `.apg-row` per visible row and one pooled `.apg-cell` per\n * visible column inside it. On each pass it releases rows and cells that left\n * the range and reuses them for the ones that entered — the DOM never grows\n * past the visible window plus its buffer. Group-header rows take a separate\n * path: a sticky label plus aggregate cells instead of data cells.\n */\nexport class RowRenderer {\n  private active = new Map<number, RowView>();\n  private rowClasses = new WeakMap<HTMLElement, string[]>();\n  private rowPool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-row'),\n    (el) => {\n      el.className = 'apg-row';\n      el.style.width = '';\n      el.style.top = '';\n      el.style.transform = '';\n      el.style.willChange = '';\n    },\n  );\n\n  constructor(\n    private canvas: HTMLElement,\n    private cells: CellRenderer,\n  ) {}\n\n  render(ctx: RenderContext): void {\n    const { firstRow, lastRow } = ctx.state;\n    // The frozen panels own the pinned rows, so the body starts past them.\n    const bodyFirst = Math.max(firstRow, ctx.state.frozenRows);\n\n    // Rows that left the range are kept ATTACHED and reused in place for the rows\n    // that entered. Detaching and re-appending would destroy each row's compositor\n    // layer (they use `will-change: transform`) and flash blank on a fast drag.\n    const freeData: RowView[] = [];\n    const freeGroup: RowView[] = [];\n    for (const [row, view] of this.active) {\n      if (row < bodyFirst || row > lastRow) {\n        (view.kind === 'group' ? freeGroup : freeData).push(view);\n        this.active.delete(row);\n      }\n    }\n\n    for (let row = bodyFirst; row <= lastRow; row++) {\n      const kind = ctx.data.rowType(row);\n      let view = this.active.get(row);\n      if (view && view.kind !== kind) {\n        (view.kind === 'group' ? freeGroup : freeData).push(view);\n        this.active.delete(row);\n        view = undefined;\n      }\n      if (!view) {\n        const free = kind === 'group' ? freeGroup : freeData;\n        view = free.pop() ?? this.acquireRow(row, ctx, kind);\n        this.active.set(row, view);\n      }\n      // Body panel is pinned, so rows are placed relative to the scroll each\n      // pass — reposition every visible row, not just newly acquired ones.\n      this.repositionRow(view, row, ctx);\n      if (kind === 'group') this.fillGroup(view, row, ctx);\n      else this.fillCells(view, row, ctx);\n    }\n\n    // Leftover rows (the viewport shrank) are the only ones actually removed.\n    for (const view of freeData) this.releaseRow(view);\n    for (const view of freeGroup) this.releaseRow(view);\n  }\n\n  // Move an already-attached pooled row to a new index without touching the DOM\n  // tree — just its position and alternating-row class.\n  private repositionRow(view: RowView, row: number, ctx: RenderContext): void {\n    const el = view.el;\n    el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n    const top = ctx.layout.getRowTop(row) - ctx.state.scrollTop;\n    if (view.kind === 'group') {\n      el.style.top = `${top}px`;\n    } else {\n      const step = ctx.state.alternatingRowStep;\n      el.classList.toggle('apg-row-alt', step > 0 && Math.floor(row / step) % 2 === 1);\n      setTransform(el, 0, top);\n    }\n  }\n\n  clear(): void {\n    for (const view of this.active.values()) this.releaseRow(view);\n    this.active.clear();\n  }\n\n  private acquireRow(row: number, ctx: RenderContext, kind: 'data' | 'group'): RowView {\n    const el = this.rowPool.acquire();\n    // The body panel is pinned to the viewport, so rows are placed relative to\n    // the current scroll position rather than at absolute canvas coordinates.\n    const top = ctx.layout.getRowTop(row) - ctx.state.scrollTop;\n    el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n\n    if (kind === 'group') {\n      // Positioned with `top` (not transform) so the sticky label inside is free\n      // of a transformed ancestor, which some browsers won't pin.\n      el.classList.add('apg-group-row');\n      el.style.width = `${ctx.layout.totalWidth}px`;\n      el.style.willChange = 'auto';\n      el.style.top = `${top}px`;\n      const label = createEl('div', 'apg-group-label');\n      el.appendChild(label);\n      this.canvas.appendChild(el);\n      return { el, cells: new Map(), kind, label };\n    }\n\n    const step = ctx.state.alternatingRowStep;\n    el.classList.toggle('apg-row-alt', step > 0 && Math.floor(row / step) % 2 === 1);\n    setTransform(el, 0, top);\n    this.canvas.appendChild(el);\n    return { el, cells: new Map(), kind };\n  }\n\n  private fillGroup(view: RowView, row: number, ctx: RenderContext): void {\n    const gr = ctx.data.groupRow(row);\n    const label = view.label;\n    if (!gr || !label) return;\n\n    label.style.paddingLeft = `${gr.level * 20 + 8}px`;\n    label.textContent = '';\n\n    const toggle = iconEl('chevron', 'apg-group-toggle');\n    toggle.classList.toggle('apg-group-toggle-open', !gr.collapsed);\n    label.appendChild(toggle);\n\n    const inner = createEl('span', 'apg-group-inner');\n    if (ctx.groupHeaderTemplate) {\n      const out = ctx.groupHeaderTemplate({\n        group: gr.group,\n        level: gr.level,\n        collapsed: gr.collapsed,\n        itemCount: gr.group.itemCount,\n      });\n      if (typeof out === 'string') inner.innerHTML = out;\n      else inner.appendChild(out);\n    } else {\n      const name = createEl('span', 'apg-group-name');\n      name.textContent = gr.group.name;\n      const count = createEl('span', 'apg-group-count');\n      count.textContent = String(gr.group.itemCount);\n      inner.append(name, count);\n    }\n    label.appendChild(inner);\n\n    const { firstCol, lastCol } = ctx.state;\n    for (const [col, el] of view.cells) {\n      if (col < firstCol || col > lastCol || !ctx.columns[col].aggregate) {\n        el.remove();\n        view.cells.delete(col);\n      }\n    }\n    for (let col = firstCol; col <= lastCol; col++) {\n      const column = ctx.columns[col];\n      if (!column.aggregate) continue;\n      let cell = view.cells.get(col);\n      if (!cell) {\n        cell = createEl('div', 'apg-group-agg');\n        view.el.appendChild(cell);\n        view.cells.set(col, cell);\n      }\n      cell.className = `apg-group-agg apg-align-${column.align}`;\n      cell.style.left = `${ctx.layout.getColLeft(col)}px`;\n      cell.style.width = `${ctx.layout.getColWidth(col)}px`;\n      const value = computeAggregate(gr.group.items, column.aggregate, (it) => column.getValue(it));\n      cell.textContent = value == null ? '' : column.formatValue(value);\n    }\n  }\n\n  private fillCells(view: RowView, row: number, ctx: RenderContext): void {\n    const { firstCol, lastCol, selection, activeCell } = ctx.state;\n    const item = ctx.data.item(row) as Record<string, unknown>;\n    const rowSelected = selection != null && row >= selection.topRow && row <= selection.bottomRow;\n    const activeCol = activeCell && activeCell.row === row ? activeCell.col : -1;\n    // The frozen-column panel owns the pinned columns, so the body starts past them.\n    const bodyFirstCol = Math.max(firstCol, ctx.state.frozenCols);\n\n    this.applyRowStyle(view.el, row, item, ctx);\n\n    for (const [col, cellEl] of view.cells) {\n      if (col < bodyFirstCol || col > lastCol || (ctx.merge && ctx.merge(row, col))) {\n        this.cells.release(cellEl);\n        view.cells.delete(col);\n      }\n    }\n\n    for (let col = bodyFirstCol; col <= lastCol; col++) {\n      // Cells inside a span are painted by the merge layer, not here.\n      if (ctx.merge && ctx.merge(row, col)) continue;\n      let cellEl = view.cells.get(col);\n      if (!cellEl) {\n        cellEl = this.cells.acquire();\n        view.el.appendChild(cellEl);\n        view.cells.set(col, cellEl);\n      }\n      const selected =\n        rowSelected && selection != null && col >= selection.leftCol && col <= selection.rightCol;\n      this.cells.update(\n        cellEl,\n        ctx.columns[col],\n        item,\n        row,\n        ctx.layout.getColLeft(col),\n        ctx.layout.getColWidth(col),\n        selected,\n        col === activeCol,\n      );\n    }\n  }\n\n  private releaseRow(view: RowView): void {\n    if (view.kind === 'group') {\n      for (const cellEl of view.cells.values()) cellEl.remove();\n      view.label?.remove();\n    } else {\n      for (const cellEl of view.cells.values()) this.cells.release(cellEl);\n    }\n    view.cells.clear();\n    this.rowPool.release(view.el);\n    view.el.remove();\n  }\n\n  // Apply the optional row-level conditional class(es) and styles. Previously\n  // applied classes are tracked so recycled rows reset instead of accumulating.\n  private applyRowStyle(\n    el: HTMLElement,\n    row: number,\n    item: Record<string, unknown>,\n    ctx: RenderContext,\n  ): void {\n    if (ctx.rowClass || this.rowClasses.has(el)) {\n      const prev = this.rowClasses.get(el);\n      if (prev) el.classList.remove(...prev);\n      const resolved = ctx.rowClass ? resolveRowValue(ctx.rowClass, { item, row }) : undefined;\n      const classes = toClassList(resolved);\n      if (classes.length) {\n        el.classList.add(...classes);\n        this.rowClasses.set(el, classes);\n      } else {\n        this.rowClasses.delete(el);\n      }\n    }\n    const style = ctx.rowStyle ? resolveRowValue(ctx.rowStyle, { item, row }) : null;\n    setConditionalStyle(el, (style as Record<string, string>) ?? null);\n  }\n}\n\nfunction resolveRowValue<V>(\n  def: V | ((ctx: { item: Record<string, unknown>; row: number }) => V),\n  ctx: { item: Record<string, unknown>; row: number },\n): V {\n  return typeof def === 'function' ? (def as (c: typeof ctx) => V)(ctx) : def;\n}\n\nfunction toClassList(value: string | string[] | null | undefined): string[] {\n  if (!value) return [];\n  const list = Array.isArray(value) ? value : [value];\n  const out: string[] = [];\n  for (const entry of list) for (const token of entry.split(/\\s+/)) if (token) out.push(token);\n  return out;\n}\n","import { RenderContext } from './RenderContext';\nimport { createEl } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\nimport { ObjectPool } from '../utils/ObjectPool';\nimport { buildColumnGroupLayout } from '../data/buildColumnGroups';\n\n/** Renders the column header cells for the visible columns, pooled like body cells. */\nexport class HeaderRenderer {\n  private active = new Map<number, HTMLElement>();\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-header-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-header-cell';\n    },\n  );\n\n  constructor(private inner: HTMLElement) {}\n\n  render(ctx: RenderContext): void {\n    const { firstCol, lastCol } = ctx.state;\n    // The frozen-column header owns the pinned columns; the body starts past them.\n    const bodyFirst = Math.max(firstCol, ctx.state.frozenCols);\n    // Columns whose header is drawn (tall) in the group band are skipped here so\n    // the header isn't rendered twice.\n    const inBand = ctx.columnGroups?.length\n      ? buildColumnGroupLayout(ctx.columns, ctx.columnGroups).leafHeaderCols\n      : null;\n\n    for (const [col, el] of this.active) {\n      if (col < bodyFirst || col > lastCol || inBand?.has(col)) {\n        el.remove();\n        this.pool.release(el);\n        this.active.delete(col);\n      }\n    }\n\n    for (let col = bodyFirst; col <= lastCol; col++) {\n      if (inBand?.has(col)) continue;\n      let el = this.active.get(col);\n      if (!el) {\n        el = this.pool.acquire();\n        this.inner.appendChild(el);\n        this.active.set(col, el);\n      }\n      fillHeaderCell(el, ctx, col);\n    }\n  }\n}\n\n/** Fill a header cell with the column's label, sort arrow, and filter button. */\nexport function fillHeaderCell(el: HTMLElement, ctx: RenderContext, col: number): void {\n  const column = ctx.columns[col];\n  el.className = `apg-header-cell apg-align-${column.align}`;\n  if (column.binding && !column.isCalculated) el.classList.add('apg-sortable');\n  el.style.left = `${ctx.layout.getColLeft(col)}px`;\n  el.style.width = `${ctx.layout.getColWidth(col)}px`;\n  el.textContent = column.header;\n  const sort = ctx.state.sort;\n  if (sort && sort.col === col) {\n    const arrow = createEl('span', 'apg-sort-arrow');\n    arrow.textContent = sort.ascending ? '▲' : '▼';\n    el.appendChild(arrow);\n  }\n  if (column.filterable) {\n    const active = ctx.state.activeFilters.has(col);\n    const btn = createEl('button', 'apg-filter-btn');\n    btn.type = 'button';\n    btn.dataset.filter = String(col);\n    btn.title = active ? 'Edit filter' : 'Filter';\n    if (active) btn.classList.add('apg-filter-active');\n    btn.appendChild(iconEl(active ? 'filterActive' : 'filter'));\n    el.appendChild(btn);\n  }\n}\n","import { RenderContext } from './RenderContext';\nimport { createEl } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\nimport { ObjectPool } from '../utils/ObjectPool';\nimport { fillHeaderCell } from './HeaderRenderer';\nimport { buildColumnGroupLayout, ColumnGroupCell } from '../data/buildColumnGroups';\n\n/**\n * Renders the multi-row column-group header band above the leaf column headers.\n * Each cell — a group span or a blank filler for an ungrouped/shallow column —\n * is a pooled element positioned from the layout: `left`/`width` from the column\n * geometry, `top`/`height` from its header row and row-span. Group cells show the\n * header and, when collapsible, a chevron that toggles the group.\n *\n * Only cells intersecting the visible column window are materialized, so the\n * node count tracks the viewport (times the small, fixed header depth), never the\n * total column count.\n */\nexport class ColumnGroupRenderer {\n  private active = new Map<string, HTMLElement>();\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-columngroup-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-columngroup-cell';\n      el.removeAttribute('data-group');\n    },\n  );\n\n  constructor(\n    private inner: HTMLElement,\n    private onToggle: (key: string) => void,\n    private rowHeight: number,\n  ) {\n    this.inner.addEventListener('click', this.onClick);\n  }\n\n  render(ctx: RenderContext): void {\n    const groups = ctx.columnGroups ?? [];\n    const { cells } = buildColumnGroupLayout(ctx.columns, groups);\n    const { firstCol, lastCol } = ctx.state;\n\n    const visible = new Map<string, ColumnGroupCell>();\n    for (const cell of cells) {\n      if (cell.endCol < firstCol || cell.startCol > lastCol) continue;\n      visible.set(cell.key, cell);\n    }\n\n    for (const [key, el] of this.active) {\n      if (!visible.has(key)) {\n        el.remove();\n        this.pool.release(el);\n        this.active.delete(key);\n      }\n    }\n\n    for (const [key, cell] of visible) {\n      let el = this.active.get(key);\n      if (!el) {\n        el = this.pool.acquire();\n        this.inner.appendChild(el);\n        this.active.set(key, el);\n      }\n      this.fill(el, cell, ctx);\n    }\n  }\n\n  clear(): void {\n    for (const el of this.active.values()) {\n      el.remove();\n      this.pool.release(el);\n    }\n    this.active.clear();\n  }\n\n  dispose(): void {\n    this.inner.removeEventListener('click', this.onClick);\n    this.clear();\n  }\n\n  private fill(el: HTMLElement, cell: ColumnGroupCell, ctx: RenderContext): void {\n    const left = ctx.layout.getColLeft(cell.startCol);\n    const right = ctx.layout.getColLeft(cell.endCol) + ctx.layout.getColWidth(cell.endCol);\n    el.style.left = `${left}px`;\n    el.style.width = `${right - left}px`;\n    el.style.top = `${cell.row * this.rowHeight}px`;\n    el.style.height = `${cell.rowSpan * this.rowHeight}px`;\n    el.style.right = '';\n\n    if (!cell.group) {\n      // A shallow leaf's own header, drawn here as one tall cell (centered,\n      // bordered, sortable/filterable) instead of a blank gap. fillHeaderCell\n      // sets left/width from the column, so re-apply our spanning geometry after.\n      el.removeAttribute('data-group');\n      fillHeaderCell(el, ctx, cell.leafCol ?? cell.startCol);\n      // fillHeaderCell rewrote className to `apg-header-cell …`; re-add the band\n      // classes so the cell is both a header and a band member, and re-apply the\n      // spanning geometry (fillHeaderCell set left/width to the single column).\n      el.classList.add('apg-columngroup-cell', 'apg-columngroup-leaf');\n      el.style.left = `${left}px`;\n      el.style.width = `${right - left}px`;\n      el.style.top = `${cell.row * this.rowHeight}px`;\n      el.style.height = `${cell.rowSpan * this.rowHeight}px`;\n      return;\n    }\n\n    const group = cell.group;\n    el.className = 'apg-columngroup-cell';\n    el.dataset.group = group.key;\n    el.textContent = '';\n\n    if (group.collapsible) {\n      el.classList.add('apg-collapsible');\n      const chevron = iconEl('chevron', 'apg-columngroup-chevron');\n      chevron.classList.toggle('apg-columngroup-chevron-open', !group.collapsed);\n      el.appendChild(chevron);\n    }\n    const label = createEl('span', 'apg-columngroup-label');\n    label.textContent = group.header;\n    el.appendChild(label);\n  }\n\n  private readonly onClick = (e: MouseEvent): void => {\n    const cell = (e.target as HTMLElement).closest<HTMLElement>('.apg-columngroup-cell');\n    if (!cell || !cell.classList.contains('apg-collapsible')) return;\n    const key = cell.dataset.group;\n    if (key) this.onToggle(key);\n  };\n}\n","import { RenderContext } from './RenderContext';\nimport { createEl, setTransform } from '../utils/DOM';\nimport { ObjectPool } from '../utils/ObjectPool';\n\n/** Renders the row-header cells (1-based row numbers) for the visible rows, pooled. */\nexport class RowHeaderRenderer {\n  private active = new Map<number, HTMLElement>();\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-rowheader-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-rowheader-cell';\n    },\n  );\n\n  constructor(private inner: HTMLElement) {}\n\n  render(ctx: RenderContext): void {\n    const { firstRow, lastRow } = ctx.state;\n    // The frozen-row header owns the pinned rows; the body starts past them.\n    const bodyFirst = Math.max(firstRow, ctx.state.frozenRows);\n\n    for (const [row, el] of this.active) {\n      if (row < bodyFirst || row > lastRow) {\n        el.remove();\n        this.pool.release(el);\n        this.active.delete(row);\n      }\n    }\n\n    for (let row = bodyFirst; row <= lastRow; row++) {\n      let el = this.active.get(row);\n      if (!el) {\n        el = this.pool.acquire();\n        this.inner.appendChild(el);\n        this.active.set(row, el);\n      }\n      el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n      setTransform(el, 0, ctx.layout.getRowTop(row) - ctx.state.scrollTop);\n      const isGroup = ctx.data.rowType(row) === 'group';\n      el.className = isGroup ? 'apg-rowheader-cell apg-rowheader-group' : 'apg-rowheader-cell';\n      el.textContent = isGroup ? '' : String(row + 1);\n    }\n  }\n\n  clear(): void {\n    for (const el of this.active.values()) {\n      el.remove();\n      this.pool.release(el);\n    }\n    this.active.clear();\n  }\n}\n","import { Column } from '../models/Column';\nimport { createEl, setConditionalStyle } from '../utils/DOM';\nimport { ObjectPool } from '../utils/ObjectPool';\n\n/** Owns the pool of cell elements and knows how to position and fill one. */\nexport class CellRenderer {\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-cell';\n    },\n  );\n\n  acquire(): HTMLElement {\n    return this.pool.acquire();\n  }\n\n  release(el: HTMLElement): void {\n    el.remove();\n    this.pool.release(el);\n  }\n\n  update(\n    el: HTMLElement,\n    column: Column,\n    item: Record<string, unknown>,\n    row: number,\n    left: number,\n    width: number,\n    selected: boolean,\n    active: boolean,\n  ): void {\n    el.style.left = `${left}px`;\n    el.style.width = `${width}px`;\n    el.className = `apg-cell apg-align-${column.align}`;\n    if (selected) el.classList.add('apg-cell-selected');\n    if (active) el.classList.add('apg-cell-active');\n\n    // Conditional styling (rebuilt every pass, so it tracks edits and never leaks\n    // onto recycled cells).\n    const classes = column.cellClasses(item, row);\n    if (classes.length) el.classList.add(...classes);\n    setConditionalStyle(el, column.cellInlineStyle(item, row));\n\n    if (column.cellTemplate) {\n      el.classList.add('apg-cell-template');\n      el.innerHTML = column.cellTemplate({ value: column.getValue(item), item, row, column });\n    } else if (column.dataType === 'Boolean') {\n      el.classList.add('apg-cell-bool');\n      el.classList.toggle('apg-checked', column.getValue(item) === true);\n      el.textContent = '';\n    } else {\n      // Mapped, editable cells get a chevron so they read as dropdowns at rest.\n      if (column.dataMap && column.editable) el.classList.add('apg-cell-dropdown');\n      el.textContent = column.format(item);\n    }\n  }\n}\n","import { RenderContext } from './RenderContext';\nimport { CellRenderer } from './CellRenderer';\nimport { fillHeaderCell } from './HeaderRenderer';\nimport { ViewportRenderer } from './ViewportRenderer';\nimport { createEl, setTransform } from '../utils/DOM';\nimport { ObjectPool } from '../utils/ObjectPool';\n\ninterface BandRow {\n  el: HTMLElement;\n  cells: Map<number, HTMLElement>;\n}\n\n/**\n * Renders a rectangular band of pooled rows and cells into a pinned panel. Used\n * for the frozen columns, frozen rows, and their shared corner. It mirrors the\n * body renderer's pooling but iterates whatever row/column window it is given.\n */\nclass CellBand {\n  private active = new Map<number, BandRow>();\n  private rowPool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-row apg-frozen-cell-row'),\n    (el) => {\n      el.className = 'apg-row apg-frozen-cell-row';\n      el.style.transform = '';\n      el.style.height = '';\n    },\n  );\n\n  constructor(\n    private inner: HTMLElement,\n    private cells: CellRenderer,\n    private cellClass: string,\n  ) {}\n\n  render(\n    ctx: RenderContext,\n    firstRow: number,\n    lastRow: number,\n    firstCol: number,\n    lastCol: number,\n    yOffset: number,\n  ): void {\n    for (const [row, view] of this.active) {\n      if (row < firstRow || row > lastRow) {\n        this.releaseRow(view);\n        this.active.delete(row);\n      }\n    }\n    for (let row = firstRow; row <= lastRow; row++) {\n      let view = this.active.get(row);\n      if (!view) {\n        view = this.acquireRow(row, ctx);\n        this.active.set(row, view);\n      }\n      view.el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n      setTransform(view.el, 0, ctx.layout.getRowTop(row) - yOffset);\n      this.fill(view, row, ctx, firstCol, lastCol);\n    }\n  }\n\n  clear(): void {\n    for (const view of this.active.values()) this.releaseRow(view);\n    this.active.clear();\n  }\n\n  private acquireRow(row: number, ctx: RenderContext): BandRow {\n    const el = this.rowPool.acquire();\n    el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n    const step = ctx.state.alternatingRowStep;\n    el.classList.toggle('apg-row-alt', step > 0 && Math.floor(row / step) % 2 === 1);\n    this.inner.appendChild(el);\n    return { el, cells: new Map() };\n  }\n\n  private fill(\n    view: BandRow,\n    row: number,\n    ctx: RenderContext,\n    firstCol: number,\n    lastCol: number,\n  ): void {\n    const isGroup = ctx.data.rowType(row) === 'group';\n    view.el.classList.toggle('apg-frozen-group', isGroup);\n\n    // Group rows have no per-column cells in the pinned bands; keep the row as a\n    // blank strip so the background stays continuous with the body.\n    for (const [col, cellEl] of view.cells) {\n      if (isGroup || col < firstCol || col > lastCol) {\n        this.cells.release(cellEl);\n        view.cells.delete(col);\n      }\n    }\n    if (isGroup) return;\n\n    const item = ctx.data.item(row) as Record<string, unknown>;\n    const { selection, activeCell } = ctx.state;\n    const rowSelected = selection != null && row >= selection.topRow && row <= selection.bottomRow;\n    const activeCol = activeCell && activeCell.row === row ? activeCell.col : -1;\n\n    for (let col = firstCol; col <= lastCol; col++) {\n      let cellEl = view.cells.get(col);\n      if (!cellEl) {\n        cellEl = this.cells.acquire();\n        view.el.appendChild(cellEl);\n        view.cells.set(col, cellEl);\n      }\n      const selected =\n        rowSelected && selection != null && col >= selection.leftCol && col <= selection.rightCol;\n      this.cells.update(\n        cellEl,\n        ctx.columns[col],\n        item,\n        row,\n        ctx.layout.getColLeft(col),\n        ctx.layout.getColWidth(col),\n        selected,\n        col === activeCol,\n      );\n      // update() rewrites className, so tag the frozen cell afterwards.\n      cellEl.classList.add('apg-frozen-cell', this.cellClass);\n    }\n  }\n\n  private releaseRow(view: BandRow): void {\n    for (const cellEl of view.cells.values()) this.cells.release(cellEl);\n    view.cells.clear();\n    this.rowPool.release(view.el);\n    view.el.remove();\n  }\n}\n\n/** Pooled header cells for the frozen-column band. */\nclass HeaderBand {\n  private active = new Map<number, HTMLElement>();\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-header-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-header-cell';\n    },\n  );\n\n  constructor(private inner: HTMLElement) {}\n\n  render(ctx: RenderContext, first: number, last: number): void {\n    for (const [col, el] of this.active) {\n      if (col < first || col > last) {\n        el.remove();\n        this.pool.release(el);\n        this.active.delete(col);\n      }\n    }\n    for (let col = first; col <= last; col++) {\n      let el = this.active.get(col);\n      if (!el) {\n        el = this.pool.acquire();\n        this.inner.appendChild(el);\n        this.active.set(col, el);\n      }\n      fillHeaderCell(el, ctx, col);\n    }\n  }\n\n  clear(): void {\n    for (const el of this.active.values()) {\n      el.remove();\n      this.pool.release(el);\n    }\n    this.active.clear();\n  }\n}\n\n/** Pooled row-header (row number) cells for the frozen-row band. */\nclass RowHeaderBand {\n  private active = new Map<number, HTMLElement>();\n  private pool = new ObjectPool<HTMLElement>(\n    () => createEl('div', 'apg-rowheader-cell'),\n    (el) => {\n      el.textContent = '';\n      el.className = 'apg-rowheader-cell';\n    },\n  );\n\n  constructor(private inner: HTMLElement) {}\n\n  render(ctx: RenderContext, first: number, last: number): void {\n    for (const [row, el] of this.active) {\n      if (row < first || row > last) {\n        el.remove();\n        this.pool.release(el);\n        this.active.delete(row);\n      }\n    }\n    for (let row = first; row <= last; row++) {\n      let el = this.active.get(row);\n      if (!el) {\n        el = this.pool.acquire();\n        this.inner.appendChild(el);\n        this.active.set(row, el);\n      }\n      el.style.height = `${ctx.layout.getRowHeight(row)}px`;\n      setTransform(el, 0, ctx.layout.getRowTop(row));\n      const isGroup = ctx.data.rowType(row) === 'group';\n      el.className = isGroup ? 'apg-rowheader-cell apg-rowheader-group' : 'apg-rowheader-cell';\n      el.textContent = isGroup ? '' : String(row + 1);\n    }\n  }\n\n  clear(): void {\n    for (const el of this.active.values()) {\n      el.remove();\n      this.pool.release(el);\n    }\n    this.active.clear();\n  }\n}\n\n/**\n * Draws the pinned regions: the frozen-column band, the frozen-row band, the\n * shared corner where they meet, and the matching header/row-header slices. The\n * three regions partition cleanly — the columns band skips the frozen rows, the\n * rows band skips the frozen columns, and the corner owns the overlap — so no\n * cell is painted twice.\n */\nexport class FrozenRenderer {\n  private colsBand: CellBand;\n  private rowsBand: CellBand;\n  private cornerBand: CellBand;\n  private colsHeader: HeaderBand;\n  private rowsHeader: RowHeaderBand;\n\n  constructor(vp: ViewportRenderer) {\n    this.colsBand = new CellBand(vp.frozenCols, new CellRenderer(), 'apg-frozen-col-cell');\n    this.rowsBand = new CellBand(vp.frozenRows, new CellRenderer(), 'apg-frozen-row-cell');\n    this.cornerBand = new CellBand(vp.frozenCorner, new CellRenderer(), 'apg-frozen-corner-cell');\n    this.colsHeader = new HeaderBand(vp.frozenColsHeader);\n    this.rowsHeader = new RowHeaderBand(vp.frozenRowsHeader);\n  }\n\n  render(ctx: RenderContext): void {\n    const fCols = ctx.state.frozenCols;\n    const fRows = ctx.state.frozenRows;\n    const { firstRow, lastRow, firstCol, lastCol, scrollTop } = ctx.state;\n\n    if (fCols > 0) {\n      // The frozen-column band scrolls vertically with the body, so it uses the\n      // same scroll offset. The frozen-row band and corner stay pinned (offset 0).\n      const bodyFirstRow = Math.max(firstRow, fRows);\n      this.colsBand.render(ctx, bodyFirstRow, lastRow, 0, fCols - 1, scrollTop);\n      this.colsHeader.render(ctx, 0, fCols - 1);\n    } else {\n      this.colsBand.clear();\n      this.colsHeader.clear();\n    }\n\n    if (fRows > 0) {\n      const bodyFirstCol = Math.max(firstCol, fCols);\n      this.rowsBand.render(ctx, 0, fRows - 1, bodyFirstCol, lastCol, 0);\n      this.rowsHeader.render(ctx, 0, fRows - 1);\n    } else {\n      this.rowsBand.clear();\n      this.rowsHeader.clear();\n    }\n\n    if (fCols > 0 && fRows > 0) {\n      this.cornerBand.render(ctx, 0, fRows - 1, 0, fCols - 1, 0);\n    } else {\n      this.cornerBand.clear();\n    }\n  }\n}\n","export interface CellAddress {\n  row: number;\n  col: number;\n}\n\n/** A normalized rectangle of cells (inclusive corners). */\nexport interface CellRange {\n  topRow: number;\n  leftCol: number;\n  bottomRow: number;\n  rightCol: number;\n}\n\nexport function cellEquals(a: CellAddress | null, b: CellAddress | null): boolean {\n  if (a === b) return true;\n  if (!a || !b) return false;\n  return a.row === b.row && a.col === b.col;\n}\n\nexport function rangeEquals(a: CellRange | null, b: CellRange | null): boolean {\n  if (a === b) return true;\n  if (!a || !b) return false;\n  return (\n    a.topRow === b.topRow &&\n    a.leftCol === b.leftCol &&\n    a.bottomRow === b.bottomRow &&\n    a.rightCol === b.rightCol\n  );\n}\n\nexport function makeRange(r1: number, c1: number, r2: number, c2: number): CellRange {\n  return {\n    topRow: Math.min(r1, r2),\n    leftCol: Math.min(c1, c2),\n    bottomRow: Math.max(r1, r2),\n    rightCol: Math.max(c1, c2),\n  };\n}\n\nexport function rangeContains(range: CellRange, row: number, col: number): boolean {\n  return (\n    row >= range.topRow && row <= range.bottomRow && col >= range.leftCol && col <= range.rightCol\n  );\n}\n","import { RenderContext } from './RenderContext';\nimport { CellRenderer } from './CellRenderer';\nimport { CellRange, rangeContains } from '../models/Cell';\n\n/**\n * Paints spanning (merged) cells on top of the normal rows. Each distinct span\n * is drawn once at its origin, sized to cover its whole range, so a span whose\n * origin scrolled above the viewport still fills the visible part. The body\n * renderer skips any cell that falls inside a span, leaving this layer to own it.\n */\nexport class MergeRenderer {\n  private cells = new CellRenderer();\n  private active = new Map<string, HTMLElement>();\n\n  constructor(private layer: HTMLElement) {}\n\n  render(ctx: RenderContext): void {\n    if (!ctx.merge) {\n      this.clear();\n      return;\n    }\n    const { firstRow, lastRow, firstCol, lastCol } = ctx.state;\n    const seen = new Set<string>();\n\n    for (let col = firstCol; col <= lastCol; col++) {\n      let row = firstRow;\n      while (row <= lastRow) {\n        const range = ctx.merge(row, col);\n        if (!range) {\n          row++;\n          continue;\n        }\n        const key = `${range.topRow}:${range.leftCol}`;\n        if (!seen.has(key)) {\n          seen.add(key);\n          this.renderSpan(ctx, range, key);\n        }\n        row = range.bottomRow + 1;\n      }\n    }\n\n    for (const [key, el] of this.active) {\n      if (!seen.has(key)) {\n        this.cells.release(el);\n        this.active.delete(key);\n      }\n    }\n  }\n\n  clear(): void {\n    for (const el of this.active.values()) this.cells.release(el);\n    this.active.clear();\n  }\n\n  private renderSpan(ctx: RenderContext, range: CellRange, key: string): void {\n    let el = this.active.get(key);\n    if (!el) {\n      el = this.cells.acquire();\n      this.layer.appendChild(el);\n      this.active.set(key, el);\n    }\n\n    const col = range.leftCol;\n    const item = ctx.data.item(range.topRow) as Record<string, unknown>;\n    const left = ctx.layout.getColLeft(col);\n    const right = ctx.layout.getColLeft(range.rightCol) + ctx.layout.getColWidth(range.rightCol);\n    // The body panel is pinned, so spans are placed relative to the scroll.\n    const top = ctx.layout.getRowTop(range.topRow) - ctx.state.scrollTop;\n    const bottom =\n      ctx.layout.getRowTop(range.bottomRow) +\n      ctx.layout.getRowHeight(range.bottomRow) -\n      ctx.state.scrollTop;\n\n    const sel = ctx.state.selection;\n    const selected = sel != null && intersects(sel, range);\n    const active =\n      ctx.state.activeCell != null &&\n      rangeContains(range, ctx.state.activeCell.row, ctx.state.activeCell.col);\n\n    this.cells.update(\n      el,\n      ctx.columns[col],\n      item,\n      range.topRow,\n      left,\n      right - left,\n      selected,\n      active,\n    );\n    el.classList.add('apg-cell-merged');\n    el.style.top = `${top}px`;\n    el.style.height = `${bottom - top}px`;\n  }\n}\n\nfunction intersects(a: CellRange, b: CellRange): boolean {\n  return (\n    a.topRow <= b.bottomRow &&\n    a.bottomRow >= b.topRow &&\n    a.leftCol <= b.rightCol &&\n    a.rightCol >= b.leftCol\n  );\n}\n","import { RenderContext } from './RenderContext';\nimport { ViewportRenderer } from './ViewportRenderer';\nimport { RowRenderer } from './RowRenderer';\nimport { HeaderRenderer } from './HeaderRenderer';\nimport { RowHeaderRenderer } from './RowHeaderRenderer';\nimport { FrozenRenderer } from './FrozenRenderer';\nimport { MergeRenderer } from './MergeRenderer';\nimport { ColumnGroupRenderer } from './ColumnGroupRenderer';\n\n/** Runs one render pass: headers, then body rows, then the pinned bands. */\nexport class Renderer {\n  private frozen: FrozenRenderer;\n  private merge: MergeRenderer;\n\n  constructor(\n    private viewport: ViewportRenderer,\n    private rows: RowRenderer,\n    private header: HeaderRenderer,\n    private rowHeader: RowHeaderRenderer,\n    private showRowHeader: boolean,\n    private columnGroups?: ColumnGroupRenderer,\n  ) {\n    this.frozen = new FrozenRenderer(viewport);\n    this.merge = new MergeRenderer(viewport.mergeLayer);\n  }\n\n  /** Resize the scroll canvas to the current totals. Call when layout changes. */\n  resize(ctx: RenderContext): void {\n    this.viewport.resize(ctx.layout.totalWidth, ctx.layout.totalHeight);\n  }\n\n  render(ctx: RenderContext): void {\n    // The group-header band sits above the leaf headers; draw it first.\n    this.columnGroups?.render(ctx);\n    this.header.render(ctx);\n    this.rows.render(ctx);\n    if (this.showRowHeader) {\n      this.rowHeader.render(ctx);\n    }\n    this.merge.render(ctx);\n    this.frozen.render(ctx);\n  }\n}\n","/**\n * Renders on scroll. Browsers fire `scroll` at most once per frame, so we render\n * synchronously in the handler instead of deferring to the next animation frame —\n * deferring leaves a blank frame on a fast drag, where the viewport has already\n * moved but the rows for the new position haven't been placed yet.\n */\nexport class ScrollManager {\n  private readonly onScroll = (): void => {\n    this.tick();\n  };\n\n  constructor(\n    private scroller: HTMLElement,\n    private tick: () => void,\n  ) {\n    this.scroller.addEventListener('scroll', this.onScroll, { passive: true });\n  }\n\n  dispose(): void {\n    this.scroller.removeEventListener('scroll', this.onScroll);\n  }\n}\n","import { CellAddress, CellRange, cellEquals, makeRange } from '../models/Cell';\n\n/**\n * Selection behavior. `None` disables selection; `Cell`/`Row`/`Column` select a\n * single item; the `*Range` variants extend to a contiguous block.\n */\nexport type SelectionMode =\n  'None' | 'Cell' | 'CellRange' | 'Row' | 'RowRange' | 'Column' | 'ColumnRange';\n\nexport interface GridBounds {\n  rowCount: number;\n  colCount: number;\n}\n\nconst RANGE_MODES = new Set<SelectionMode>(['CellRange', 'RowRange', 'ColumnRange']);\n\n/**\n * Tracks the active cell and the anchor it extends from. The highlighted\n * rectangle is derived from those plus the mode, so the active cell keeps its\n * real column even in Row mode (where the whole row is highlighted).\n */\nexport class SelectionModel {\n  private active: CellAddress | null = null;\n  private anchor: CellAddress | null = null;\n\n  constructor(private mode: SelectionMode = 'Cell') {}\n\n  getMode(): SelectionMode {\n    return this.mode;\n  }\n\n  setMode(mode: SelectionMode): boolean {\n    if (this.mode === mode) return false;\n    this.mode = mode;\n    if (mode === 'None') {\n      this.active = null;\n      this.anchor = null;\n    } else if (this.active) {\n      this.anchor = { ...this.active };\n    }\n    return true;\n  }\n\n  getActive(): CellAddress | null {\n    return this.active ? { ...this.active } : null;\n  }\n\n  /** The highlighted rectangle for the current mode, or null if nothing is selected. */\n  getRange(bounds: GridBounds): CellRange | null {\n    if (this.mode === 'None' || !this.active) return null;\n    const a = this.active;\n    const anc = this.anchor ?? a;\n    const lastRow = bounds.rowCount - 1;\n    const lastCol = bounds.colCount - 1;\n\n    switch (this.mode) {\n      case 'Cell':\n        return makeRange(a.row, a.col, a.row, a.col);\n      case 'CellRange':\n        return makeRange(anc.row, anc.col, a.row, a.col);\n      case 'Row':\n        return makeRange(a.row, 0, a.row, lastCol);\n      case 'RowRange':\n        return makeRange(anc.row, 0, a.row, lastCol);\n      case 'Column':\n        return makeRange(0, a.col, lastRow, a.col);\n      case 'ColumnRange':\n        return makeRange(0, anc.col, lastRow, a.col);\n      default:\n        return null;\n    }\n  }\n\n  /** Move the active cell. With `extend` (and a range mode) the anchor stays put. */\n  moveTo(cell: CellAddress, extend: boolean): boolean {\n    if (this.mode === 'None') return false;\n\n    const keepAnchor = extend && RANGE_MODES.has(this.mode) && this.active != null;\n    const nextAnchor = keepAnchor ? (this.anchor ?? { ...this.active! }) : { ...cell };\n    const changed = !cellEquals(this.active, cell) || !cellEquals(this.anchor, nextAnchor);\n\n    this.active = { ...cell };\n    this.anchor = nextAnchor;\n    return changed;\n  }\n\n  clear(): boolean {\n    if (!this.active && !this.anchor) return false;\n    this.active = null;\n    this.anchor = null;\n    return true;\n  }\n}\n","import { CellAddress } from '../models/Cell';\nimport { LayoutEngine } from '../virtualization/LayoutEngine';\n\n/**\n * Translates mouse events on the viewport into cell addresses. A press selects;\n * dragging with the button down (or shift+click) extends the selection, which\n * the grid applies according to its selection mode.\n */\nexport class MouseHandler {\n  private dragging = false;\n\n  private readonly onMouseDown = (e: MouseEvent): void => {\n    if (e.button !== 0) return;\n    // Let clicks inside an open editor select text normally.\n    if ((e.target as HTMLElement).closest('.apg-editor')) return;\n    const cell = this.hitTest(e);\n    if (!cell) return;\n    e.preventDefault(); // keep the browser from starting a text selection\n    this.dragging = true;\n    this.onSelect(cell, e.shiftKey, true);\n  };\n\n  private readonly onMouseMove = (e: MouseEvent): void => {\n    if (!this.dragging) return;\n    const cell = this.hitTest(e);\n    if (cell) this.onSelect(cell, true, false);\n  };\n\n  private readonly onMouseUp = (): void => {\n    this.dragging = false;\n  };\n\n  private readonly onDoubleClick = (e: MouseEvent): void => {\n    if ((e.target as HTMLElement).closest('.apg-editor')) return;\n    const cell = this.hitTest(e);\n    if (cell) this.onDouble(cell);\n  };\n\n  constructor(\n    private viewport: HTMLElement,\n    private layout: LayoutEngine,\n    private onSelect: (cell: CellAddress, extend: boolean, isPress: boolean) => void,\n    private onDouble: (cell: CellAddress) => void,\n    private gutterLeft: number,\n    private gutterTop: number,\n  ) {\n    this.viewport.addEventListener('mousedown', this.onMouseDown);\n    this.viewport.addEventListener('dblclick', this.onDoubleClick);\n    window.addEventListener('mousemove', this.onMouseMove);\n    window.addEventListener('mouseup', this.onMouseUp);\n  }\n\n  dispose(): void {\n    this.viewport.removeEventListener('mousedown', this.onMouseDown);\n    this.viewport.removeEventListener('dblclick', this.onDoubleClick);\n    window.removeEventListener('mousemove', this.onMouseMove);\n    window.removeEventListener('mouseup', this.onMouseUp);\n  }\n\n  private hitTest(e: MouseEvent): CellAddress | null {\n    if (this.layout.rowCount === 0 || this.layout.colCount === 0) return null;\n    const rect = this.viewport.getBoundingClientRect();\n    const vx = e.clientX - rect.left;\n    const vy = e.clientY - rect.top;\n    // Clicks on the pinned header/corner gutters are not data cells.\n    if (vx < this.gutterLeft || vy < this.gutterTop) return null;\n    const x = vx - this.gutterLeft + this.viewport.scrollLeft;\n    const y = vy - this.gutterTop + this.viewport.scrollTop;\n    return { row: this.layout.rowAtY(y), col: this.layout.colAtX(x) };\n  }\n}\n","export type NavAction = 'up' | 'down' | 'left' | 'right' | 'home' | 'end' | 'pageup' | 'pagedown';\n\n/** Maps grid navigation and undo/redo keys and forwards them to the grid. */\nexport class KeyboardHandler {\n  private readonly onKeyDown = (e: KeyboardEvent): void => {\n    if (e.ctrlKey || e.metaKey) {\n      const key = e.key.toLowerCase();\n      if (key === 'z') {\n        e.preventDefault();\n        this.onUndoRedo(e.shiftKey ? 'redo' : 'undo');\n        return;\n      }\n      if (key === 'y') {\n        e.preventDefault();\n        this.onUndoRedo('redo');\n        return;\n      }\n      return;\n    }\n    if (e.key === ' ' || e.key === 'F2' || e.key === 'Enter') {\n      e.preventDefault();\n      this.onActivate();\n      return;\n    }\n    const action = toAction(e.key);\n    if (!action) return;\n    e.preventDefault();\n    this.onNav(action, e.shiftKey);\n  };\n\n  constructor(\n    private host: HTMLElement,\n    private onNav: (action: NavAction, extend: boolean) => void,\n    private onUndoRedo: (action: 'undo' | 'redo') => void,\n    private onActivate: () => void,\n  ) {\n    this.host.addEventListener('keydown', this.onKeyDown);\n  }\n\n  dispose(): void {\n    this.host.removeEventListener('keydown', this.onKeyDown);\n  }\n}\n\nfunction toAction(key: string): NavAction | null {\n  switch (key) {\n    case 'ArrowUp':\n      return 'up';\n    case 'ArrowDown':\n      return 'down';\n    case 'ArrowLeft':\n      return 'left';\n    case 'ArrowRight':\n      return 'right';\n    case 'Home':\n      return 'home';\n    case 'End':\n      return 'end';\n    case 'PageUp':\n      return 'pageup';\n    case 'PageDown':\n      return 'pagedown';\n    default:\n      return null;\n  }\n}\n","import { LayoutEngine } from '../virtualization/LayoutEngine';\nimport { Column } from '../models/Column';\n\nconst EDGE = 5;\nconst MIN_WIDTH = 24;\n\n/**\n * Drag-to-resize columns from the header. Hit-tests the pointer against column\n * right edges (no per-cell handles, since header cells are pooled). Previews the\n * new width live, then commits once through `commit` so it lands as one undoable\n * action.\n */\nexport class ColumnResizer {\n  private col = -1;\n  private startX = 0;\n  private startWidth = 0;\n\n  private readonly onDown = (e: MouseEvent): void => {\n    const col = this.edgeAt(e);\n    if (col < 0) return;\n    e.preventDefault();\n    this.col = col;\n    this.startX = e.clientX;\n    this.startWidth = this.columns()[col].width;\n    window.addEventListener('mousemove', this.onMove);\n    window.addEventListener('mouseup', this.onUp);\n  };\n\n  private readonly onHover = (e: MouseEvent): void => {\n    this.header.style.cursor = this.edgeAt(e) >= 0 ? 'col-resize' : '';\n  };\n\n  private readonly onMove = (e: MouseEvent): void => {\n    const width = Math.max(MIN_WIDTH, this.startWidth + (e.clientX - this.startX));\n    this.columns()[this.col].width = width;\n    this.preview();\n  };\n\n  private readonly onUp = (e: MouseEvent): void => {\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n    const width = Math.max(MIN_WIDTH, this.startWidth + (e.clientX - this.startX));\n    this.columns()[this.col].width = this.startWidth; // restore so commit records one action\n    this.commit(this.col, width);\n    this.col = -1;\n  };\n\n  constructor(\n    private header: HTMLElement,\n    private layout: LayoutEngine,\n    private columns: () => Column[],\n    private preview: () => void,\n    private commit: (col: number, width: number) => void,\n  ) {\n    this.header.addEventListener('mousedown', this.onDown);\n    this.header.addEventListener('mousemove', this.onHover);\n  }\n\n  dispose(): void {\n    this.header.removeEventListener('mousedown', this.onDown);\n    this.header.removeEventListener('mousemove', this.onHover);\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n  }\n\n  private edgeAt(e: MouseEvent): number {\n    const rect = this.header.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const col = this.layout.colAtX(x);\n    const right = this.layout.getColLeft(col) + this.layout.getColWidth(col);\n    return Math.abs(x - right) <= EDGE ? col : -1;\n  }\n}\n","import { LayoutEngine } from '../virtualization/LayoutEngine';\nimport { Column } from '../models/Column';\nimport { createEl } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\n\nconst EDGE = 5; // resize zone — leave it to the ColumnResizer\nconst THRESHOLD = 4; // pixels before a press becomes a drag\n\n/**\n * Drag a column header to reorder columns. A press that moves past the threshold\n * starts a drag, shows a drop marker at the nearest column boundary, and commits\n * the move on release.\n */\nexport class ColumnDragger {\n  private srcCol = -1;\n  private startX = 0;\n  private dragging = false;\n  private overZone = false;\n  private marker = createEl('div', 'apg-col-drop-marker');\n  private ghost?: HTMLElement;\n  private insertAt = 0;\n\n  private readonly onDown = (e: MouseEvent): void => {\n    if (e.button !== 0 || this.isEdge(e)) return;\n    this.srcCol = this.colAt(e);\n    if (this.srcCol < 0) return;\n    this.startX = e.clientX;\n    this.dragging = false;\n    window.addEventListener('mousemove', this.onMove);\n    window.addEventListener('mouseup', this.onUp);\n  };\n\n  private readonly onMove = (e: MouseEvent): void => {\n    if (!this.dragging) {\n      if (Math.abs(e.clientX - this.startX) < THRESHOLD) return;\n      this.dragging = true;\n      this.header.style.cursor = 'grabbing';\n      this.header.appendChild(this.marker);\n      this.showGhost();\n    }\n    this.moveGhost(e);\n    // Over the group panel: switch from reordering to \"group by this column\".\n    if (this.isOverGroupZone(e)) {\n      if (!this.overZone) {\n        this.overZone = true;\n        this.marker.style.display = 'none';\n        this.ghost?.classList.add('apg-drag-ghost-active');\n        this.onGroupHover?.(true);\n      }\n      return;\n    }\n    if (this.overZone) {\n      this.overZone = false;\n      this.marker.style.display = '';\n      this.ghost?.classList.remove('apg-drag-ghost-active');\n      this.onGroupHover?.(false);\n    }\n    const x = this.contentX(e);\n    const col = this.layout.colAtX(x);\n    const mid = this.layout.getColLeft(col) + this.layout.getColWidth(col) / 2;\n    this.insertAt = x < mid ? col : col + 1;\n    this.marker.style.left = `${this.layout.getColLeft(this.insertAt)}px`;\n  };\n\n  private readonly onUp = (): void => {\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n    this.header.style.cursor = '';\n    this.removeGhost();\n    if (this.dragging) {\n      this.marker.remove();\n      this.marker.style.display = '';\n      if (this.overZone && this.onGroupBy) {\n        this.onGroupBy(this.srcCol);\n      } else {\n        const to = this.insertAt > this.srcCol ? this.insertAt - 1 : this.insertAt;\n        if (to !== this.srcCol) this.commit(this.srcCol, to);\n      }\n    }\n    this.onGroupHover?.(false);\n    this.overZone = false;\n    this.srcCol = -1;\n    this.dragging = false;\n  };\n\n  constructor(\n    private header: HTMLElement,\n    private layout: LayoutEngine,\n    private columns: () => Column[],\n    private commit: (from: number, to: number) => void,\n    private groupZone?: () => DOMRect | null,\n    private onGroupBy?: (col: number) => void,\n    private onGroupHover?: (active: boolean) => void,\n  ) {\n    this.header.addEventListener('mousedown', this.onDown);\n  }\n\n  dispose(): void {\n    this.header.removeEventListener('mousedown', this.onDown);\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n    this.marker.remove();\n    this.removeGhost();\n  }\n\n  // A label chip that follows the cursor while dragging, so it's clear a header\n  // is being moved (and where it can go).\n  private showGhost(): void {\n    const header = this.columns()[this.srcCol]?.header ?? '';\n    this.ghost = createEl('div', 'apg-drag-ghost');\n    this.ghost.appendChild(iconEl('group', 'apg-drag-ghost-icon'));\n    const label = createEl('span', 'apg-drag-ghost-label');\n    label.textContent = header;\n    this.ghost.appendChild(label);\n    document.body.appendChild(this.ghost);\n  }\n\n  private moveGhost(e: MouseEvent): void {\n    if (!this.ghost) return;\n    // Anchor the chip on the pointer: cursor sits just inside its left edge,\n    // vertically centered, so it reads as \"held\" by the mouse.\n    const h = this.ghost.offsetHeight || 26;\n    this.ghost.style.left = `${e.clientX - 6}px`;\n    this.ghost.style.top = `${e.clientY - h / 2}px`;\n  }\n\n  private removeGhost(): void {\n    this.ghost?.remove();\n    this.ghost = undefined;\n  }\n\n  private contentX(e: MouseEvent): number {\n    return e.clientX - this.header.getBoundingClientRect().left;\n  }\n\n  private colAt(e: MouseEvent): number {\n    if (this.columns().length === 0) return -1;\n    return this.layout.colAtX(this.contentX(e));\n  }\n\n  private isEdge(e: MouseEvent): boolean {\n    const x = this.contentX(e);\n    const col = this.layout.colAtX(x);\n    const right = this.layout.getColLeft(col) + this.layout.getColWidth(col);\n    return Math.abs(x - right) <= EDGE;\n  }\n\n  private isOverGroupZone(e: MouseEvent): boolean {\n    const rect = this.groupZone?.();\n    if (!rect) return false;\n    return (\n      e.clientX >= rect.left &&\n      e.clientX <= rect.right &&\n      e.clientY >= rect.top &&\n      e.clientY <= rect.bottom\n    );\n  }\n}\n","export interface ClipboardDeps {\n  /** True while a cell editor is open, so clipboard events go to the editor. */\n  isEditing: () => boolean;\n  /** Text to write to the clipboard for the current selection, or null to skip. */\n  getClip: () => string | null;\n  /** Apply pasted text to the grid. */\n  applyClip: (text: string) => void;\n}\n\n/**\n * Wires the grid's copy and paste shortcuts to the system clipboard. It listens\n * for the browser's native copy/paste events on the host, which fire on Ctrl+C\n * and Ctrl+V (and the menu actions) while the grid has focus. Using these events\n * means pasted text can come from another app (a spreadsheet) or from the grid\n * itself, in the same tab-delimited format.\n */\nexport class ClipboardHandler {\n  private readonly onCopy = (e: ClipboardEvent): void => {\n    if (this.deps.isEditing() || !e.clipboardData) return;\n    const text = this.deps.getClip();\n    if (text == null) return;\n    e.clipboardData.setData('text/plain', text);\n    e.preventDefault();\n  };\n\n  private readonly onPaste = (e: ClipboardEvent): void => {\n    if (this.deps.isEditing() || !e.clipboardData) return;\n    const text = e.clipboardData.getData('text/plain');\n    if (!text) return;\n    e.preventDefault();\n    this.deps.applyClip(text);\n  };\n\n  constructor(\n    private host: HTMLElement,\n    private deps: ClipboardDeps,\n  ) {\n    this.host.addEventListener('copy', this.onCopy);\n    this.host.addEventListener('paste', this.onPaste);\n  }\n\n  dispose(): void {\n    this.host.removeEventListener('copy', this.onCopy);\n    this.host.removeEventListener('paste', this.onPaste);\n  }\n}\n","import { ExportData, ExportFormat, ExportOptions } from '../types';\n\n/**\n * CSV writer following RFC 4180: fields containing the delimiter, a quote, or a\n * newline are wrapped in double quotes and inner quotes are doubled. A UTF-8 BOM\n * is prefixed by default so Excel opens the file as UTF-8.\n */\nexport const csvFormat: ExportFormat = {\n  id: 'csv',\n  extension: 'csv',\n  mimeType: 'text/csv;charset=utf-8',\n\n  render(data: ExportData, options: ExportOptions): string {\n    const opts = options.csv ?? {};\n    const delimiter = opts.delimiter ?? ',';\n    const newline = opts.newline ?? '\\r\\n';\n    const bom = opts.bom ?? true;\n    const includeHeaders = options.includeHeaders ?? true;\n\n    const escape = (field: string): string => {\n      if (\n        field.includes(delimiter) ||\n        field.includes('\"') ||\n        field.includes('\\n') ||\n        field.includes('\\r')\n      ) {\n        return `\"${field.replace(/\"/g, '\"\"')}\"`;\n      }\n      return field;\n    };\n\n    const lines: string[] = [];\n    if (includeHeaders) {\n      lines.push(data.columns.map((c) => escape(c.header)).join(delimiter));\n    }\n    for (const row of data.rows) {\n      lines.push(row.cells.map((cell) => escape(cell.text)).join(delimiter));\n    }\n\n    const body = lines.join(newline);\n    return bom ? `\\uFEFF${body}` : body;\n  },\n};\n","/**\n * CRC-32 (IEEE 802.3, polynomial 0xEDB88370 reflected) used by the ZIP file\n * format. Zero-dependency: the lookup table is built once on first use.\n */\n\nlet table: Uint32Array | null = null;\n\nfunction buildTable(): Uint32Array {\n  const t = new Uint32Array(256);\n  for (let n = 0; n < 256; n++) {\n    let c = n;\n    for (let k = 0; k < 8; k++) {\n      c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n    }\n    t[n] = c >>> 0;\n  }\n  return t;\n}\n\n/** Compute the CRC-32 of a byte array. Returns an unsigned 32-bit integer. */\nexport function crc32(bytes: Uint8Array): number {\n  if (!table) table = buildTable();\n  let crc = 0xffffffff;\n  for (let i = 0; i < bytes.length; i++) {\n    crc = table[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8);\n  }\n  return (crc ^ 0xffffffff) >>> 0;\n}\n","import { crc32 } from './crc32';\n\n/**\n * A minimal ZIP (PKZIP / OPC) writer built from scratch — no dependencies. It\n * emits STORED entries (compression method 0, i.e. no compression), which is a\n * fully valid ZIP that Excel and every unzip tool open without complaint;\n * DEFLATE would only reduce size. Enough to package an .xlsx (an OPC ZIP of\n * XML parts).\n *\n * All multi-byte fields are little-endian, per the ZIP spec.\n */\n\ninterface Entry {\n  nameBytes: Uint8Array;\n  data: Uint8Array;\n  crc: number;\n  offset: number; // byte offset of this entry's local header\n}\n\nconst LOCAL_SIG = 0x04034b50;\nconst CENTRAL_SIG = 0x02014b50;\nconst EOCD_SIG = 0x06054b50;\nconst VERSION = 20; // 2.0 — needed for STORED with data descriptor-less entries\n\nconst utf8 = new TextEncoder();\n\nexport class ZipWriter {\n  private entries: Entry[] = [];\n  private chunks: Uint8Array[] = [];\n  private offset = 0;\n\n  /** Add a file. `content` is UTF-8 text or raw bytes. */\n  add(path: string, content: string | Uint8Array): void {\n    const data = typeof content === 'string' ? utf8.encode(content) : content;\n    const nameBytes = utf8.encode(path);\n    const crc = crc32(data);\n    const entry: Entry = { nameBytes, data, crc, offset: this.offset };\n    this.entries.push(entry);\n\n    // Local file header (30 bytes + name), then the stored data.\n    const header = new Uint8Array(30 + nameBytes.length);\n    const v = new DataView(header.buffer);\n    v.setUint32(0, LOCAL_SIG, true);\n    v.setUint16(4, VERSION, true);\n    v.setUint16(6, 0, true); // general purpose flags\n    v.setUint16(8, 0, true); // method 0 = stored\n    v.setUint16(10, 0, true); // mod time\n    v.setUint16(12, 0x21, true); // mod date (1980-01-01 is 0x21)\n    v.setUint32(14, crc, true);\n    v.setUint32(18, data.length, true); // compressed size == size (stored)\n    v.setUint32(22, data.length, true); // uncompressed size\n    v.setUint16(26, nameBytes.length, true);\n    v.setUint16(28, 0, true); // extra field length\n    header.set(nameBytes, 30);\n\n    this.push(header);\n    this.push(data);\n  }\n\n  /** Finish the archive and return the complete ZIP bytes. */\n  build(): Uint8Array {\n    const centralStart = this.offset;\n\n    for (const e of this.entries) {\n      const rec = new Uint8Array(46 + e.nameBytes.length);\n      const v = new DataView(rec.buffer);\n      v.setUint32(0, CENTRAL_SIG, true);\n      v.setUint16(4, VERSION, true); // version made by\n      v.setUint16(6, VERSION, true); // version needed\n      v.setUint16(8, 0, true); // flags\n      v.setUint16(10, 0, true); // method (stored)\n      v.setUint16(12, 0, true); // mod time\n      v.setUint16(14, 0x21, true); // mod date\n      v.setUint32(16, e.crc, true);\n      v.setUint32(20, e.data.length, true); // compressed size\n      v.setUint32(24, e.data.length, true); // uncompressed size\n      v.setUint16(28, e.nameBytes.length, true);\n      v.setUint16(30, 0, true); // extra length\n      v.setUint16(32, 0, true); // comment length\n      v.setUint16(34, 0, true); // disk number start\n      v.setUint16(36, 0, true); // internal attributes\n      v.setUint32(38, 0, true); // external attributes\n      v.setUint32(42, e.offset, true); // local header offset\n      rec.set(e.nameBytes, 46);\n      this.push(rec);\n    }\n\n    const centralSize = this.offset - centralStart;\n\n    // End of central directory record (22 bytes, no comment).\n    const eocd = new Uint8Array(22);\n    const v = new DataView(eocd.buffer);\n    v.setUint32(0, EOCD_SIG, true);\n    v.setUint16(4, 0, true); // disk number\n    v.setUint16(6, 0, true); // disk with central dir\n    v.setUint16(8, this.entries.length, true); // entries on this disk\n    v.setUint16(10, this.entries.length, true); // total entries\n    v.setUint32(12, centralSize, true);\n    v.setUint32(16, centralStart, true);\n    v.setUint16(20, 0, true); // comment length\n    this.push(eocd);\n\n    return this.concat();\n  }\n\n  private push(chunk: Uint8Array): void {\n    this.chunks.push(chunk);\n    this.offset += chunk.length;\n  }\n\n  private concat(): Uint8Array {\n    const out = new Uint8Array(this.offset);\n    let pos = 0;\n    for (const c of this.chunks) {\n      out.set(c, pos);\n      pos += c.length;\n    }\n    return out;\n  }\n}\n","import { ExportCell, ExportCellStyle, ExportData, ExportFormat, ExportOptions } from '../types';\nimport { ZipWriter } from '../zip/zip';\n\n/**\n * Zero-dependency XLSX (SpreadsheetML) writer. An .xlsx is an OPC package — a\n * ZIP of XML parts — which {@link ZipWriter} builds by hand. We emit the minimal\n * set of parts Excel/LibreOffice open without repair, use inline strings (so no\n * sharedStrings part is needed), and type each cell (number / boolean / date\n * serial / string). Column groups become merged header cells; column widths, a\n * bold header style, and per-cell styling from a `cellCallback` (bold, italic,\n * color, background, alignment) are all supported by building `styles.xml`\n * dynamically.\n */\nexport const xlsxFormat: ExportFormat = {\n  id: 'xlsx',\n  extension: 'xlsx',\n  mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n\n  render(data: ExportData, options: ExportOptions): Uint8Array {\n    const styles = new StyleCollector();\n    const sheet = sheetXml(data, options, styles);\n    const zip = new ZipWriter();\n    zip.add('[Content_Types].xml', CONTENT_TYPES);\n    zip.add('_rels/.rels', ROOT_RELS);\n    zip.add('xl/workbook.xml', WORKBOOK);\n    zip.add('xl/_rels/workbook.xml.rels', WORKBOOK_RELS);\n    zip.add('xl/styles.xml', styles.build());\n    zip.add('xl/worksheets/sheet1.xml', sheet);\n    return zip.build();\n  },\n};\n\n// ---- Static package parts ---------------------------------------------------\n\nconst CONTENT_TYPES = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n<Default Extension=\"xml\" ContentType=\"application/xml\"/>\n<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>\n<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>\n<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>\n</Types>`;\n\nconst ROOT_RELS = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>\n</Relationships>`;\n\nconst WORKBOOK = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n<sheets><sheet name=\"Sheet1\" sheetId=\"1\" r:id=\"rId1\"/></sheets>\n</workbook>`;\n\nconst WORKBOOK_RELS = `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n<Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>\n<Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>`;\n\n// ---- Dynamic styles ---------------------------------------------------------\n\n/** A fully-resolved cell format (base + optional callback style). */\ninterface XfKey {\n  bold: boolean;\n  italic: boolean;\n  color?: string; // hex without '#'\n  fill?: string; // hex without '#'\n  align?: 'left' | 'center' | 'right';\n  date: boolean;\n}\n\n/**\n * Interns fonts, fills, and cell formats (`<xf>`), deduplicating them, and emits\n * a valid `styles.xml`. Callers request a style index for a resolved\n * {@link XfKey}; identical requests reuse the same index.\n */\nclass StyleCollector {\n  private fonts: string[] = ['<font><sz val=\"11\"/><name val=\"Calibri\"/></font>'];\n  private fills: string[] = [\n    '<fill><patternFill patternType=\"none\"/></fill>',\n    '<fill><patternFill patternType=\"gray125\"/></fill>',\n  ];\n  private xfs: string[] = ['<xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>'];\n  private fontCache = new Map<string, number>();\n  private fillCache = new Map<string, number>();\n  private xfCache = new Map<string, number>();\n\n  /** Get (or create) a cell-format index for a resolved style. */\n  style(key: XfKey): number {\n    const id = JSON.stringify(key);\n    const cached = this.xfCache.get(id);\n    if (cached != null) return cached;\n\n    const fontId = this.font(key);\n    const fillId = key.fill ? this.fill(key.fill) : 0;\n    const numFmt = key.date ? 14 : 0;\n\n    let xf = `<xf numFmtId=\"${numFmt}\" fontId=\"${fontId}\" fillId=\"${fillId}\" borderId=\"0\" xfId=\"0\"`;\n    if (fontId) xf += ' applyFont=\"1\"';\n    if (fillId) xf += ' applyFill=\"1\"';\n    if (key.date) xf += ' applyNumberFormat=\"1\"';\n    if (key.align) {\n      xf += ` applyAlignment=\"1\"><alignment horizontal=\"${key.align}\"/></xf>`;\n    } else {\n      xf += '/>';\n    }\n    const index = this.xfs.length;\n    this.xfs.push(xf);\n    this.xfCache.set(id, index);\n    return index;\n  }\n\n  private font(key: XfKey): number {\n    if (!key.bold && !key.italic && !key.color) return 0;\n    const id = `${key.bold}|${key.italic}|${key.color ?? ''}`;\n    const cached = this.fontCache.get(id);\n    if (cached != null) return cached;\n    let font = '<font>';\n    if (key.bold) font += '<b/>';\n    if (key.italic) font += '<i/>';\n    font += '<sz val=\"11\"/>';\n    if (key.color) font += `<color rgb=\"FF${key.color}\"/>`;\n    font += '<name val=\"Calibri\"/></font>';\n    const index = this.fonts.length;\n    this.fonts.push(font);\n    this.fontCache.set(id, index);\n    return index;\n  }\n\n  private fill(hex: string): number {\n    const cached = this.fillCache.get(hex);\n    if (cached != null) return cached;\n    const fill = `<fill><patternFill patternType=\"solid\"><fgColor rgb=\"FF${hex}\"/><bgColor indexed=\"64\"/></patternFill></fill>`;\n    const index = this.fills.length;\n    this.fills.push(fill);\n    this.fillCache.set(hex, index);\n    return index;\n  }\n\n  build(): string {\n    return (\n      '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n      '<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">' +\n      `<fonts count=\"${this.fonts.length}\">${this.fonts.join('')}</fonts>` +\n      `<fills count=\"${this.fills.length}\">${this.fills.join('')}</fills>` +\n      '<borders count=\"1\"><border><left/><right/><top/><bottom/><diagonal/></border></borders>' +\n      '<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/></cellStyleXfs>' +\n      `<cellXfs count=\"${this.xfs.length}\">${this.xfs.join('')}</cellXfs>` +\n      '<cellStyles count=\"1\"><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"/></cellStyles>' +\n      '</styleSheet>'\n    );\n  }\n}\n\n// Turn an ExportCellStyle + base flags into an interned style index.\nfunction styleIndex(\n  styles: StyleCollector,\n  base: { bold?: boolean; date?: boolean },\n  s: ExportCellStyle | undefined,\n): number {\n  const key: XfKey = {\n    bold: (base.bold ?? false) || (s?.bold ?? false),\n    italic: s?.italic ?? false,\n    color: hex(s?.color),\n    fill: hex(s?.background),\n    align: s?.align,\n    date: base.date ?? false,\n  };\n  if (!key.bold && !key.italic && !key.color && !key.fill && !key.align && !key.date) return 0;\n  return styles.style(key);\n}\n\n// Normalize a CSS color to a 6-hex-digit uppercase string, or undefined.\nfunction hex(color: string | undefined): string | undefined {\n  if (!color) return undefined;\n  let c = color.trim().replace(/^#/, '');\n  const named: Record<string, string> = {\n    red: 'FF0000',\n    green: '008000',\n    blue: '0000FF',\n    black: '000000',\n    white: 'FFFFFF',\n    orange: 'FFA500',\n    gray: '808080',\n    grey: '808080',\n  };\n  if (named[c.toLowerCase()]) return named[c.toLowerCase()];\n  if (c.length === 3) c = c.replace(/(.)/g, '$1$1');\n  return /^[0-9a-fA-F]{6}$/.test(c) ? c.toUpperCase() : undefined;\n}\n\n// ---- Worksheet --------------------------------------------------------------\n\nfunction sheetXml(data: ExportData, options: ExportOptions, styles: StyleCollector): string {\n  const includeHeaders = options.includeHeaders ?? true;\n  const headerRows = data.headerRows ?? 0;\n  const headerStyle = styles.style({ bold: true, italic: false, date: false });\n  const outline = data.outline ?? false;\n  const parts: string[] = [];\n  parts.push('<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>');\n  parts.push('<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">');\n\n  // sheetPr with outline summary-above so group headers sit above their rows,\n  // matching how the grid renders grouping.\n  if (outline) {\n    parts.push('<sheetPr><outlinePr summaryBelow=\"0\" summaryRight=\"0\"/></sheetPr>');\n  }\n  if (outline && data.outlineLevels) {\n    parts.push(`<sheetFormatPr defaultRowHeight=\"15\" outlineLevelRow=\"${data.outlineLevels}\"/>`);\n  }\n\n  parts.push(colsXml(data));\n\n  parts.push('<sheetData>');\n  let rowNum = 1;\n\n  if (includeHeaders && headerRows > 0 && data.headerGroups?.length) {\n    for (let hr = 0; hr < headerRows; hr++) {\n      const cells: string[] = [];\n      for (const g of data.headerGroups) {\n        if (g.row !== hr) continue;\n        cells.push(headerCellXml(colLetter(g.startCol) + rowNum, headerStyle, g.header));\n      }\n      parts.push(`<row r=\"${rowNum}\">${cells.join('')}</row>`);\n      rowNum++;\n    }\n  }\n\n  if (includeHeaders) {\n    const cells = data.columns.map((c, i) =>\n      headerCellXml(colLetter(i) + rowNum, headerStyle, c.header),\n    );\n    parts.push(`<row r=\"${rowNum}\">${cells.join('')}</row>`);\n    rowNum++;\n  }\n  // The header row that carries the AutoFilter (last header row).\n  const filterHeaderRow = includeHeaders ? rowNum - 1 : 0;\n\n  for (const row of data.rows) {\n    const cells = row.cells.map((cell, i) => bodyCellXml(colLetter(i) + rowNum, cell, styles));\n    // Excel row outlining: outline level for grouped data rows (group-header\n    // summary rows stay at level 0 so they head their section).\n    let attrs =\n      outline && row.kind === 'data' && row.level ? ` outlineLevel=\"${row.level}\"` : '';\n    // Rows filtered out by the active AutoFilter are hidden but still present.\n    if (row.hidden) attrs += ' hidden=\"1\"';\n    parts.push(`<row r=\"${rowNum}\"${attrs}>${cells.join('')}</row>`);\n    rowNum++;\n  }\n\n  const dataStartRow =\n    1 +\n    (includeHeaders && headerRows > 0 && data.headerGroups?.length ? headerRows : 0) +\n    (includeHeaders ? 1 : 0);\n  parts.push('</sheetData>');\n  // Schema order: autoFilter precedes mergeCells.\n  parts.push(autoFilterXml(data, includeHeaders, filterHeaderRow, rowNum - 1));\n  parts.push(mergeXml(data, includeHeaders, dataStartRow));\n  parts.push('</worksheet>');\n  return parts.join('');\n}\n\nfunction colsXml(data: ExportData): string {\n  const cols = data.columns\n    .map((c, i) => {\n      const chars = Math.min(80, Math.max(6, Math.round(c.width / 7)));\n      return `<col min=\"${i + 1}\" max=\"${i + 1}\" width=\"${chars}\" customWidth=\"1\"/>`;\n    })\n    .join('');\n  return `<cols>${cols}</cols>`;\n}\n\nfunction bodyCellXml(ref: string, cell: ExportCell, styles: StyleCollector): string {\n  if (cell.value == null && (cell.text === '' || cell.text == null)) {\n    const s = styleIndex(styles, {}, cell.style);\n    return s ? `<c r=\"${ref}\" s=\"${s}\"/>` : `<c r=\"${ref}\"/>`;\n  }\n  switch (cell.type) {\n    case 'Number': {\n      const n = Number(cell.value);\n      if (!Number.isFinite(n)) return inlineStr(ref, cell.text, styleIndex(styles, {}, cell.style));\n      return `<c r=\"${ref}\"${sAttr(styleIndex(styles, {}, cell.style))}><v>${n}</v></c>`;\n    }\n    case 'Boolean': {\n      if (typeof cell.value !== 'boolean')\n        return inlineStr(ref, cell.text, styleIndex(styles, {}, cell.style));\n      return `<c r=\"${ref}\" t=\"b\"${sAttr(styleIndex(styles, {}, cell.style))}><v>${cell.value ? 1 : 0}</v></c>`;\n    }\n    case 'Date': {\n      const serial = toExcelSerial(cell.value);\n      const s = styleIndex(styles, { date: true }, cell.style);\n      if (serial == null) return inlineStr(ref, cell.text, styleIndex(styles, {}, cell.style));\n      return `<c r=\"${ref}\" s=\"${s}\"><v>${serial}</v></c>`;\n    }\n    default:\n      return cell.text === ''\n        ? `<c r=\"${ref}\"${sAttr(styleIndex(styles, {}, cell.style))}/>`\n        : inlineStr(ref, cell.text, styleIndex(styles, {}, cell.style));\n  }\n}\n\nfunction headerCellXml(ref: string, style: number, text: string): string {\n  return `<c r=\"${ref}\"${sAttr(style)} t=\"inlineStr\"><is><t xml:space=\"preserve\">${escapeXml(text)}</t></is></c>`;\n}\n\nfunction inlineStr(ref: string, text: string, style: number): string {\n  return `<c r=\"${ref}\"${sAttr(style)} t=\"inlineStr\"><is><t xml:space=\"preserve\">${escapeXml(text)}</t></is></c>`;\n}\n\nfunction sAttr(style: number): string {\n  return style ? ` s=\"${style}\"` : '';\n}\n\n// Excel dates are serial days since 1899-12-30 (the 1900 date system, including\n// the historical leap-year bug baked into the epoch offset).\nfunction toExcelSerial(value: unknown): number | null {\n  const d = value instanceof Date ? value : typeof value === 'string' ? new Date(value) : null;\n  if (!d || Number.isNaN(d.getTime())) return null;\n  const epoch = Date.UTC(1899, 11, 30);\n  const utc = Date.UTC(\n    d.getFullYear(),\n    d.getMonth(),\n    d.getDate(),\n    d.getHours(),\n    d.getMinutes(),\n    d.getSeconds(),\n  );\n  return (utc - epoch) / 86400000;\n}\n\nfunction autoFilterXml(\n  data: ExportData,\n  includeHeaders: boolean,\n  headerRow: number,\n  lastRow: number,\n): string {\n  // AutoFilter needs a header row to anchor the dropdowns.\n  if (!data.autoFilter || !includeHeaders || data.columns.length === 0) return '';\n  const left = colLetter(0);\n  const right = colLetter(data.columns.length - 1);\n  const bottom = Math.max(headerRow, lastRow);\n  const ref = `${left}${headerRow}:${right}${bottom}`;\n\n  // Per-column value filters (the checkbox list). colId is 0-based within the\n  // AutoFilter range, which starts at column 0 here.\n  const inner = (data.filters ?? [])\n    .filter((f) => f.values.length > 0)\n    .map((f) => {\n      const filters = f.values.map((v) => `<filter val=\"${escapeXml(v)}\"/>`).join('');\n      return `<filterColumn colId=\"${f.col}\"><filters>${filters}</filters></filterColumn>`;\n    })\n    .join('');\n\n  return inner ? `<autoFilter ref=\"${ref}\">${inner}</autoFilter>` : `<autoFilter ref=\"${ref}\"/>`;\n}\n\nfunction mergeXml(data: ExportData, includeHeaders: boolean, dataStartRow: number): string {\n  const cells: string[] = [];\n\n  // Header-group band merges (only when headers are emitted).\n  if (includeHeaders && data.headerGroups?.length) {\n    for (const g of data.headerGroups) {\n      const top = g.row + 1;\n      const bottom = g.row + g.rowSpan;\n      const left = colLetter(g.startCol);\n      const right = colLetter(g.endCol);\n      if (left === right && top === bottom) continue;\n      cells.push(`<mergeCell ref=\"${left}${top}:${right}${bottom}\"/>`);\n    }\n  }\n\n  // Data-region merges (from a merge manager), offset by the header rows.\n  if (data.merges?.length) {\n    for (const m of data.merges) {\n      const top = dataStartRow + m.topRow;\n      const bottom = dataStartRow + m.bottomRow;\n      const left = colLetter(m.leftCol);\n      const right = colLetter(m.rightCol);\n      if (left === right && top === bottom) continue;\n      cells.push(`<mergeCell ref=\"${left}${top}:${right}${bottom}\"/>`);\n    }\n  }\n\n  if (cells.length === 0) return '';\n  return `<mergeCells count=\"${cells.length}\">${cells.join('')}</mergeCells>`;\n}\n\nfunction colLetter(index: number): string {\n  let n = index;\n  let s = '';\n  do {\n    s = String.fromCharCode(65 + (n % 26)) + s;\n    n = Math.floor(n / 26) - 1;\n  } while (n >= 0);\n  return s;\n}\n\nfunction escapeXml(text: string): string {\n  return text\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;');\n}\n","import { ExportData, ExportFormat, ExportOptions, ExportRow } from '../types';\n\n/**\n * Zero-dependency PDF writer that lays the export out as a paginated table with\n * gridlines, a bold-ish header row, and one of the 14 standard fonts (Helvetica)\n * so no font file needs embedding. The PDF object model (catalog → pages →\n * page(s) → content stream) is assembled by hand with a correct xref table.\n *\n * Coordinate system: origin is bottom-left, y increases upward.\n */\nexport const pdfFormat: ExportFormat = {\n  id: 'pdf',\n  extension: 'pdf',\n  mimeType: 'application/pdf',\n\n  render(data: ExportData, options: ExportOptions): Uint8Array {\n    return new PdfDoc(data, options).build();\n  },\n};\n\n// US Letter in points (72 per inch).\nconst PAGE = { portrait: { w: 612, h: 792 }, landscape: { w: 792, h: 612 } };\nconst MARGIN = 36;\nconst CHAR_W = 0.5; // Helvetica avg glyph width ≈ 0.5em, for width estimates\n\nclass PdfDoc {\n  private page: { w: number; h: number };\n  private fontSize: number;\n  private rowH: number;\n  private includeHeaders: boolean;\n  private colX: number[] = [];\n  private tableWidth: number;\n\n  constructor(\n    private data: ExportData,\n    options: ExportOptions,\n  ) {\n    const pdf = options.pdf ?? {};\n    this.page = PAGE[pdf.orientation ?? 'landscape'];\n    this.fontSize = pdf.fontSize ?? 9;\n    this.rowH = this.fontSize + 6;\n    this.includeHeaders = options.includeHeaders ?? true;\n\n    // Scale column pixel widths to fit the printable width.\n    const printable = this.page.w - MARGIN * 2;\n    const totalPx = data.columns.reduce((s, c) => s + c.width, 0) || 1;\n    const scale = printable / totalPx;\n    let x = MARGIN;\n    this.colX = [x];\n    for (const c of data.columns) {\n      x += c.width * scale;\n      this.colX.push(x);\n    }\n    this.tableWidth = x - MARGIN;\n  }\n\n  build(): Uint8Array {\n    const pages = this.paginate();\n    const streams = pages.map((rows, i) => this.pageStream(rows, i === 0));\n\n    // Object layout: 1 catalog, 2 pages, 3 font, then per-page [pageObj, contentObj].\n    const pageObjIds: number[] = [];\n    const objects: string[] = [];\n    const firstPageObj = 5;\n    for (let i = 0; i < pages.length; i++) pageObjIds.push(firstPageObj + i * 2);\n\n    objects[1] = `<< /Type /Catalog /Pages 2 0 R >>`;\n    objects[2] = `<< /Type /Pages /Kids [${pageObjIds.map((id) => `${id} 0 R`).join(' ')}] /Count ${pages.length} >>`;\n    objects[3] = `<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>`;\n    objects[4] = `<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold >>`;\n\n    for (let i = 0; i < pages.length; i++) {\n      const pageId = firstPageObj + i * 2;\n      const contentId = pageId + 1;\n      objects[pageId] =\n        `<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${this.page.w} ${this.page.h}] ` +\n        `/Resources << /Font << /F1 3 0 R /F2 4 0 R >> >> /Contents ${contentId} 0 R >>`;\n      objects[contentId] = `<< /Length ${byteLen(streams[i])} >>\\nstream\\n${streams[i]}\\nendstream`;\n    }\n\n    return this.serialize(objects);\n  }\n\n  // Split rows into pages by available vertical space.\n  private paginate(): ExportRow[][] {\n    const top = this.page.h - MARGIN - (this.data.title ? this.rowH + 6 : 0);\n    const bottom = MARGIN;\n    const headerH = this.includeHeaders ? this.rowH : 0;\n    const rowsPerPage = Math.max(1, Math.floor((top - bottom - headerH) / this.rowH));\n    const pages: ExportRow[][] = [];\n    for (let i = 0; i < this.data.rows.length; i += rowsPerPage) {\n      pages.push(this.data.rows.slice(i, i + rowsPerPage));\n    }\n    return pages.length ? pages : [[]];\n  }\n\n  private pageStream(rows: ExportRow[], firstPage: boolean): string {\n    const ops: string[] = [];\n    let y = this.page.h - MARGIN;\n\n    if (firstPage && this.data.title) {\n      ops.push(text(MARGIN, y - this.fontSize - 2, this.data.title, this.fontSize + 3));\n      y -= this.rowH + 6;\n    }\n\n    const tableTop = y;\n\n    if (this.includeHeaders) {\n      ops.push(`0.93 0.95 0.98 rg`);\n      ops.push(rect(MARGIN, y - this.rowH, this.tableWidth, this.rowH, true));\n      ops.push(`0 0 0 rg`);\n      this.data.columns.forEach((c, i) => {\n        ops.push(this.cellText(c.header, i, y, c.align, { bold: true }));\n      });\n      y -= this.rowH;\n    }\n\n    for (const row of rows) {\n      if (row.kind === 'group') {\n        ops.push(`0.90 0.92 0.97 rg`);\n        ops.push(rect(MARGIN, y - this.rowH, this.tableWidth, this.rowH, true));\n        ops.push(`0 0 0 rg`);\n      }\n      // Per-cell backgrounds first, so text draws on top.\n      row.cells.forEach((cell, i) => {\n        if (i >= this.data.columns.length) return;\n        const bg = cell.style?.background && rgb(cell.style.background);\n        if (bg) {\n          ops.push(`${bg} rg`);\n          ops.push(rect(this.colX[i], y - this.rowH, this.colX[i + 1] - this.colX[i], this.rowH, true));\n          ops.push(`0 0 0 rg`);\n        }\n      });\n      row.cells.forEach((cell, i) => {\n        if (i >= this.data.columns.length) return;\n        ops.push(this.cellText(cell.text, i, y, cell.style?.align ?? cell.align, cell.style));\n      });\n      y -= this.rowH;\n    }\n\n    // Gridlines.\n    ops.push(`0.8 0.8 0.8 RG`);\n    ops.push(`0.5 w`);\n    for (let i = 0; i <= this.data.columns.length; i++) {\n      ops.push(line(this.colX[i], tableTop, this.colX[i], y));\n    }\n    for (let ry = tableTop, r = 0; ry >= y - 0.1; ry -= this.rowH, r++) {\n      ops.push(line(MARGIN, ry, MARGIN + this.tableWidth, ry));\n    }\n\n    return ops.join('\\n');\n  }\n\n  private cellText(\n    value: string,\n    col: number,\n    y: number,\n    align: string,\n    style?: { bold?: boolean; italic?: boolean; color?: string },\n  ): string {\n    const left = this.colX[col];\n    const right = this.colX[col + 1];\n    const cellW = right - left - 8;\n    const clipped = this.clip(value, cellW);\n    const textW = clipped.length * this.fontSize * CHAR_W;\n    let x = left + 4;\n    if (align === 'right') x = right - 4 - textW;\n    else if (align === 'center') x = left + (right - left - textW) / 2;\n\n    const font = style?.bold ? 'F2' : 'F1';\n    const color = style?.color && rgb(style.color);\n    const drawn = text(x, y - this.fontSize - 3, clipped, this.fontSize, font);\n    if (!color) return drawn;\n    // Set fill color, draw, reset to black.\n    return `${color} rg\\n${drawn}\\n0 0 0 rg`;\n  }\n\n  private clip(value: string, maxWidth: number): string {\n    const per = this.fontSize * CHAR_W;\n    const max = Math.max(1, Math.floor(maxWidth / per));\n    if (value.length <= max) return value;\n    return value.slice(0, Math.max(1, max - 1)) + '…';\n  }\n\n  // Emit the object table + xref + trailer with correct byte offsets.\n  private serialize(objects: string[]): Uint8Array {\n    const count = objects.length; // objects[0] unused; ids are 1..count-1\n    let out = '%PDF-1.4\\n%\\xFF\\xFF\\xFF\\xFF\\n';\n    const offsets: number[] = [];\n    for (let id = 1; id < count; id++) {\n      offsets[id] = byteLen(out);\n      out += `${id} 0 obj\\n${objects[id]}\\nendobj\\n`;\n    }\n    const xrefStart = byteLen(out);\n    const total = count; // entries 0..count-1\n    out += `xref\\n0 ${total}\\n`;\n    out += `0000000000 65535 f \\n`;\n    for (let id = 1; id < count; id++) {\n      out += `${String(offsets[id]).padStart(10, '0')} 00000 n \\n`;\n    }\n    out += `trailer\\n<< /Size ${total} /Root 1 0 R >>\\n`;\n    out += `startxref\\n${xrefStart}\\n%%EOF`;\n    return latin1(out);\n  }\n}\n\n// ---- PDF content-stream helpers ---------------------------------------------\n\nfunction text(x: number, y: number, value: string, size: number, font = 'F1'): string {\n  return `BT /${font} ${size} Tf ${fixed(x)} ${fixed(y)} Td (${escapePdf(value)}) Tj ET`;\n}\n\n// Convert a CSS color to a PDF \"r g b\" fill triple (0..1), or '' if unknown.\nfunction rgb(color: string): string {\n  const named: Record<string, [number, number, number]> = {\n    red: [204, 0, 0],\n    green: [0, 128, 0],\n    blue: [0, 0, 204],\n    black: [0, 0, 0],\n    white: [255, 255, 255],\n    orange: [255, 165, 0],\n    gray: [128, 128, 128],\n    grey: [128, 128, 128],\n  };\n  let c = color.trim().replace(/^#/, '');\n  let r: number, g: number, b: number;\n  if (named[c.toLowerCase()]) {\n    [r, g, b] = named[c.toLowerCase()];\n  } else {\n    if (c.length === 3) c = c.replace(/(.)/g, '$1$1');\n    if (!/^[0-9a-fA-F]{6}$/.test(c)) return '';\n    r = parseInt(c.slice(0, 2), 16);\n    g = parseInt(c.slice(2, 4), 16);\n    b = parseInt(c.slice(4, 6), 16);\n  }\n  return `${(r / 255).toFixed(3)} ${(g / 255).toFixed(3)} ${(b / 255).toFixed(3)}`;\n}\n\nfunction rect(x: number, y: number, w: number, h: number, fill: boolean): string {\n  return `${fixed(x)} ${fixed(y)} ${fixed(w)} ${fixed(h)} re ${fill ? 'f' : 'S'}`;\n}\n\nfunction line(x1: number, y1: number, x2: number, y2: number): string {\n  return `${fixed(x1)} ${fixed(y1)} m ${fixed(x2)} ${fixed(y2)} l S`;\n}\n\nfunction fixed(n: number): string {\n  return n.toFixed(2);\n}\n\nfunction escapePdf(value: string): string {\n  // Escape the three special chars; drop non-Latin1 so the standard font renders.\n  return value\n    .replace(/\\\\/g, '\\\\\\\\')\n    .replace(/\\(/g, '\\\\(')\n    .replace(/\\)/g, '\\\\)')\n    .replace(/[^\\x20-\\x7e]/g, '?');\n}\n\n// Byte length of a latin1/binary string.\nfunction byteLen(s: string): number {\n  return s.length; // all chars are < 256 (latin1) by construction\n}\n\nfunction latin1(s: string): Uint8Array {\n  const out = new Uint8Array(s.length);\n  for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i) & 0xff;\n  return out;\n}\n","import { ExportFormat } from './types';\nimport { csvFormat } from './formats/csv';\nimport { xlsxFormat } from './formats/xlsx';\nimport { pdfFormat } from './formats/pdf';\n\n/**\n * Registry of output formats. New formats are added by registering an\n * {@link ExportFormat}; the manager looks them up by id. Ships csv/xlsx/pdf.\n */\nexport class ExportRegistry {\n  private formats = new Map<string, ExportFormat>();\n\n  constructor() {\n    this.register(csvFormat);\n    this.register(xlsxFormat);\n    this.register(pdfFormat);\n  }\n\n  register(format: ExportFormat): void {\n    this.formats.set(format.id, format);\n  }\n\n  get(id: string): ExportFormat | undefined {\n    return this.formats.get(id);\n  }\n\n  ids(): string[] {\n    return [...this.formats.keys()];\n  }\n}\n","import { Column } from '../models/Column';\nimport { computeAggregate } from '../data/aggregate';\nimport { CollectionViewGroup } from '../data/CollectionViewGroup';\nimport {\n  ExportCell,\n  ExportColumn,\n  ExportData,\n  ExportHeaderGroup,\n  ExportMerge,\n  ExportOptions,\n  ExportRow,\n} from './types';\n\n/** The minimal row-source the builder reads — a subset of {@link DataView}. */\nexport interface ExportSource {\n  /** Number of display rows (data rows plus visible group headers). */\n  readonly length: number;\n  /** Whether the source is grouped (has group-header rows). */\n  readonly grouped?: boolean;\n  item(index: number): Record<string, unknown> | undefined;\n  rowType(index: number): 'group' | 'data';\n  groupRow(index: number): { group: CollectionViewGroup; level: number } | null;\n}\n\n/** A resolved column group band for multi-level header export. */\nexport interface ExportColumnGroupSpan {\n  header: string;\n  startCol: number;\n  endCol: number;\n  row: number;\n  rowSpan: number;\n}\n\nexport interface BuildExportInput {\n  /** The columns to export, already ordered/filtered. */\n  columns: Column[];\n  source: ExportSource;\n  /** Rectangle to limit rows/cols to, or null for the whole grid. */\n  selection?: { topRow: number; bottomRow: number; leftCol: number; rightCol: number } | null;\n  /** Optional multi-level header bands (from grid column groups). */\n  headerGroups?: ExportColumnGroupSpan[];\n  headerRows?: number;\n  /**\n   * Optional cell-merge lookup in grid coordinates: given a (displayRow,\n   * gridCol) it returns the span that cell belongs to, or null. Used to emit\n   * merged cells in the export. `gridColOf` maps an export-column index back to\n   * the grid-column index the lookup expects.\n   */\n  merge?: (displayRow: number, gridCol: number) => ExportMergeRange | null;\n  /** Map an export-column index to its grid-column index (identity by default). */\n  gridColOf?: (exportCol: number) => number;\n  /** Whether the grid has column filtering enabled (drives AutoFilter default). */\n  filterable?: boolean;\n  /** Active value-filters (export-column index → passing display values). */\n  filters?: { col: number; values: string[] }[];\n}\n\n/** A merge span in grid coordinates, as returned by the grid's merge manager. */\nexport interface ExportMergeRange {\n  topRow: number;\n  bottomRow: number;\n  leftCol: number;\n  rightCol: number;\n}\n\n/**\n * Turn grid columns + a row source into the format-agnostic {@link ExportData}.\n * Pure and grid-free: each cell carries its raw value, its formatted text, its\n * type, and alignment, so any writer can render it. Group-header rows (with\n * aggregates) are included when `options.includeGroups` is set and the source\n * is grouped.\n */\nexport function buildExportData(input: BuildExportInput, options: ExportOptions): ExportData {\n  const ctx = prepare(input, options);\n  for (let r = ctx.firstRow; r <= ctx.lastRow; r++) {\n    const row = ctx.buildRow(r);\n    if (row) ctx.rows.push(row);\n  }\n  return ctx.finish();\n}\n\n/**\n * Async variant of {@link buildExportData}: builds rows in chunks, yielding to\n * the event loop between chunks so a large export doesn't freeze the page.\n * Reports progress (0..1) and honors an AbortSignal. Rejects with an\n * `AbortError` if the signal fires.\n */\nexport async function buildExportDataAsync(\n  input: BuildExportInput,\n  options: ExportOptions,\n): Promise<ExportData> {\n  const ctx = prepare(input, options);\n  const chunk = Math.max(1, options.chunkSize ?? 2000);\n  const total = Math.max(1, ctx.lastRow - ctx.firstRow + 1);\n  let done = 0;\n\n  for (let r = ctx.firstRow; r <= ctx.lastRow; r++) {\n    if (options.signal?.aborted) throw abortError();\n    const row = ctx.buildRow(r);\n    if (row) ctx.rows.push(row);\n    done++;\n    if (done % chunk === 0) {\n      options.onProgress?.(Math.min(1, done / total));\n      await yieldToEventLoop();\n      if (options.signal?.aborted) throw abortError();\n    }\n  }\n  options.onProgress?.(1);\n  return ctx.finish();\n}\n\n// Shared setup + per-row builder used by both the sync and async paths.\nfunction prepare(input: BuildExportInput, options: ExportOptions) {\n  const { columns, source, selection } = input;\n  // Detect whether the source is grouped by probing for any group row.\n  const grouped = hasGroupRows(source);\n  // Outline grouping (native Excel row grouping) defaults on when grouped; it\n  // implies emitting the group-header rows as summary rows.\n  const outline = grouped && (options.outlineGroups ?? true);\n  const includeGroups = outline || (options.includeGroups ?? false);\n  const cellCallback = options.cellCallback;\n\n  const exportColumns: ExportColumn[] = columns.map((c) => ({\n    header: c.header,\n    key: c.binding,\n    type: c.dataType,\n    align: c.align,\n    width: c.width,\n  }));\n\n  // Apply the header callback once, up front.\n  if (options.headerCallback) {\n    exportColumns.forEach((column, col) => {\n      const out = options.headerCallback!({ column, col, text: column.header });\n      column.header = typeof out === 'string' ? out : column.header;\n    });\n  }\n\n  const firstRow = selection ? Math.max(0, selection.topRow) : 0;\n  const lastRow = selection ? Math.min(source.length - 1, selection.bottomRow) : source.length - 1;\n  const rows: ExportRow[] = [];\n  // Source display-row index for each pushed export row (data rows only carry a\n  // meaningful value; group rows record -1). Used to resolve merge spans.\n  const displayRows: number[] = [];\n  // Running group depth: a data row sits `currentDepth` levels deep (the level\n  // of the most recent group header + 1). Drives Excel row outlining.\n  let currentDepth = 0;\n  let maxOutline = 0;\n\n  const runCellCallbacks = (\n    row: ExportRow,\n    rowIndex: number,\n    item: Record<string, unknown> | null,\n  ): void => {\n    if (!cellCallback) return;\n    row.cells.forEach((cell, col) => {\n      cellCallback({\n        cell,\n        column: exportColumns[col],\n        col,\n        row: rowIndex,\n        rowKind: row.kind,\n        item,\n      });\n    });\n  };\n\n  const buildRow = (r: number): ExportRow | null => {\n    if (source.rowType(r) === 'group') {\n      if (!includeGroups) return null;\n      const gr = source.groupRow(r);\n      if (!gr) return null;\n      const row = groupRow(gr.group, gr.level, columns);\n      // Data rows following this header sit one level deeper.\n      currentDepth = gr.level + 1;\n      if (currentDepth > maxOutline) maxOutline = currentDepth;\n      runCellCallbacks(row, r, null);\n      displayRows.push(-1);\n      return row;\n    }\n    const item = source.item(r);\n    if (!item) return null;\n    const row: ExportRow = {\n      kind: 'data',\n      cells: columns.map((c) => dataCell(c, item)),\n      level: outline && currentDepth > 0 ? currentDepth : undefined,\n    };\n    runCellCallbacks(row, r, item);\n    displayRows.push(r);\n    return row;\n  };\n\n  const finish = (): ExportData => {\n    const merges = input.merge ? collectMerges(rows, displayRows, input) : undefined;\n    // AutoFilter defaults to on when the caller enabled filtering support.\n    const autoFilter = options.autoFilter ?? (input.filterable ?? false);\n\n    // Reflect active value-filters: hide non-matching data rows so Excel opens\n    // showing the filtered result, while the AutoFilter keeps the criteria.\n    const filters = input.filters?.length ? input.filters : undefined;\n    if (filters) {\n      const sets = filters.map((f) => ({ col: f.col, set: new Set(f.values) }));\n      for (const row of rows) {\n        if (row.kind !== 'data') continue;\n        const passes = sets.every(({ col, set }) => set.has(row.cells[col]?.text ?? ''));\n        if (!passes) row.hidden = true;\n      }\n    }\n\n    return {\n      columns: exportColumns,\n      rows,\n      headerGroups: input.headerGroups as ExportHeaderGroup[] | undefined,\n      headerRows: input.headerRows,\n      merges,\n      autoFilter,\n      filters,\n      outline: outline && maxOutline > 0,\n      outlineLevels: maxOutline,\n      title: options.title,\n    };\n  };\n\n  return { firstRow, lastRow, rows, buildRow, finish };\n}\n\n// Cheap probe: does the source have any group rows? (grouped view)\nfunction hasGroupRows(source: ExportSource): boolean {\n  const n = Math.min(source.length, 500);\n  for (let i = 0; i < n; i++) if (source.rowType(i) === 'group') return true;\n  return false;\n}\n\n/**\n * Resolve merge spans (in grid coordinates) into export-coordinate spans, and\n * blank the non-origin cells of each span so writers don't repeat the value.\n * Only spans that cover ≥2 exported cells are emitted; a span partly outside the\n * export (e.g. clipped by a selection or reordered columns) is truncated to the\n * exported portion.\n */\nfunction collectMerges(\n  rows: ExportRow[],\n  displayRows: number[],\n  input: BuildExportInput,\n): ExportMerge[] {\n  const merge = input.merge!;\n  const gridColOf = input.gridColOf ?? ((c: number) => c);\n  const colCount = input.columns.length;\n\n  // Map a grid display-row → export-row index (data rows only).\n  const displayToExport = new Map<number, number>();\n  displayRows.forEach((d, exportRow) => {\n    if (d >= 0) displayToExport.set(d, exportRow);\n  });\n\n  const merges: ExportMerge[] = [];\n  const seen = new Set<string>();\n\n  for (let exportRow = 0; exportRow < rows.length; exportRow++) {\n    if (rows[exportRow].kind !== 'data') continue;\n    const displayRow = displayRows[exportRow];\n    for (let exportCol = 0; exportCol < colCount; exportCol++) {\n      const span = merge(displayRow, gridColOf(exportCol));\n      if (!span) continue;\n      // A span may cover several grid columns; find the exported columns whose\n      // grid index falls in [leftCol, rightCol].\n      const exportCols: number[] = [];\n      for (let c = 0; c < colCount; c++) {\n        const gc = gridColOf(c);\n        if (gc >= span.leftCol && gc <= span.rightCol) exportCols.push(c);\n      }\n      // Rows of the span that are present in the export, in export order.\n      const exportRows: number[] = [];\n      for (let dr = span.topRow; dr <= span.bottomRow; dr++) {\n        const er = displayToExport.get(dr);\n        if (er != null) exportRows.push(er);\n      }\n      if (exportRows.length === 0 || exportCols.length === 0) continue;\n      const top = Math.min(...exportRows);\n      const bottom = Math.max(...exportRows);\n      const left = Math.min(...exportCols);\n      const right = Math.max(...exportCols);\n      if (top === bottom && left === right) continue; // not a real span here\n\n      const key = `${top}:${left}`;\n      if (seen.has(key)) continue;\n      seen.add(key);\n      merges.push({ topRow: top, bottomRow: bottom, leftCol: left, rightCol: right });\n\n      // Blank the non-origin cells within the exported span.\n      for (const er of exportRows) {\n        for (const ec of exportCols) {\n          if (er === top && ec === left) continue;\n          const cell = rows[er].cells[ec];\n          if (cell) {\n            cell.value = null;\n            cell.text = '';\n          }\n        }\n      }\n    }\n  }\n  return merges;\n}\n\nfunction yieldToEventLoop(): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, 0));\n}\n\nfunction abortError(): Error {\n  const err = new Error('Export aborted');\n  err.name = 'AbortError';\n  return err;\n}\n\nfunction dataCell(column: Column, item: Record<string, unknown>): ExportCell {\n  const value = column.getValue(item);\n  return {\n    value,\n    text: cellText(column, value, item),\n    type: column.dataType,\n    align: column.align,\n  };\n}\n\n// Formatted display text, with a readable fallback for booleans (which the grid\n// renders as a checkbox glyph and so formats to '').\nfunction cellText(column: Column, value: unknown, item: Record<string, unknown>): string {\n  if (column.dataType === 'Boolean') {\n    return value === true ? 'TRUE' : value === false ? 'FALSE' : '';\n  }\n  return column.formatValue(value, item);\n}\n\n// A group-header row: the group label in the first cell, then any per-column\n// aggregates in their columns (mirrors what the grid draws on group rows).\nfunction groupRow(group: CollectionViewGroup, level: number, columns: Column[]): ExportRow {\n  const cells: ExportCell[] = columns.map((column, i) => {\n    if (i === 0) {\n      const indent = '  '.repeat(level);\n      return {\n        value: group.name,\n        text: `${indent}${group.name} (${group.itemCount})`,\n        type: 'String',\n        align: 'left',\n      };\n    }\n    if (column.aggregate) {\n      const agg = computeAggregate(group.items, column.aggregate, (it) => column.getValue(it));\n      return {\n        value: agg,\n        text: agg == null ? '' : column.formatValue(agg),\n        type: agg == null ? 'String' : 'Number',\n        align: column.align,\n      };\n    }\n    return { value: null, text: '', type: 'String', align: column.align };\n  });\n  return { kind: 'group', level, cells };\n}\n","/**\n * A minimal, self-contained progress overlay shown during `exportAsync` when\n * `showProgress` is enabled. It mounts into the grid host, needs no styles from\n * the grid stylesheet (inline styles only), and is removed when the export\n * finishes. Hidden by default — the manager only creates it on request.\n */\nexport class ProgressOverlay {\n  private root: HTMLElement;\n  private bar: HTMLElement;\n  private label: HTMLElement;\n\n  constructor(private host: HTMLElement) {\n    this.root = el('div', {\n      position: 'absolute',\n      inset: '0',\n      display: 'flex',\n      flexDirection: 'column',\n      alignItems: 'center',\n      justifyContent: 'center',\n      gap: '10px',\n      background: 'rgba(0,0,0,0.35)',\n      zIndex: '50',\n      font: '13px/1.4 -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif',\n      color: '#fff',\n    });\n    this.root.className = 'apg-export-progress';\n    this.root.setAttribute('role', 'progressbar');\n\n    this.label = el('div', { fontWeight: '600' });\n    this.label.textContent = 'Exporting…';\n\n    const track = el('div', {\n      width: '220px',\n      height: '8px',\n      borderRadius: '4px',\n      background: 'rgba(255,255,255,0.25)',\n      overflow: 'hidden',\n    });\n    this.bar = el('div', {\n      width: '0%',\n      height: '100%',\n      borderRadius: '4px',\n      background: '#4b8bff',\n      transition: 'width 0.1s linear',\n    });\n    track.appendChild(this.bar);\n    this.root.append(this.label, track);\n  }\n\n  show(): void {\n    // The host must be a positioned container; the grid host already is.\n    if (getComputedStyle(this.host).position === 'static') {\n      this.host.style.position = 'relative';\n    }\n    this.host.appendChild(this.root);\n  }\n\n  set(fraction: number): void {\n    const pct = Math.round(Math.min(1, Math.max(0, fraction)) * 100);\n    this.bar.style.width = `${pct}%`;\n    this.label.textContent = `Exporting… ${pct}%`;\n    this.root.setAttribute('aria-valuenow', String(pct));\n  }\n\n  hide(): void {\n    this.root.remove();\n  }\n}\n\nfunction el(tag: string, style: Partial<CSSStyleDeclaration>): HTMLElement {\n  const node = document.createElement(tag);\n  Object.assign(node.style, style);\n  return node;\n}\n","import { Column } from '../models/Column';\nimport { ExportRegistry } from './registry';\nimport {\n  buildExportData,\n  buildExportDataAsync,\n  BuildExportInput,\n  ExportColumnGroupSpan,\n  ExportMergeRange,\n  ExportSource,\n} from './buildExportData';\nimport { downloadBlob } from './download';\nimport { ProgressOverlay } from './ProgressOverlay';\nimport { ExportData, ExportOptions } from './types';\n\n/** Everything the manager needs from the grid, injected as getters. */\nexport interface ExportDeps {\n  /** Visible columns in display order. */\n  columns: () => Column[];\n  /** The row source (the grid's DataView satisfies this — filtered + grouped view). */\n  source: () => ExportSource;\n  /**\n   * The full, unfiltered, ungrouped source. Used when exporting a native Excel\n   * AutoFilter so the file contains every row for Excel to filter. Optional; the\n   * filtered `source` is used when absent.\n   */\n  fullSource?: () => ExportSource;\n  /** Current selection rectangle, or null. */\n  selection: () => {\n    topRow: number;\n    bottomRow: number;\n    leftCol: number;\n    rightCol: number;\n  } | null;\n  /** Multi-level header bands for the current columns, or empty. */\n  headerGroups: () => { spans: ExportColumnGroupSpan[]; rows: number };\n  /** Cell-merge lookup in grid coordinates, or undefined when merging is off. */\n  merge?: () => ((displayRow: number, gridCol: number) => ExportMergeRange | null) | undefined;\n  /** Whether the grid has column filtering enabled (drives the AutoFilter default). */\n  filterable?: () => boolean;\n  /**\n   * Active value-based column filters, as `{ binding, values }`. Reflected in\n   * the exported AutoFilter so Excel opens showing the same filtered result.\n   */\n  activeFilters?: () => { binding: string; values: string[] }[];\n  /** Cancelable \"before\" hook; return false to abort. */\n  onExporting: (options: ExportOptions) => boolean;\n  /** \"After\" hook, fired once the artifact is produced. */\n  onExported: (options: ExportOptions) => void;\n  /** Host element the progress overlay mounts into (the grid host). */\n  host?: () => HTMLElement | null;\n}\n\n/** The result of an export: the artifact plus its file metadata. */\nexport interface ExportResult {\n  content: string | Uint8Array;\n  fileName: string;\n  mimeType: string;\n}\n\n/**\n * Orchestrates an export: assembles the {@link ExportData} IR from the grid,\n * hands it to the selected {@link ExportFormat}, fires the cancelable\n * `exporting` / `exported` events, and (by default) downloads the file.\n * Grid-agnostic beyond the injected {@link ExportDeps}.\n */\nexport class ExportManager {\n  private registry = new ExportRegistry();\n  private overlay?: ProgressOverlay;\n\n  constructor(private deps: ExportDeps) {}\n\n  /** Register a custom output format. */\n  registerFormat = this.registry.register.bind(this.registry);\n\n  /** Ids of the available formats. */\n  formats(): string[] {\n    return this.registry.ids();\n  }\n\n  /**\n   * Run an export synchronously. Returns the artifact + metadata, or null if a\n   * handler canceled it or the format/columns are invalid. Downloads unless\n   * `options.download === false`. For large datasets prefer {@link exportAsync}.\n   */\n  export(options: ExportOptions = {}): ExportResult | null {\n    const format = this.resolveFormat(options);\n    if (!format) return null;\n    if (this.deps.onExporting(options) === false) return null;\n\n    const data = buildExportData(this.buildInput(options), options);\n    return this.finishExport(data, format, options);\n  }\n\n  /**\n   * Run an export asynchronously: rows are built in chunks that yield to the\n   * event loop, so the page stays responsive. Reports progress via\n   * `options.onProgress` and shows the built-in overlay when\n   * `options.showProgress` is true. Honors `options.signal` for cancellation.\n   * Resolves to the artifact (null if canceled), rejects only on unexpected\n   * errors — an abort resolves to null.\n   */\n  async exportAsync(options: ExportOptions = {}): Promise<ExportResult | null> {\n    const format = this.resolveFormat(options);\n    if (!format) return null;\n    if (this.deps.onExporting(options) === false) return null;\n\n    const showProgress = options.showProgress ?? false;\n    const host = this.deps.host?.() ?? null;\n    if (showProgress && host) {\n      this.overlay = new ProgressOverlay(host);\n      this.overlay.show();\n    }\n\n    // Chain the caller's progress into the overlay.\n    const onProgress = (f: number): void => {\n      this.overlay?.set(f);\n      options.onProgress?.(f);\n    };\n\n    try {\n      const data = await buildExportDataAsync(this.buildInput(options), {\n        ...options,\n        onProgress,\n      });\n      // Rendering the artifact is synchronous but usually fast.\n      const result = this.finishExport(data, format, options);\n      return result;\n    } catch (err) {\n      if ((err as Error).name === 'AbortError') return null;\n      throw err;\n    } finally {\n      this.overlay?.hide();\n      this.overlay = undefined;\n    }\n  }\n\n  /** Build just the IR (useful for tests or custom rendering). */\n  buildData(options: ExportOptions = {}): ExportData {\n    return buildExportData(this.buildInput(options), options);\n  }\n\n  dispose(): void {\n    this.overlay?.hide();\n    this.overlay = undefined;\n  }\n\n  // ---- internals ------------------------------------------------------------\n\n  private resolveFormat(options: ExportOptions) {\n    const formatId = options.format ?? 'csv';\n    const format = this.registry.get(formatId);\n    if (!format) warn(`unknown export format \"${formatId}\"`);\n    return format;\n  }\n\n  private finishExport(\n    data: ExportData,\n    format: NonNullable<ReturnType<ExportManager['resolveFormat']>>,\n    options: ExportOptions,\n  ): ExportResult {\n    const content = format.render(data, options);\n    const fileName = `${options.fileName ?? 'export'}.${format.extension}`;\n    if (options.download ?? true) {\n      downloadBlob(content, fileName, format.mimeType);\n    }\n    this.deps.onExported(options);\n    return { content, fileName, mimeType: format.mimeType };\n  }\n\n  private buildInput(options: ExportOptions): BuildExportInput {\n    const allColumns = this.deps.columns();\n    const columns = pickColumns(allColumns, options.columns);\n    const selectionScoped = (options.rows ?? 'all') === 'selection';\n    const selection = selectionScoped ? this.deps.selection() : null;\n    const hg = this.deps.headerGroups();\n    const merge = this.deps.merge?.();\n    // Map an export-column index to its position in the grid's visible columns,\n    // which is the coordinate space the merge lookup uses.\n    const gridIndex = new Map(allColumns.map((c, i) => [c, i]));\n    const gridColOf = (exportCol: number): number => gridIndex.get(columns[exportCol]) ?? exportCol;\n\n    const filterable = this.deps.filterable?.() ?? false;\n    const autoFilter = options.autoFilter ?? filterable;\n    const filtered = this.deps.source();\n    // When emitting a native Excel AutoFilter, export every row (unfiltered) so\n    // Excel has data to filter — but only when we aren't grouped or\n    // selection-scoped, where the visible view is what the user means.\n    const useFull =\n      autoFilter && !selectionScoped && !filtered.grouped && this.deps.fullSource != null;\n    const source = useFull ? this.deps.fullSource!() : filtered;\n\n    // Map active value-filters to export-column indices (only when the AutoFilter\n    // is actually emitted and we exported the full data set — otherwise the rows\n    // are already filtered and re-applying would double up).\n    const colByBinding = new Map(columns.map((c, i) => [c.binding, i]));\n    const filters =\n      autoFilter && useFull\n        ? (this.deps.activeFilters?.() ?? [])\n            .map((f) => ({ col: colByBinding.get(f.binding) ?? -1, values: f.values }))\n            .filter((f) => f.col >= 0 && f.values.length > 0)\n        : undefined;\n\n    return {\n      columns,\n      \n      source,\n      selection: selection\n        ? {\n            topRow: selection.topRow,\n            bottomRow: selection.bottomRow,\n            leftCol: 0,\n            rightCol: columns.length - 1,\n          }\n        : null,\n      // Header groups only make sense with the full, unfiltered column set.\n      headerGroups: options.columns ? undefined : hg.spans,\n      headerRows: options.columns ? undefined : hg.rows,\n      merge: merge ?? undefined,\n      gridColOf: merge ? gridColOf : undefined,\n      filterable,\n      filters: filters && filters.length ? filters : undefined,\n    };\n  }\n}\n\n// Resolve the requested column bindings to Column objects, in the requested\n// order. Unknown bindings are skipped; omitting `bindings` keeps all columns.\nfunction pickColumns(columns: Column[], bindings?: string[]): Column[] {\n  if (!bindings || bindings.length === 0) return columns;\n  const byBinding = new Map(columns.map((c) => [c.binding, c]));\n  const out: Column[] = [];\n  for (const b of bindings) {\n    const c = byBinding.get(b);\n    if (c) out.push(c);\n  }\n  return out.length ? out : columns;\n}\n\nfunction warn(message: string): void {\n  if (typeof console !== 'undefined') console.warn(`apgrid: ${message}`);\n}\n","/**\n * Trigger a browser download of exported content. Kept isolated so the rest of\n * the export module stays DOM-free and unit-testable. No dependencies.\n */\nexport function downloadBlob(\n  content: string | Uint8Array,\n  fileName: string,\n  mimeType: string,\n): void {\n  if (typeof document === 'undefined' || typeof URL === 'undefined') return;\n  // Copy into a fresh ArrayBuffer-backed view so Blob gets a clean buffer.\n  const part: BlobPart = typeof content === 'string' ? content : new Uint8Array(content).slice();\n  const blob = new Blob([part], { type: mimeType });\n  const url = URL.createObjectURL(blob);\n  const a = document.createElement('a');\n  a.href = url;\n  a.download = fileName;\n  a.style.display = 'none';\n  document.body.appendChild(a);\n  a.click();\n  document.body.removeChild(a);\n  // Revoke on the next tick so the click has committed.\n  setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n","import { createEl } from '../utils/DOM';\nimport { IconName, iconEl } from '../utils/icons';\n\nexport interface MenuItem {\n  label: string;\n  icon?: IconName;\n  disabled?: boolean;\n  action: () => void;\n}\n\nexport type MenuEntry = MenuItem | 'separator';\n\n/**\n * A small floating menu shown at a point (typically the mouse on right-click).\n * Closes on outside click, Escape, scroll, or when another menu opens. Icons\n * come from the shared icon set.\n */\nexport class ContextMenu {\n  private el?: HTMLElement;\n\n  get isOpen(): boolean {\n    return this.el != null;\n  }\n\n  open(x: number, y: number, items: MenuEntry[]): void {\n    this.close();\n    const menu = createEl('div', 'apg-context-menu');\n    for (const item of items) {\n      if (item === 'separator') {\n        menu.appendChild(createEl('div', 'apg-context-menu-sep'));\n        continue;\n      }\n      const row = createEl('button', 'apg-context-menu-item');\n      row.type = 'button';\n      row.disabled = !!item.disabled;\n      row.appendChild(item.icon ? iconEl(item.icon, 'apg-context-menu-icon') : blankIcon());\n      const label = createEl('span', 'apg-context-menu-label');\n      label.textContent = item.label;\n      row.appendChild(label);\n      if (!item.disabled) {\n        row.addEventListener('click', () => {\n          this.close();\n          item.action();\n        });\n      }\n      menu.appendChild(row);\n    }\n    document.body.appendChild(menu);\n\n    // Keep the menu inside the viewport.\n    const r = menu.getBoundingClientRect();\n    const left = Math.max(4, Math.min(x, window.innerWidth - r.width - 8));\n    const top = Math.max(4, Math.min(y, window.innerHeight - r.height - 8));\n    menu.style.left = `${left}px`;\n    menu.style.top = `${top}px`;\n    this.el = menu;\n\n    // Defer so the opening click/contextmenu doesn't immediately close it.\n    setTimeout(() => {\n      window.addEventListener('mousedown', this.onOutside, true);\n      window.addEventListener('keydown', this.onKey, true);\n      window.addEventListener('scroll', this.close, true);\n    });\n  }\n\n  readonly close = (): void => {\n    if (!this.el) return;\n    this.el.remove();\n    this.el = undefined;\n    window.removeEventListener('mousedown', this.onOutside, true);\n    window.removeEventListener('keydown', this.onKey, true);\n    window.removeEventListener('scroll', this.close, true);\n  };\n\n  private readonly onOutside = (e: MouseEvent): void => {\n    if (this.el && !this.el.contains(e.target as Node)) this.close();\n  };\n\n  private readonly onKey = (e: KeyboardEvent): void => {\n    if (e.key === 'Escape') this.close();\n  };\n}\n\nfunction blankIcon(): HTMLElement {\n  return createEl('span', 'apg-context-menu-icon');\n}\n","import { createEl } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\nimport { ContextMenu, MenuEntry } from './ContextMenu';\n\nexport interface GroupChip {\n  binding: string;\n  header: string;\n  sort: 'asc' | 'desc' | null;\n}\n\n/**\n * Toggles for the grouping bar. Everything defaults to enabled; set a field to\n * false to remove that capability. Passed via the grid's `groupPanel` option,\n * which also accepts `true` (all defaults) or `false` (no panel).\n *\n * Purely visual bits are not flags here — hide them with CSS instead: the bar\n * icon is `.apg-grouppanel-icon` and each chip's drag grip is\n * `.apg-group-chip-grip` (e.g. `.apg-group-chip-grip { display: none }`).\n */\nexport interface GroupPanelOptions {\n  /** Text shown when no columns are grouped. */\n  placeholder?: string;\n  /** Maximum number of grouping levels. Default 6. */\n  maxGroups?: number;\n  /** Drag a column header into the bar to group by it. Default true. */\n  allowDragToGroup?: boolean;\n  /** Drag chips to reorder grouping levels. Default true. */\n  allowReorder?: boolean;\n  /** Click a chip (or use the menu) to sort the level. Default true. */\n  allowSort?: boolean;\n  /** Remove a level with its ✕ (or the menu). Default true. */\n  allowRemove?: boolean;\n  /** Right-click a chip for a menu of grouping actions. Default true. */\n  contextMenu?: boolean;\n}\n\n/** Fully-resolved {@link GroupPanelOptions}; every field is set. */\nexport interface ResolvedGroupPanel {\n  placeholder: string;\n  maxGroups: number;\n  allowDragToGroup: boolean;\n  allowReorder: boolean;\n  allowSort: boolean;\n  allowRemove: boolean;\n  contextMenu: boolean;\n}\n\nexport interface GroupPanelCallbacks {\n  chips: () => GroupChip[];\n  onRemove: (binding: string) => void;\n  onReorder: (from: number, to: number) => void;\n  onToggleSort: (binding: string) => void;\n  /** Set a level's sort explicitly: true = ascending, false = descending, null = clear. */\n  onSort: (binding: string, dir: boolean | null) => void;\n  onExpandAll: () => void;\n  onCollapseAll: () => void;\n}\n\nconst THRESHOLD = 4; // pixels before a chip press becomes a reorder drag\n\n/**\n * The grouping bar. Shows a chip per active group level — each with a drag grip,\n * its sort direction, and a remove button — separated by chevrons to read as a\n * hierarchy. Users can reorder levels by dragging chips, toggle a level's sort\n * by clicking it, remove a level with its ✕, and right-click a chip for a menu\n * of grouping actions. Each of these is individually switchable through\n * {@link ResolvedGroupPanel}. Dropping a column header onto the bar is handled by\n * the header dragger, which uses {@link hostElement} as the drop zone and\n * {@link highlight} to show it.\n */\nexport class GroupPanel {\n  private list: HTMLElement;\n  private placeholderEl: HTMLElement;\n  private marker = createEl('div', 'apg-group-chip-marker');\n  private menu = new ContextMenu();\n  private dragFrom = -1;\n  private dragging = false;\n  private startX = 0;\n  private insertAt = 0;\n\n  constructor(\n    private host: HTMLElement,\n    private cb: GroupPanelCallbacks,\n    private opts: ResolvedGroupPanel,\n  ) {\n    this.host.appendChild(iconEl('group', 'apg-grouppanel-icon'));\n    this.placeholderEl = createEl('span', 'apg-group-placeholder');\n    this.placeholderEl.textContent = opts.placeholder;\n    this.list = createEl('div', 'apg-group-chips');\n    this.host.append(this.placeholderEl, this.list);\n    this.host.addEventListener('mousedown', this.onDown);\n    this.host.addEventListener('click', this.onClick);\n    if (opts.contextMenu) this.host.addEventListener('contextmenu', this.onContextMenu);\n    this.render();\n  }\n\n  get hostElement(): HTMLElement {\n    return this.host;\n  }\n\n  highlight(on: boolean): void {\n    this.host.classList.toggle('apg-grouppanel-over', on);\n  }\n\n  render(): void {\n    const chips = this.cb.chips();\n    this.placeholderEl.style.display = chips.length ? 'none' : '';\n    this.list.textContent = '';\n    chips.forEach((chip, i) => {\n      if (i > 0) this.list.appendChild(iconEl('chevron', 'apg-group-sep'));\n\n      const el = createEl('div', 'apg-group-chip');\n      el.dataset.index = String(i);\n      el.dataset.binding = chip.binding;\n      // Leave the grab cursor to CSS when reorderable (so :active shows grabbing);\n      // otherwise reflect what a click does.\n      if (!this.opts.allowReorder) el.style.cursor = this.opts.allowSort ? 'pointer' : 'default';\n\n      el.appendChild(iconEl('dragHandle', 'apg-group-chip-grip'));\n\n      const label = createEl('span', 'apg-group-chip-label');\n      label.textContent = chip.header;\n      el.appendChild(label);\n\n      if (this.opts.allowSort && chip.sort) {\n        el.appendChild(iconEl(chip.sort === 'asc' ? 'sortAsc' : 'sortDesc', 'apg-group-chip-sort'));\n      }\n\n      if (this.opts.allowRemove) {\n        const remove = createEl('button', 'apg-group-chip-remove');\n        remove.type = 'button';\n        remove.dataset.remove = chip.binding;\n        remove.title = `Remove ${chip.header} grouping`;\n        remove.appendChild(iconEl('close'));\n        el.appendChild(remove);\n      }\n\n      this.list.appendChild(el);\n    });\n  }\n\n  dispose(): void {\n    this.host.removeEventListener('mousedown', this.onDown);\n    this.host.removeEventListener('click', this.onClick);\n    this.host.removeEventListener('contextmenu', this.onContextMenu);\n    this.menu.close();\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n    this.marker.remove();\n    this.host.textContent = '';\n  }\n\n  // Right-click a chip: a menu of grouping actions, like a spreadsheet grid.\n  // Sort/remove entries follow the same toggles as the chip controls.\n  private readonly onContextMenu = (e: MouseEvent): void => {\n    const chip = (e.target as HTMLElement).closest('.apg-group-chip') as HTMLElement | null;\n    const binding = chip?.dataset.binding;\n    if (!binding) return;\n    e.preventDefault();\n    const sorted = this.cb.chips().find((c) => c.binding === binding)?.sort ?? null;\n    const items: MenuEntry[] = [\n      { label: 'Expand All', icon: 'caretUp', action: () => this.cb.onExpandAll() },\n      { label: 'Collapse All', icon: 'caretRight', action: () => this.cb.onCollapseAll() },\n    ];\n    if (this.opts.allowSort) {\n      items.push(\n        'separator',\n        { label: 'Sort Ascending', icon: 'sortAsc', action: () => this.cb.onSort(binding, true) },\n        {\n          label: 'Sort Descending',\n          icon: 'sortDesc',\n          action: () => this.cb.onSort(binding, false),\n        },\n        {\n          label: 'Remove Sort',\n          icon: 'dot',\n          disabled: sorted == null,\n          action: () => this.cb.onSort(binding, null),\n        },\n      );\n    }\n    if (this.opts.allowRemove) {\n      items.push('separator', {\n        label: 'Remove Group',\n        icon: 'close',\n        action: () => this.cb.onRemove(binding),\n      });\n    }\n    this.menu.open(e.clientX, e.clientY, items);\n  };\n\n  private readonly onClick = (e: MouseEvent): void => {\n    if (this.dragging) return;\n    const target = e.target as HTMLElement;\n    const removeEl = target.closest('[data-remove]') as HTMLElement | null;\n    if (removeEl?.dataset.remove != null) {\n      this.cb.onRemove(removeEl.dataset.remove);\n      return;\n    }\n    if (!this.opts.allowSort) return;\n    const chip = target.closest('.apg-group-chip') as HTMLElement | null;\n    if (chip?.dataset.binding) this.cb.onToggleSort(chip.dataset.binding);\n  };\n\n  private readonly onDown = (e: MouseEvent): void => {\n    if (e.button !== 0 || !this.opts.allowReorder) return;\n    const target = e.target as HTMLElement;\n    if (target.closest('[data-remove]')) return; // the ✕ is a click, not a drag\n    const chip = target.closest('.apg-group-chip') as HTMLElement | null;\n    if (!chip) return;\n    this.dragFrom = Number(chip.dataset.index);\n    this.startX = e.clientX;\n    this.dragging = false;\n    window.addEventListener('mousemove', this.onMove);\n    window.addEventListener('mouseup', this.onUp);\n  };\n\n  private readonly onMove = (e: MouseEvent): void => {\n    if (!this.dragging) {\n      if (Math.abs(e.clientX - this.startX) < THRESHOLD) return;\n      this.dragging = true;\n      this.host.classList.add('apg-grouppanel-reordering');\n    }\n    const chipEls = [...this.list.querySelectorAll('.apg-group-chip')] as HTMLElement[];\n    let idx = chipEls.length;\n    for (let i = 0; i < chipEls.length; i++) {\n      const r = chipEls[i].getBoundingClientRect();\n      if (e.clientX < r.left + r.width / 2) {\n        idx = i;\n        break;\n      }\n    }\n    this.insertAt = idx;\n    if (idx < chipEls.length) this.list.insertBefore(this.marker, chipEls[idx]);\n    else this.list.appendChild(this.marker);\n  };\n\n  private readonly onUp = (): void => {\n    window.removeEventListener('mousemove', this.onMove);\n    window.removeEventListener('mouseup', this.onUp);\n    this.host.classList.remove('apg-grouppanel-reordering');\n    if (this.dragging) {\n      this.marker.remove();\n      const to = this.insertAt > this.dragFrom ? this.insertAt - 1 : this.insertAt;\n      if (this.dragFrom >= 0 && to !== this.dragFrom) this.cb.onReorder(this.dragFrom, to);\n    }\n    this.dragFrom = -1;\n    // Let the click that follows this mouseup see dragging=true so a reorder\n    // doesn't also toggle sort, then clear it.\n    setTimeout(() => (this.dragging = false), 0);\n  };\n}\n","import { Column } from './Column';\n\nexport type FilterOperator =\n  | 'contains'\n  | 'equals'\n  | 'notEquals'\n  | 'startsWith'\n  | 'endsWith'\n  | 'empty'\n  | 'notEmpty'\n  | 'gt'\n  | 'gte'\n  | 'lt'\n  | 'lte';\n\nexport interface FilterCondition {\n  op: FilterOperator;\n  value: string;\n}\n\nexport interface OperatorChoice {\n  op: FilterOperator;\n  label: string;\n}\n\nexport const TEXT_OPERATORS: OperatorChoice[] = [\n  { op: 'contains', label: 'Contains' },\n  { op: 'equals', label: 'Equals' },\n  { op: 'notEquals', label: 'Does not equal' },\n  { op: 'startsWith', label: 'Starts with' },\n  { op: 'endsWith', label: 'Ends with' },\n  { op: 'empty', label: 'Is empty' },\n  { op: 'notEmpty', label: 'Is not empty' },\n];\n\nexport const NUMBER_OPERATORS: OperatorChoice[] = [\n  { op: 'equals', label: '=' },\n  { op: 'notEquals', label: '≠' },\n  { op: 'gt', label: '>' },\n  { op: 'gte', label: '≥' },\n  { op: 'lt', label: '<' },\n  { op: 'lte', label: '≤' },\n];\n\n/** The operator choices to offer for a column, based on its data type. */\nexport function operatorsFor<T>(column: Column<T>): OperatorChoice[] {\n  return column.dataType === 'Number' || column.dataType === 'Date'\n    ? NUMBER_OPERATORS\n    : TEXT_OPERATORS;\n}\n\n/** Canonical string used both to list distinct values and to match the value set. */\nexport function filterKey<T>(column: Column<T>, item: T): string {\n  const raw = column.getValue(item);\n  if (column.dataType === 'Boolean') return raw === true ? 'True' : 'False';\n  return column.formatValue(raw, item);\n}\n\n/**\n * Holds the filter state for one column: a set of selected display values (null\n * means \"all\", i.e. no value filter) and an optional operator/value condition.\n * A row passes only when it satisfies both parts.\n */\nexport class ColumnFilter<T = Record<string, unknown>> {\n  values: Set<string> | null = null;\n  condition: FilterCondition | null = null;\n\n  constructor(readonly column: Column<T>) {}\n\n  get isActive(): boolean {\n    return this.values != null || this.condition != null;\n  }\n\n  clear(): void {\n    this.values = null;\n    this.condition = null;\n  }\n\n  test(item: T): boolean {\n    if (this.values && !this.values.has(filterKey(this.column, item))) return false;\n    if (this.condition) {\n      const raw = this.column.getValue(item);\n      const display = this.column.formatValue(raw, item);\n      if (!testCondition(this.column, raw, display, this.condition)) return false;\n    }\n    return true;\n  }\n}\n\nfunction testCondition<T>(\n  column: Column<T>,\n  raw: unknown,\n  display: string,\n  cond: FilterCondition,\n): boolean {\n  const { op } = cond;\n  if (op === 'empty') return raw == null || display === '';\n  if (op === 'notEmpty') return !(raw == null || display === '');\n\n  if (column.dataType === 'Number' || column.dataType === 'Date') {\n    const a = toNumber(raw);\n    const b = column.dataType === 'Date' ? Date.parse(cond.value) : Number(cond.value);\n    if (a == null || Number.isNaN(b)) return true; // no usable bound → don't constrain\n    switch (op) {\n      case 'equals':\n        return a === b;\n      case 'notEquals':\n        return a !== b;\n      case 'gt':\n        return a > b;\n      case 'gte':\n        return a >= b;\n      case 'lt':\n        return a < b;\n      case 'lte':\n        return a <= b;\n      default:\n        return true;\n    }\n  }\n\n  const needle = cond.value.toLowerCase();\n  if (needle === '') return true;\n  const hay = display.toLowerCase();\n  switch (op) {\n    case 'contains':\n      return hay.includes(needle);\n    case 'equals':\n      return hay === needle;\n    case 'notEquals':\n      return hay !== needle;\n    case 'startsWith':\n      return hay.startsWith(needle);\n    case 'endsWith':\n      return hay.endsWith(needle);\n    default:\n      return true;\n  }\n}\n\nfunction toNumber(raw: unknown): number | null {\n  if (raw == null || raw === '') return null;\n  if (raw instanceof Date) return raw.getTime();\n  const n = Number(raw);\n  return Number.isNaN(n) ? null : n;\n}\n","import { Column } from '../models/Column';\nimport { ColumnFilter, filterKey } from '../models/ColumnFilter';\nimport { CollectionView } from './CollectionView';\n\n/**\n * Owns a {@link ColumnFilter} per column binding and composes the active ones\n * into a single predicate installed on the collection view. Column filtering\n * therefore owns `CollectionView.filter` while it's in use.\n */\nexport class FilterModel<T = Record<string, unknown>> {\n  private filters = new Map<string, ColumnFilter<T>>();\n\n  constructor(private view: CollectionView<T>) {}\n\n  /** The filter for a column, created on first access. */\n  get(column: Column<T>): ColumnFilter<T> {\n    let f = this.filters.get(column.binding);\n    if (!f) {\n      f = new ColumnFilter<T>(column);\n      this.filters.set(column.binding, f);\n    }\n    return f;\n  }\n\n  isActive(binding: string): boolean {\n    return this.filters.get(binding)?.isActive ?? false;\n  }\n\n  get hasAny(): boolean {\n    for (const f of this.filters.values()) if (f.isActive) return true;\n    return false;\n  }\n\n  /**\n   * Distinct display values to offer for a column. Reflects the other active\n   * column filters (like a spreadsheet) but ignores this column's own filter, so\n   * its list doesn't collapse to just the values already selected.\n   */\n  distinctValues(column: Column<T>): string[] {\n    const others = [...this.filters.values()].filter(\n      (f) => f.isActive && f.column.binding !== column.binding,\n    );\n    const seen = new Set<string>();\n    for (const item of this.view.sourceCollection) {\n      if (others.every((f) => f.test(item))) seen.add(filterKey(column, item));\n    }\n    return [...seen].sort((a, b) => a.localeCompare(b));\n  }\n\n  /** Recompose the active filters and install (or clear) the view predicate. */\n  apply(): void {\n    const active = [...this.filters.values()].filter((f) => f.isActive);\n    this.view.filter = active.length ? (item) => active.every((f) => f.test(item)) : null;\n  }\n\n  clearAll(): void {\n    for (const f of this.filters.values()) f.clear();\n    this.apply();\n  }\n}\n","import { createEl } from '../utils/DOM';\nimport { iconEl } from '../utils/icons';\nimport { Column } from '../models/Column';\nimport {\n  ColumnFilter,\n  FilterCondition,\n  FilterOperator,\n  operatorsFor,\n} from '../models/ColumnFilter';\n\nexport interface FilterDraft {\n  values: Set<string> | null;\n  condition: FilterCondition | null;\n}\n\nexport interface FilterEditorOptions<T> {\n  column: Column<T>;\n  values: string[];\n  filter: ColumnFilter<T>;\n  /** Show the Sort Ascending/Descending shortcuts. */\n  showSort: boolean;\n  /** Current sort direction for this column, or null when unsorted. */\n  sort: 'asc' | 'desc' | null;\n  onSort: (dir: boolean | null) => void;\n  onApply: (draft: FilterDraft) => void;\n  onClear: () => void;\n}\n\n// Operators that ignore the value input.\nconst VALUELESS: FilterOperator[] = ['empty', 'notEmpty'];\n\n/**\n * The column filter popup: an operator/value condition on top and an\n * Excel-style \"filter by value\" checklist below, with a search box, Select All,\n * and Clear/Apply. Floats near the header's filter button and closes on outside\n * click, Escape, or scroll.\n */\nexport class FilterEditor<T = Record<string, unknown>> {\n  private el?: HTMLElement;\n\n  get isOpen(): boolean {\n    return this.el != null;\n  }\n\n  open(anchor: DOMRect, opts: FilterEditorOptions<T>): void {\n    this.close();\n    const { column, values, filter } = opts;\n\n    const selected = new Set(filter.values ?? values);\n    let condOp: FilterOperator = filter.condition?.op ?? operatorsFor(column)[0].op;\n    let condValue = filter.condition?.value ?? '';\n\n    const dialog = createEl('div', 'apg-filter-dialog');\n\n    // Sort shortcuts, like a column menu. Clicking the active direction clears it.\n    if (opts.showSort) {\n      const sortRow = createEl('div', 'apg-filter-sort');\n      const makeSort = (dir: 'asc' | 'desc', label: string): HTMLButtonElement => {\n        const btn = createEl('button', 'apg-filter-sort-btn');\n        btn.type = 'button';\n        if (opts.sort === dir) btn.classList.add('apg-filter-sort-active');\n        btn.appendChild(iconEl(dir === 'asc' ? 'sortAsc' : 'sortDesc'));\n        const text = createEl('span');\n        text.textContent = label;\n        btn.appendChild(text);\n        btn.addEventListener('click', () => {\n          this.close();\n          opts.onSort(opts.sort === dir ? null : dir === 'asc');\n        });\n        return btn;\n      };\n      sortRow.append(makeSort('asc', 'Sort Ascending'), makeSort('desc', 'Sort Descending'));\n      dialog.appendChild(sortRow);\n      dialog.appendChild(createEl('div', 'apg-filter-sep'));\n    }\n\n    // Condition row (skipped for Boolean, which only makes sense as a value list).\n    let valueInput: HTMLInputElement | undefined;\n    if (column.dataType !== 'Boolean') {\n      const section = createEl('div', 'apg-filter-section');\n      const opSelect = createEl('select', 'apg-filter-op');\n      for (const choice of operatorsFor(column)) {\n        const o = createEl('option');\n        o.value = choice.op;\n        o.textContent = choice.label;\n        if (choice.op === condOp) o.selected = true;\n        opSelect.appendChild(o);\n      }\n      valueInput = createEl('input', 'apg-filter-value');\n      valueInput.type =\n        column.dataType === 'Number' ? 'number' : column.dataType === 'Date' ? 'date' : 'text';\n      valueInput.placeholder = 'Value';\n      valueInput.value = condValue;\n      valueInput.style.display = VALUELESS.includes(condOp) ? 'none' : '';\n      opSelect.addEventListener('change', () => {\n        condOp = opSelect.value as FilterOperator;\n        valueInput!.style.display = VALUELESS.includes(condOp) ? 'none' : '';\n      });\n      valueInput.addEventListener('input', () => (condValue = valueInput!.value));\n      section.append(opSelect, valueInput);\n      dialog.appendChild(section);\n      dialog.appendChild(createEl('div', 'apg-filter-sep'));\n    }\n\n    // Value checklist with search + select all.\n    const search = createEl('input', 'apg-filter-search');\n    search.type = 'search';\n    search.placeholder = 'Search values';\n    dialog.appendChild(search);\n\n    const selectAllRow = createEl('label', 'apg-filter-selectall');\n    const selectAll = createEl('input');\n    selectAll.type = 'checkbox';\n    const selectAllText = createEl('span');\n    selectAllText.textContent = '(Select all)';\n    selectAllRow.append(selectAll, selectAllText);\n    dialog.appendChild(selectAllRow);\n\n    const list = createEl('div', 'apg-filter-list');\n    const boxes = new Map<string, HTMLInputElement>();\n    for (const v of values) {\n      const row = createEl('label', 'apg-filter-item');\n      const box = createEl('input');\n      box.type = 'checkbox';\n      box.checked = selected.has(v);\n      box.addEventListener('change', () => {\n        if (box.checked) selected.add(v);\n        else selected.delete(v);\n        syncSelectAll();\n      });\n      const text = createEl('span');\n      text.textContent = v === '' ? '(Blanks)' : v;\n      row.append(box, text);\n      list.appendChild(row);\n      boxes.set(v, box);\n    }\n    dialog.appendChild(list);\n\n    const syncSelectAll = (): void => {\n      const visible = values.filter((v) => boxes.get(v)!.parentElement!.style.display !== 'none');\n      const on = visible.filter((v) => selected.has(v)).length;\n      selectAll.checked = on > 0 && on === visible.length;\n      selectAll.indeterminate = on > 0 && on < visible.length;\n    };\n    selectAll.addEventListener('change', () => {\n      for (const v of values) {\n        const box = boxes.get(v)!;\n        if (box.parentElement!.style.display === 'none') continue;\n        box.checked = selectAll.checked;\n        if (selectAll.checked) selected.add(v);\n        else selected.delete(v);\n      }\n    });\n    search.addEventListener('input', () => {\n      const q = search.value.trim().toLowerCase();\n      for (const v of values) {\n        const match = v.toLowerCase().includes(q);\n        boxes.get(v)!.parentElement!.style.display = match ? '' : 'none';\n      }\n      syncSelectAll();\n    });\n    syncSelectAll();\n\n    // Footer buttons.\n    const footer = createEl('div', 'apg-filter-footer');\n    const clearBtn = createEl('button', 'apg-filter-clear');\n    clearBtn.type = 'button';\n    clearBtn.textContent = 'Clear';\n    const applyBtn = createEl('button', 'apg-filter-apply');\n    applyBtn.type = 'button';\n    applyBtn.textContent = 'Apply';\n    footer.append(clearBtn, applyBtn);\n    dialog.appendChild(footer);\n\n    clearBtn.addEventListener('click', () => {\n      this.close();\n      opts.onClear();\n    });\n    applyBtn.addEventListener('click', () => {\n      const allOn = selected.size === values.length;\n      const draft: FilterDraft = {\n        values: allOn ? null : new Set(selected),\n        condition: buildCondition(condOp, condValue),\n      };\n      this.close();\n      opts.onApply(draft);\n    });\n\n    document.body.appendChild(dialog);\n    const r = dialog.getBoundingClientRect();\n    const left = Math.max(4, Math.min(anchor.left, window.innerWidth - r.width - 8));\n    const top = Math.max(4, Math.min(anchor.bottom + 4, window.innerHeight - r.height - 8));\n    dialog.style.left = `${left}px`;\n    dialog.style.top = `${top}px`;\n    this.el = dialog;\n\n    setTimeout(() => {\n      if (!this.el) return; // closed before the timeout fired\n      window.addEventListener('mousedown', this.onOutside, true);\n      window.addEventListener('keydown', this.onKey, true);\n      window.addEventListener('scroll', this.onScroll, true);\n    });\n  }\n\n  readonly close = (): void => {\n    if (!this.el) return;\n    this.el.remove();\n    this.el = undefined;\n    window.removeEventListener('mousedown', this.onOutside, true);\n    window.removeEventListener('keydown', this.onKey, true);\n    window.removeEventListener('scroll', this.onScroll, true);\n  };\n\n  private readonly onOutside = (e: MouseEvent): void => {\n    if (this.el && !this.el.contains(e.target as Node)) this.close();\n  };\n\n  // Close when the grid (or page) scrolls, but not when the value list inside\n  // the dialog scrolls.\n  private readonly onScroll = (e: Event): void => {\n    if (this.el && !this.el.contains(e.target as Node)) this.close();\n  };\n\n  private readonly onKey = (e: KeyboardEvent): void => {\n    if (e.key === 'Escape') this.close();\n  };\n}\n\nfunction buildCondition(op: FilterOperator, value: string): FilterCondition | null {\n  if (VALUELESS.includes(op)) return { op, value: '' };\n  return value.trim() !== '' ? { op, value } : null;\n}\n","import { UndoableAction } from './UndoableAction';\n\n/**\n * Tracks undoable actions. Pushing an action past the redo point discards the\n * redo branch. Capped at `maxActions` (default 1000) so long sessions don't grow\n * without bound. `onStateChanged` lets the UI enable/disable undo/redo controls.\n */\nexport class UndoStack {\n  private actions: UndoableAction[] = [];\n  private pointer = -1; // index of the last applied action\n  private busy = false; // suppress re-entrant pushes during undo/redo\n\n  onStateChanged?: () => void;\n\n  constructor(private maxActions = 1000) {}\n\n  get canUndo(): boolean {\n    return this.pointer >= 0;\n  }\n\n  get canRedo(): boolean {\n    return this.pointer < this.actions.length - 1;\n  }\n\n  get actionCount(): number {\n    return this.actions.length;\n  }\n\n  push(action: UndoableAction): void {\n    if (this.busy) return;\n    this.actions.splice(this.pointer + 1);\n    this.actions.push(action);\n    if (this.actions.length > this.maxActions) this.actions.shift();\n    this.pointer = this.actions.length - 1;\n    this.onStateChanged?.();\n  }\n\n  undo(): void {\n    if (!this.canUndo) return;\n    this.busy = true;\n    this.actions[this.pointer].undo();\n    this.busy = false;\n    this.pointer--;\n    this.onStateChanged?.();\n  }\n\n  redo(): void {\n    if (!this.canRedo) return;\n    this.busy = true;\n    this.actions[this.pointer + 1].redo();\n    this.busy = false;\n    this.pointer++;\n    this.onStateChanged?.();\n  }\n\n  clear(): void {\n    this.actions = [];\n    this.pointer = -1;\n    this.onStateChanged?.();\n  }\n}\n","import { UndoableAction } from './UndoableAction';\nimport { Column } from '../models/Column';\n\n/** A column width change. Undo/redo swaps the stored old and new widths. */\nexport class ResizeColumnAction implements UndoableAction {\n  constructor(\n    private column: Column,\n    private oldWidth: number,\n    private newWidth: number,\n    private onApplied: () => void,\n  ) {}\n\n  private apply(width: number): void {\n    this.column.width = width;\n    this.onApplied();\n  }\n\n  undo(): void {\n    this.apply(this.oldWidth);\n  }\n\n  redo(): void {\n    this.apply(this.newWidth);\n  }\n}\n","import { UndoableAction } from './UndoableAction';\nimport { DataView } from '../data/DataView';\nimport { Column } from '../models/Column';\n\n/** A single cell value change. Undo/redo swaps the stored old and new values. */\nexport class EditAction implements UndoableAction {\n  constructor(\n    private data: DataView,\n    private column: Column,\n    private row: number,\n    private oldValue: unknown,\n    private newValue: unknown,\n    private onApplied: () => void,\n  ) {}\n\n  private apply(value: unknown): void {\n    const item = this.data.item(this.row);\n    this.data.applyEdit(item, () => this.column.setValue(item, value));\n    this.onApplied();\n  }\n\n  undo(): void {\n    this.apply(this.oldValue);\n  }\n\n  redo(): void {\n    this.apply(this.newValue);\n  }\n}\n","import { UndoableAction } from './UndoableAction';\n\n/**\n * Groups several actions into one undo step. Used by paste, which can change\n * many cells at once but should undo/redo as a single operation. Undo runs the\n * inner actions in reverse; redo runs them in order. A single onApplied call\n * redraws once after the whole batch.\n */\nexport class BatchAction implements UndoableAction {\n  constructor(\n    private actions: UndoableAction[],\n    private onApplied: () => void,\n  ) {}\n\n  undo(): void {\n    for (let i = this.actions.length - 1; i >= 0; i--) this.actions[i].undo();\n    this.onApplied();\n  }\n\n  redo(): void {\n    for (const action of this.actions) action.redo();\n    this.onApplied();\n  }\n}\n","import { UndoableAction } from './UndoableAction';\nimport { Column } from '../models/Column';\n\n/** Moves a column from one index to another. Undo/redo replays the move. */\nexport class MoveColumnAction implements UndoableAction {\n  constructor(\n    private columns: Column[],\n    private from: number,\n    private to: number,\n    private onApplied: () => void,\n  ) {}\n\n  redo(): void {\n    moveColumn(this.columns, this.from, this.to);\n    this.onApplied();\n  }\n\n  undo(): void {\n    moveColumn(this.columns, this.to, this.from);\n    this.onApplied();\n  }\n}\n\nexport function moveColumn(columns: Column[], from: number, to: number): void {\n  const [col] = columns.splice(from, 1);\n  columns.splice(to, 0, col);\n}\n","import { Column } from '../models/Column';\n\n/**\n * A plain text input overlay for editing one cell. Positioned over the active\n * cell, it commits on Enter/blur and cancels on Escape, reporting the result\n * through callbacks so the EditorManager stays in charge of the lifecycle.\n */\nexport class TextEditor {\n  private input: HTMLInputElement;\n\n  constructor(\n    private onCommit: (value: string) => void,\n    private onCancel: () => void,\n  ) {\n    this.input = document.createElement('input');\n    this.input.className = 'apg-editor';\n    this.input.addEventListener('keydown', (e) => {\n      if (e.key === 'Enter') {\n        e.preventDefault();\n        this.onCommit(this.input.value);\n      } else if (e.key === 'Escape') {\n        e.preventDefault();\n        this.onCancel();\n      }\n      e.stopPropagation();\n    });\n    this.input.addEventListener('blur', () => this.onCommit(this.input.value));\n  }\n\n  open(parent: HTMLElement, column: Column, item: Record<string, unknown>, rect: DOMRect): void {\n    this.input.type = inputType(column.dataType);\n    this.input.className = `apg-editor apg-align-${column.align}`;\n    this.input.value = editorValue(column, item);\n    this.input.style.transform = `translate3d(${rect.left}px, ${rect.top}px, 0)`;\n    this.input.style.width = `${rect.width}px`;\n    this.input.style.height = `${rect.height}px`;\n    parent.appendChild(this.input);\n    this.input.focus();\n    if (this.input.type === 'text') this.input.select();\n  }\n\n  close(): void {\n    this.input.remove();\n  }\n}\n\nfunction inputType(dataType: string): string {\n  if (dataType === 'Number') return 'number';\n  if (dataType === 'Date') return 'date';\n  return 'text';\n}\n\nfunction editorValue(column: Column, item: Record<string, unknown>): string {\n  const value = column.getValue(item);\n  if (value == null) return '';\n  if (column.dataType === 'Date' && value instanceof Date) {\n    return value.toISOString().slice(0, 10); // yyyy-MM-dd for <input type=date>\n  }\n  return String(value);\n}\n","import { Column } from '../models/Column';\nimport { DataMapEditor } from '../models/DataMapEditor';\n\n/**\n * An in-cell editable dropdown for data-mapped columns. The input sits exactly\n * over the cell (same size and look) with a chevron and a styled list of the\n * map's display values below it, so editing feels like the cell itself opening\n * a dropdown rather than a separate control floating over the grid.\n *\n * Typing filters the list; arrow keys move the highlight; Enter or a click\n * commits. A Menu column is pick-only (read-only input). When the column's\n * DataMap is editable, a typed value that isn't on the list is kept as-is;\n * otherwise the commit snaps back to a matching option.\n */\nexport class DropDownEditor {\n  private root: HTMLElement;\n  private input: HTMLInputElement;\n  private arrow: HTMLElement;\n  private listEl: HTMLElement;\n  private options: string[] = [];\n  private highlight = -1;\n  private editable = false;\n\n  constructor(\n    private onCommit: (value: string) => void,\n    private onCancel: () => void,\n  ) {\n    this.root = document.createElement('div');\n    this.root.className = 'apg-editor apg-editor-dropdown';\n\n    this.input = document.createElement('input');\n    this.input.className = 'apg-dd-input';\n    this.input.autocomplete = 'off';\n\n    this.arrow = document.createElement('span');\n    this.arrow.className = 'apg-dd-arrow';\n    this.arrow.setAttribute('aria-hidden', 'true');\n\n    this.listEl = document.createElement('ul');\n    this.listEl.className = 'apg-dropdown';\n\n    this.root.append(this.input, this.arrow, this.listEl);\n\n    this.input.addEventListener('input', () => this.filter(this.input.value));\n    this.input.addEventListener('keydown', (e) => this.onKeyDown(e));\n    this.input.addEventListener('blur', () => this.commitInput());\n    // Commit on mousedown (before the input blurs) so the click isn't lost.\n    this.listEl.addEventListener('mousedown', (e) => {\n      const li = (e.target as HTMLElement).closest('li');\n      if (!li) return;\n      e.preventDefault();\n      this.onCommit(li.textContent ?? '');\n    });\n    // Toggle the list from the chevron without losing input focus.\n    this.arrow.addEventListener('mousedown', (e) => {\n      e.preventDefault();\n      this.toggleList();\n    });\n  }\n\n  open(parent: HTMLElement, column: Column, item: Record<string, unknown>, rect: DOMRect): void {\n    const map = column.dataMap;\n    this.editable = map?.isEditable ?? false;\n    this.options = map ? map.getDisplayValues(item) : [];\n    this.input.readOnly = column.dataMapEditor === DataMapEditor.Menu;\n    this.input.value = map ? map.getDisplayValue(column.getValue(item)) : '';\n    this.root.style.transform = `translate3d(${rect.left}px, ${rect.top}px, 0)`;\n    this.root.style.width = `${rect.width}px`;\n    this.root.style.height = `${rect.height}px`;\n    parent.appendChild(this.root);\n    this.renderList(this.options);\n    this.input.focus();\n    if (!this.input.readOnly) this.input.select();\n  }\n\n  close(): void {\n    this.root.remove();\n  }\n\n  private filter(text: string): void {\n    const q = text.trim().toLowerCase();\n    const matches = q ? this.options.filter((o) => o.toLowerCase().includes(q)) : this.options;\n    this.renderList(matches);\n  }\n\n  private toggleList(): void {\n    if (this.listEl.style.display === 'none') this.renderList(this.options);\n    else this.listEl.style.display = 'none';\n  }\n\n  private renderList(items: string[]): void {\n    this.listEl.innerHTML = '';\n    this.highlight = -1;\n    const current = this.input.value;\n    for (const display of items) {\n      const li = document.createElement('li');\n      li.className = 'apg-dropdown-option';\n      li.textContent = display;\n      if (display === current) li.classList.add('apg-dropdown-active');\n      this.listEl.appendChild(li);\n    }\n    this.listEl.style.display = items.length ? '' : 'none';\n    this.positionList();\n  }\n\n  // Flip the list above the input when there isn't room below it in the scroller.\n  private positionList(): void {\n    const viewport = this.root.closest('.apg-viewport');\n    if (!viewport) return;\n    const inputRect = this.input.getBoundingClientRect();\n    const vpRect = viewport.getBoundingClientRect();\n    const spaceBelow = vpRect.bottom - inputRect.bottom;\n    const flip = spaceBelow < this.listEl.offsetHeight && inputRect.top - vpRect.top > spaceBelow;\n    this.listEl.classList.toggle('apg-dropdown-up', flip);\n  }\n\n  private onKeyDown(e: KeyboardEvent): void {\n    const options = [...this.listEl.children] as HTMLElement[];\n    if (e.key === 'ArrowDown') {\n      e.preventDefault();\n      this.move(1, options);\n    } else if (e.key === 'ArrowUp') {\n      e.preventDefault();\n      this.move(-1, options);\n    } else if (e.key === 'Enter') {\n      e.preventDefault();\n      const sel = options[this.highlight];\n      if (sel) this.onCommit(sel.textContent ?? '');\n      else this.commitInput();\n    } else if (e.key === 'Escape') {\n      e.preventDefault();\n      this.onCancel();\n    }\n    e.stopPropagation();\n  }\n\n  private move(delta: number, options: HTMLElement[]): void {\n    if (!options.length) return;\n    if (this.highlight >= 0) options[this.highlight].classList.remove('apg-dropdown-active');\n    this.highlight = (this.highlight + delta + options.length) % options.length;\n    const el = options[this.highlight];\n    el.classList.add('apg-dropdown-active');\n    el.scrollIntoView({ block: 'nearest' });\n  }\n\n  // Resolve the typed text on blur/Enter. Editable maps keep free text; fixed\n  // maps snap to a matching option, falling back to the only visible one.\n  private commitInput(): void {\n    const value = this.input.value;\n    if (this.editable) {\n      this.onCommit(value);\n      return;\n    }\n    const exact = this.options.find((o) => o.toLowerCase() === value.trim().toLowerCase());\n    if (exact) {\n      this.onCommit(exact);\n      return;\n    }\n    const visible = [...this.listEl.children] as HTMLElement[];\n    if (visible.length === 1) this.onCommit(visible[0].textContent ?? '');\n    else this.onCancel();\n  }\n}\n","import { Column } from '../models/Column';\n\nlet nextId = 0;\n\n/**\n * A radio-button panel for data-mapped columns. Renders one radio per display\n * value below the cell and commits the chosen value on selection. Escape cancels;\n * moving focus out of the panel cancels too. Mirrors the other editors' interface.\n */\nexport class RadioEditor {\n  private root: HTMLElement;\n  private name: string;\n\n  constructor(\n    private onCommit: (value: string) => void,\n    private onCancel: () => void,\n  ) {\n    this.name = `apg-radio-${nextId++}`;\n    this.root = document.createElement('div');\n    this.root.className = 'apg-editor apg-editor-radio';\n    this.root.addEventListener('keydown', (e) => {\n      if (e.key === 'Escape') {\n        e.preventDefault();\n        this.onCancel();\n      }\n      e.stopPropagation();\n    });\n    this.root.addEventListener('focusout', (e) => {\n      const next = e.relatedTarget as Node | null;\n      if (!next || !this.root.contains(next)) this.onCancel();\n    });\n  }\n\n  open(parent: HTMLElement, column: Column, item: Record<string, unknown>, rect: DOMRect): void {\n    const map = column.dataMap;\n    const current = map ? map.getDisplayValue(column.getValue(item)) : '';\n    this.root.innerHTML = '';\n    for (const display of map ? map.getDisplayValues(item) : []) {\n      const label = document.createElement('label');\n      label.className = 'apg-radio-option';\n      const radio = document.createElement('input');\n      radio.type = 'radio';\n      radio.name = this.name;\n      radio.value = display;\n      radio.checked = display === current;\n      radio.addEventListener('change', () => this.onCommit(display));\n      label.append(radio, document.createTextNode(` ${display}`));\n      this.root.appendChild(label);\n    }\n    this.root.style.transform = `translate3d(${rect.left}px, ${rect.top}px, 0)`;\n    this.root.style.minWidth = `${rect.width}px`;\n    parent.appendChild(this.root);\n    const focusTarget =\n      this.root.querySelector<HTMLElement>('input:checked') ??\n      this.root.querySelector<HTMLElement>('input');\n    focusTarget?.focus();\n  }\n\n  close(): void {\n    this.root.remove();\n  }\n}\n","import { TextEditor } from './TextEditor';\nimport { DropDownEditor } from './DropDownEditor';\nimport { RadioEditor } from './RadioEditor';\nimport { Column } from '../models/Column';\nimport { DataMapEditor } from '../models/DataMapEditor';\nimport { DataView } from '../data/DataView';\nimport { LayoutEngine } from '../virtualization/LayoutEngine';\nimport { CellAddress } from '../models/Cell';\nimport { UndoStack } from '../commands/UndoStack';\nimport { EditAction } from '../commands/EditAction';\n\nexport interface EditorDeps {\n  /** The scrolling cells panel. The editor lives here so it tracks the cell while scrolling. */\n  cells: HTMLElement;\n  layout: LayoutEngine;\n  /** Current vertical scroll offset; rows in the pinned body are placed relative to it. */\n  scrollTop: () => number;\n  data: DataView;\n  columns: Column[];\n  undo: UndoStack;\n  onApplied: () => void;\n  /** Return false to prevent the cell from entering edit mode. */\n  onBeginning?: (cell: CellAddress) => boolean;\n  onStart: (cell: CellAddress) => void;\n  /** Return false to reject the new value before it is committed. */\n  onEnding?: (cell: CellAddress, value: unknown) => boolean;\n  /** Called after a new value was committed to the row. */\n  onEnded?: (cell: CellAddress, value: unknown) => void;\n  onEnd: (cell: CellAddress) => void;\n}\n\n/** The common shape every cell editor implements so the manager can swap them. */\ninterface CellEditor {\n  open(parent: HTMLElement, column: Column, item: Record<string, unknown>, rect: DOMRect): void;\n  close(): void;\n}\n\n/** Begins, commits, and cancels cell edits; commits run through the undo stack. */\nexport class EditorManager {\n  private text: TextEditor;\n  private dropdown: DropDownEditor;\n  private radio: RadioEditor;\n  private active: CellEditor | null = null;\n  private editing: CellAddress | null = null;\n\n  constructor(private deps: EditorDeps) {\n    const commit = (value: string) => this.commit(value);\n    const cancel = () => this.cancel();\n    this.text = new TextEditor(commit, cancel);\n    this.dropdown = new DropDownEditor(commit, cancel);\n    this.radio = new RadioEditor(commit, cancel);\n  }\n\n  get isEditing(): boolean {\n    return this.editing != null;\n  }\n\n  /** Flip a Boolean cell's value through the undo stack. Returns true if handled. */\n  toggleBoolean(cell: CellAddress): boolean {\n    const column = this.deps.columns[cell.col];\n    if (!column || !column.editable || column.dataType !== 'Boolean') return false;\n    const item = this.deps.data.item(cell.row);\n    const oldValue = column.getValue(item) === true;\n    this.deps.undo.push(\n      new EditAction(this.deps.data, column, cell.row, oldValue, !oldValue, this.deps.onApplied),\n    );\n    this.deps.data.applyEdit(item, () => column.setValue(item, !oldValue));\n    this.deps.onApplied();\n    return true;\n  }\n\n  begin(cell: CellAddress): void {\n    const column = this.deps.columns[cell.col];\n    if (!column || !column.editable || column.dataType === 'Boolean' || this.editing) return;\n    if (this.deps.onBeginning && !this.deps.onBeginning(cell)) return; // a handler canceled it\n\n    const rect = this.cellRect(cell);\n    this.editing = cell;\n    this.active = this.editorFor(column);\n    this.active.open(this.deps.cells, column, this.deps.data.item(cell.row), rect);\n    this.deps.onStart(cell);\n  }\n\n  private commit(value: string): void {\n    const cell = this.editing;\n    if (!cell) return;\n    this.editing = null;\n    this.active?.close();\n    this.active = null;\n\n    const column = this.deps.columns[cell.col];\n    const item = this.deps.data.item(cell.row);\n    const oldValue = column.getValue(item);\n    const newValue = column.parse(value);\n    // Commit only when the value changed and no handler rejects it.\n    if (newValue !== oldValue && (!this.deps.onEnding || this.deps.onEnding(cell, newValue))) {\n      this.deps.undo.push(\n        new EditAction(this.deps.data, column, cell.row, oldValue, newValue, this.deps.onApplied),\n      );\n      this.deps.data.applyEdit(item, () => column.setValue(item, newValue));\n      this.deps.onApplied();\n      this.deps.onEnded?.(cell, newValue);\n    }\n    this.deps.onEnd(cell);\n  }\n\n  private cancel(): void {\n    const cell = this.editing;\n    if (!cell) return;\n    this.editing = null;\n    this.active?.close();\n    this.active = null;\n    this.deps.onEnd(cell);\n  }\n\n  private editorFor(column: Column): CellEditor {\n    if (!column.dataMap) return this.text;\n    if (column.dataMapEditor === DataMapEditor.RadioButtons) return this.radio;\n    return this.dropdown; // DropDownList, AutoComplete, and Menu share the in-cell dropdown\n  }\n\n  // Position in the pinned cells panel, matching how rows are placed: the row's\n  // absolute top minus the current scroll offset. The browser flips the native\n  // dropdown/calendar up or down on its own.\n  private cellRect(cell: CellAddress): DOMRect {\n    return new DOMRect(\n      this.deps.layout.getColLeft(cell.col),\n      this.deps.layout.getRowTop(cell.row) - this.deps.scrollTop(),\n      this.deps.layout.getColWidth(cell.col),\n      this.deps.layout.getRowHeight(cell.row),\n    );\n  }\n}\n","import { CellRange, makeRange } from './Cell';\n\n/** What a merge manager can ask about the grid while deciding a cell's span. */\nexport interface MergeQuery {\n  row: number;\n  col: number;\n  rowCount: number;\n  colCount: number;\n  /** The raw value of any cell, for comparing neighbours. */\n  value(row: number, col: number): unknown;\n  /** Whether a column opts into merging. */\n  mergeableCol(col: number): boolean;\n}\n\n/**\n * Returns the range a cell belongs to, or null when it stands alone. Return the\n * same range for every cell inside it. Only spans larger than a single cell are\n * meaningful — return null for singletons.\n */\nexport type MergeManager = (q: MergeQuery) => CellRange | null;\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n  if (a === b) return true;\n  if (a == null || b == null) return false;\n  return String(a) === String(b);\n}\n\n/**\n * The default, content-driven manager: in a mergeable column, a run of adjacent\n * rows with equal values merges into one vertical span.\n */\nexport const contentMerge: MergeManager = (q) => {\n  if (!q.mergeableCol(q.col)) return null;\n  const v = q.value(q.row, q.col);\n  if (v == null || v === '') return null;\n\n  let top = q.row;\n  let bottom = q.row;\n  while (top - 1 >= 0 && sameValue(q.value(top - 1, q.col), v)) top--;\n  while (bottom + 1 < q.rowCount && sameValue(q.value(bottom + 1, q.col), v)) bottom++;\n  if (top === bottom) return null;\n  return makeRange(top, q.col, bottom, q.col);\n};\n","import { GridOptions, resolveOptions } from './GridOptions';\nimport { GridState } from './GridState';\nimport { GridViewport } from './GridViewport';\nimport { Column, ColumnDef } from '../models/Column';\nimport { ColumnGroup, ColumnGroupDef, ColumnGroupNode } from '../models/ColumnGroup';\nimport { buildColumnGroups, buildColumnGroupLayout } from '../data/buildColumnGroups';\nimport { CellAddress, CellRange } from '../models/Cell';\nimport { DataView } from '../data/DataView';\nimport { CollectionView } from '../data/CollectionView';\nimport { SortDescription } from '../models/SortDescription';\nimport { PropertyGroupDescription } from '../models/GroupDescription';\nimport { LayoutEngine } from '../virtualization/LayoutEngine';\nimport { ViewportRenderer } from '../rendering/ViewportRenderer';\nimport { RowRenderer } from '../rendering/RowRenderer';\nimport { HeaderRenderer } from '../rendering/HeaderRenderer';\nimport { ColumnGroupRenderer } from '../rendering/ColumnGroupRenderer';\nimport { RowHeaderRenderer } from '../rendering/RowHeaderRenderer';\nimport { CellRenderer } from '../rendering/CellRenderer';\nimport { Renderer } from '../rendering/Renderer';\nimport { RenderContext } from '../rendering/RenderContext';\nimport { ScrollManager } from '../scrolling/ScrollManager';\nimport { SelectionModel, SelectionMode, GridBounds } from '../selection/SelectionModel';\nimport { EventBus, EventHandler } from '../events/EventBus';\nimport { GridEvents } from '../events/GridEvents';\nimport { MouseHandler } from '../events/MouseHandler';\nimport { KeyboardHandler, NavAction } from '../events/KeyboardHandler';\nimport { ColumnResizer } from '../events/ColumnResizer';\nimport { ColumnDragger } from '../events/ColumnDragger';\nimport { ClipboardHandler } from '../events/ClipboardHandler';\nimport { ExportManager, ExportResult } from '../export/ExportManager';\nimport { ExportOptions, ExportData } from '../export/types';\nimport { GroupPanel, GroupChip } from '../rendering/GroupPanel';\nimport { GroupHeaderTemplate } from '../rendering/GroupHeader';\nimport { FilterModel } from '../data/FilterModel';\nimport { FilterEditor } from '../rendering/FilterEditor';\nimport { UndoStack } from '../commands/UndoStack';\nimport { ResizeColumnAction } from '../commands/ResizeColumnAction';\nimport { EditAction } from '../commands/EditAction';\nimport { BatchAction } from '../commands/BatchAction';\nimport { MoveColumnAction, moveColumn } from '../commands/MoveColumnAction';\nimport { EditorManager } from '../editing/EditorManager';\nimport { MergeManager, contentMerge } from '../models/MergeManager';\nimport { GridStateSnapshot, ColumnGroupStateSnapshot } from '../models/GridStateSnapshot';\nimport { clamp } from '../utils/Math';\n\ntype Row = Record<string, unknown>;\n\n// Event names whose payload carries a `cancel` flag (the \"-ing\"/before events).\ntype CancelableEvent = {\n  [K in keyof GridEvents]: GridEvents[K] extends { cancel: boolean } ? K : never;\n}[keyof GridEvents];\n\nconst GROUP_PANEL_HEIGHT = 40;\n\n// Serialize a resolved column-group node back into a plain def, preserving\n// nesting and collapse state. A leaf becomes its binding string (the shorthand\n// form), a group becomes a def object with recursively-serialized children.\nfunction nodeToDef(node: ColumnGroupNode): string | ColumnGroupDef {\n  if (node.kind === 'leaf') return node.binding;\n  return groupToDef(node);\n}\n\nfunction groupToDef(group: ColumnGroup): ColumnGroupDef {\n  return {\n    header: group.header,\n    key: group.key,\n    collapsed: group.collapsed,\n    collapsible: group.collapsible,\n    collapseTo: group.collapseTo,\n    columns: group.children.map(nodeToDef),\n  };\n}\n\n// Serialize a group subtree for persistence. Leaves become binding strings,\n// subgroups nest recursively — so collapse state round-trips at every level.\nfunction groupToSnapshot(group: ColumnGroup): ColumnGroupStateSnapshot {\n  return {\n    key: group.key,\n    header: group.header,\n    collapsed: group.collapsed,\n    collapseTo: group.collapseTo,\n    columns: group.children.map((child) =>\n      child.kind === 'leaf' ? child.binding : groupToSnapshot(child),\n    ),\n  };\n}\n\n/**\n * The grid facade. Constructs and owns every subsystem, drives the\n * scroll/resize render loop, and exposes the public API.\n */\nexport class Grid {\n  private host: HTMLElement;\n  private state = new GridState();\n  private data: DataView;\n  /** The authored columns in stable order, including any currently hidden by a collapsed group. */\n  private allColumns: Column[];\n  /** The visible columns (`allColumns` minus hidden). Everything indexed by column reads this. */\n  private columns: Column[];\n  private rowHeight: number;\n  private headerHeight: number;\n  private showRowHeader: boolean;\n\n  private layout: LayoutEngine;\n  private viewport: GridViewport;\n  private viewportRenderer: ViewportRenderer;\n  private rowRenderer: RowRenderer;\n  private headerRenderer: HeaderRenderer;\n  private columnGroupRenderer?: ColumnGroupRenderer;\n  private rowHeaderRenderer: RowHeaderRenderer;\n  private renderer: Renderer;\n  private scroll: ScrollManager;\n  private resizeObserver?: ResizeObserver;\n\n  private selectionModel = new SelectionModel();\n  private events = new EventBus<GridEvents>();\n  private mouse: MouseHandler;\n  private keyboard: KeyboardHandler;\n  private resizer: ColumnResizer;\n  private dragger?: ColumnDragger;\n  private clipboard?: ClipboardHandler;\n  private exportManager: ExportManager;\n  private groupPanel?: GroupPanel;\n  private groupHeaderTemplate?: GroupHeaderTemplate;\n  /** Active multi-level column-header groups, in authored order. Empty when none. */\n  private columnGroupList: ColumnGroup[] = [];\n  /** Number of header rows the group band shows (deepest group nesting). */\n  private columnGroupDepth = 0;\n  /** Height of the group-header row (only shown when there are column groups). */\n  private groupHeaderRowHeight: number;\n  private rowClass?: RenderContext['rowClass'];\n  private rowStyle?: RenderContext['rowStyle'];\n  private mergeManager?: MergeManager;\n  private anyMergeable = false;\n  private filterModel?: FilterModel;\n  private filterEditor?: FilterEditor;\n  private maxGroups: number;\n  private allowSorting: boolean;\n  private headerDownX = -1;\n  private undoStack = new UndoStack();\n  private editor: EditorManager;\n  private unsubscribeData: () => void = () => {};\n\n  constructor(host: string | HTMLElement, options: GridOptions) {\n    const el = typeof host === 'string' ? document.querySelector<HTMLElement>(host) : host;\n    if (!el) throw new Error(`apgrid: host element not found for \"${String(host)}\"`);\n    this.host = el;\n\n    const resolved = resolveOptions(options);\n    this.allColumns = resolved.columns;\n    this.columnGroupList = buildColumnGroups(this.allColumns, resolved.columnGroups);\n    this.columns = this.syncHiddenColumns();\n    this.data = new DataView(resolved.view);\n    this.rowHeight = resolved.rowHeight;\n    this.headerHeight = resolved.headerHeight;\n    this.groupHeaderRowHeight = resolved.groupHeaderRowHeight;\n    this.maxGroups = resolved.maxGroups;\n    this.groupHeaderTemplate = resolved.groupHeaderTemplate;\n    this.rowClass = resolved.rowClass;\n    this.rowStyle = resolved.rowStyle;\n    this.mergeManager = resolved.mergeManager;\n    this.anyMergeable = this.allColumns.some((c) => c.allowMerging);\n    this.selectionModel = new SelectionModel(resolved.selectionMode);\n    this.state.alternatingRowStep = resolved.alternatingRowStep;\n    this.state.frozenCols = resolved.frozenColumns;\n    this.state.frozenRows = resolved.frozenRows;\n\n    const showColumnHeader =\n      resolved.headersVisibility === 'All' || resolved.headersVisibility === 'Column';\n    this.showRowHeader =\n      resolved.headersVisibility === 'All' || resolved.headersVisibility === 'Row';\n    const hasColumnGroups = this.columnGroupList.length > 0;\n    // Header depth (rows) is fixed by the authored tree — collapsing hides\n    // columns but never changes how many header rows the band shows.\n    this.columnGroupDepth = this.columnGroupList.reduce((m, g) => Math.max(m, g.depth()), 0);\n\n    this.host.style.setProperty('--apg-row-height', `${this.rowHeight}px`);\n    this.host.style.setProperty('--apg-header-height', `${this.headerHeight}px`);\n    this.host.style.setProperty('--apg-group-header-height', `${this.groupHeaderRowHeight}px`);\n    if (resolved.columnGroupAnimation) this.host.classList.add('apg-animated');\n    this.host.tabIndex = 0;\n\n    this.layout = new LayoutEngine(this.data.length, this.rowHeight, this.columns);\n    this.viewport = new GridViewport(this.state, this.layout);\n\n    this.viewportRenderer = new ViewportRenderer(this.host, {\n      showColumnHeader,\n      showRowHeader: this.showRowHeader,\n      headerHeight: this.headerHeight,\n      rowHeaderWidth: resolved.rowHeaderWidth,\n      showGroupPanel: resolved.groupPanel,\n      groupPanelHeight: GROUP_PANEL_HEIGHT,\n      // The band is as tall as the deepest group nesting requires.\n      columnGroupHeight: this.columnGroupDepth * this.groupHeaderRowHeight,\n    });\n    this.rowRenderer = new RowRenderer(this.viewportRenderer.cells, new CellRenderer());\n    this.headerRenderer = new HeaderRenderer(this.viewportRenderer.headerInner);\n    if (hasColumnGroups && this.viewportRenderer.columnGroupInner) {\n      this.columnGroupRenderer = new ColumnGroupRenderer(\n        this.viewportRenderer.columnGroupInner,\n        (key) => this.toggleColumnGroup(key),\n        this.groupHeaderRowHeight,\n      );\n    }\n    this.rowHeaderRenderer = new RowHeaderRenderer(this.viewportRenderer.rowHeaderInner);\n    this.renderer = new Renderer(\n      this.viewportRenderer,\n      this.rowRenderer,\n      this.headerRenderer,\n      this.rowHeaderRenderer,\n      this.showRowHeader,\n      this.columnGroupRenderer,\n    );\n\n    this.scroll = new ScrollManager(this.viewportRenderer.viewport, () => this.onScroll());\n    this.mouse = new MouseHandler(\n      this.viewportRenderer.viewport,\n      this.layout,\n      (cell, extend, isPress) => this.onSelect(cell, extend, isPress),\n      (cell) => this.onDoubleClick(cell),\n      this.viewportRenderer.gutterLeft,\n      this.viewportRenderer.gutterTop,\n    );\n    this.keyboard = new KeyboardHandler(\n      this.host,\n      (action, extend) => this.onNav(action, extend),\n      (action) => (action === 'undo' ? this.undo() : this.redo()),\n      () => this.onActivate(),\n    );\n    this.resizer = new ColumnResizer(\n      this.viewportRenderer.headerInner,\n      this.layout,\n      () => this.columns,\n      () => this.refresh(),\n      (col, width) => this.resizeColumn(col, width),\n    );\n    if (this.viewportRenderer.groupPanel) {\n      this.groupPanel = new GroupPanel(\n        this.viewportRenderer.groupPanel,\n        {\n          chips: () => this.groupChips(),\n          onRemove: (b) => this.removeGroup(b),\n          onReorder: (from, to) => this.moveGroup(from, to),\n          onToggleSort: (b) => this.sort(b),\n          onSort: (b, dir) => this.sort(b, dir),\n          onExpandAll: () => this.expandAllGroups(),\n          onCollapseAll: () => this.collapseAllGroups(),\n        },\n        resolved.groupPanelOptions,\n      );\n    }\n    // The header dragger also handles dropping a column onto the group bar, so\n    // build it when either column reordering or drag-to-group is enabled, and\n    // gate each behavior on its own flag.\n    const dragToGroup = this.groupPanel != null && resolved.groupPanelOptions.allowDragToGroup;\n    if (resolved.allowColumnReorder || dragToGroup) {\n      const panel = this.groupPanel;\n      this.dragger = new ColumnDragger(\n        this.viewportRenderer.headerInner,\n        this.layout,\n        () => this.columns,\n        resolved.allowColumnReorder ? (from, to) => this.moveColumn(from, to) : () => {},\n        dragToGroup ? () => panel!.hostElement.getBoundingClientRect() : undefined,\n        dragToGroup ? (col) => this.addGroup(this.columns[col]?.binding ?? '') : undefined,\n        dragToGroup ? (active) => panel!.highlight(active) : undefined,\n      );\n    }\n    this.allowSorting = resolved.allowSorting;\n    const header = this.viewportRenderer.headerInner;\n    header.addEventListener('mousedown', this.onHeaderMouseDown);\n    header.addEventListener('click', this.onHeaderClick);\n\n    if (this.columns.some((c) => c.filterable)) {\n      this.filterModel = new FilterModel(this.data.collectionView);\n      this.filterEditor = new FilterEditor();\n    }\n\n    this.editor = new EditorManager({\n      cells: this.viewportRenderer.cells,\n      layout: this.layout,\n      scrollTop: () => this.viewportRenderer.viewport.scrollTop,\n      data: this.data,\n      columns: this.columns,\n      undo: this.undoStack,\n      onApplied: () => this.draw(),\n      onBeginning: (cell) => !this.emitCancel('beginningEdit', { row: cell.row, col: cell.col }),\n      onStart: (cell) => this.events.emit('cellEditStart', cell),\n      onEnding: (cell, value) =>\n        !this.emitCancel('cellEditEnding', { row: cell.row, col: cell.col, value }),\n      onEnded: (cell, value) =>\n        this.events.emit('cellEditEnded', { row: cell.row, col: cell.col, value }),\n      onEnd: (cell) => this.events.emit('cellEditEnd', cell),\n    });\n    this.undoStack.onStateChanged = () =>\n      this.events.emit('undoStackChanged', { canUndo: this.canUndo, canRedo: this.canRedo });\n\n    if (resolved.allowClipboard) {\n      this.clipboard = new ClipboardHandler(this.host, {\n        isEditing: () => this.editor.isEditing,\n        getClip: () => this.copyForClipboard(),\n        applyClip: (text) => this.setClipString(text),\n      });\n    }\n\n    this.exportManager = new ExportManager({\n      columns: () => this.columns,\n      source: () => this.data,\n      fullSource: () => this.fullExportSource(),\n      selection: () => this.selection,\n      headerGroups: () => this.exportHeaderGroups(),\n      merge: () => this.mergeLookup(),\n      filterable: () => this.filterModel != null,\n      activeFilters: () => this.activeExportFilters(),\n      host: () => this.host,\n      onExporting: (opts) =>\n        !this.emitCancel('exporting', {\n          format: opts.format ?? 'csv',\n          fileName: `${opts.fileName ?? 'export'}.${opts.format ?? 'csv'}`,\n        }),\n      onExported: (opts) =>\n        this.events.emit('exported', {\n          format: opts.format ?? 'csv',\n          fileName: `${opts.fileName ?? 'export'}.${opts.format ?? 'csv'}`,\n        }),\n    });\n\n    this.unsubscribeData = this.data.collectionView.on('collectionChanged', (e) => {\n      // Edits keep the same rows, so only redraw; add/remove/reset change totals.\n      if (e.action === 'change') this.draw();\n      else this.refresh();\n      this.events.emit('collectionChanged', { action: e.action });\n    });\n\n    if (typeof ResizeObserver !== 'undefined') {\n      this.resizeObserver = new ResizeObserver(() => this.measure());\n      this.resizeObserver.observe(this.host);\n    }\n\n    this.syncViewportSize();\n    this.refresh();\n  }\n\n  /** Subscribe to a grid event. Returns a function that removes the handler. */\n  on<K extends keyof GridEvents>(type: K, handler: EventHandler<GridEvents[K]>): () => void {\n    return this.events.on(type, handler);\n  }\n\n  /** The collection view behind the grid. Use it to read tracked changes or add/remove rows. */\n  get collectionView(): CollectionView {\n    return this.data.collectionView;\n  }\n\n  /** The active (current) cell, or null when nothing is selected. */\n  get selectedCell(): CellAddress | null {\n    return this.selectionModel.getActive();\n  }\n\n  /** The highlighted rectangle for the current selection mode, or null. */\n  get selection(): CellRange | null {\n    return this.selectionModel.getRange(this.bounds());\n  }\n\n  get selectionMode(): SelectionMode {\n    return this.selectionModel.getMode();\n  }\n\n  set selectionMode(mode: SelectionMode) {\n    if (!this.selectionModel.setMode(mode)) return;\n    this.syncSelectionState();\n    this.draw();\n    this.events.emit('selectionChanged', this.selectionModel.getActive());\n  }\n\n  select(row: number, col: number, extend = false): void {\n    if (this.selectionModel.getMode() === 'None') return;\n    const cell = {\n      row: clamp(row, 0, this.layout.rowCount - 1),\n      col: clamp(col, 0, this.layout.colCount - 1),\n    };\n    this.applyMove(cell, extend);\n    this.scrollIntoView(cell);\n  }\n\n  /** Recompute totals and redraw. Call after the data or columns change. */\n  refresh(): void {\n    this.data.refreshGroups();\n    // Re-derive visible columns from the authored list in case group membership\n    // or the authored order changed since the last refresh.\n    this.columns = this.syncHiddenColumns();\n    this.layout.setColumns(this.columns);\n    this.layout.setRowCount(this.data.length);\n    this.renderer.resize(this.context());\n    this.syncFrozen();\n    this.draw();\n  }\n\n  /** Redraw the current window without recomputing totals. */\n  invalidate(): void {\n    this.draw();\n  }\n\n  /** Number of columns pinned to the left. */\n  get frozenColumns(): number {\n    return this.state.frozenCols;\n  }\n\n  /** Number of rows pinned to the top. */\n  get frozenRows(): number {\n    return this.state.frozenRows;\n  }\n\n  /** Pin the first `count` columns to the left. Pass 0 to unfreeze. */\n  freezeColumns(count: number): void {\n    const c = clamp(Math.floor(count), 0, this.layout.colCount);\n    if (c === this.state.frozenCols) return;\n    if (this.emitCancel('freezingColumns', { count: c })) return;\n    this.state.frozenCols = c;\n    this.syncFrozen();\n    this.draw();\n    this.events.emit('frozenColumnsChanged', { count: c });\n  }\n\n  /** Pin the first `count` rows to the top. Pass 0 to unfreeze. */\n  freezeRows(count: number): void {\n    const c = clamp(Math.floor(count), 0, this.layout.rowCount);\n    if (c === this.state.frozenRows) return;\n    if (this.emitCancel('freezingRows', { count: c })) return;\n    this.state.frozenRows = c;\n    this.syncFrozen();\n    this.draw();\n    this.events.emit('frozenRowsChanged', { count: c });\n  }\n\n  // Clamp the freeze counts to the current grid size and size the pinned panels.\n  private syncFrozen(): void {\n    const cols = clamp(this.state.frozenCols, 0, this.layout.colCount);\n    const rows = clamp(this.state.frozenRows, 0, this.layout.rowCount);\n    this.state.frozenCols = cols;\n    this.state.frozenRows = rows;\n    this.viewportRenderer.setFrozen(\n      this.layout.frozenColsWidth(cols),\n      this.layout.frozenRowsHeight(rows),\n    );\n  }\n\n  /** Capture the current column layout, sort, filters, grouping, freeze, selection, and scroll. */\n  toJSON(): GridStateSnapshot {\n    const active = this.selectionModel.getActive();\n    return {\n      version: 1,\n      // Persist the full authored order/width, including columns currently hidden\n      // by a collapsed group, so restore round-trips even while collapsed.\n      columns: this.allColumns.map((c) => ({ binding: c.binding, width: c.width })),\n      sort: this.state.sort\n        ? {\n            binding: this.columns[this.state.sort.col].binding,\n            ascending: this.state.sort.ascending,\n          }\n        : null,\n      filters: this.filterModel\n        ? this.allColumns\n            .map((c) => this.filterModel!.get(c))\n            .filter((f) => f.isActive)\n            .map((f) => ({\n              binding: f.column.binding,\n              values: f.values ? [...f.values] : null,\n              condition: f.condition ? { ...f.condition } : null,\n            }))\n        : [],\n      groups: this.groupDescriptions.map((g) => g.property),\n      collapsedGroups: this.data.collapsedGroups(),\n      columnGroups: this.columnGroupList.map((g) => groupToSnapshot(g)),\n      frozen: { columns: this.state.frozenCols, rows: this.state.frozenRows },\n      selectionMode: this.selectionModel.getMode(),\n      activeCell: active ? { row: active.row, col: active.col } : null,\n      scroll: {\n        top: this.viewportRenderer.viewport.scrollTop,\n        left: this.viewportRenderer.viewport.scrollLeft,\n      },\n    };\n  }\n\n  /** Restore a snapshot from {@link toJSON}. Unknown bindings are ignored. */\n  loadJSON(snapshot: GridStateSnapshot): void {\n    if (!snapshot || snapshot.version !== 1) return;\n\n    if (snapshot.columns) this.applyColumnState(snapshot.columns);\n\n    // Restore column groups (and their collapse state) after the column order is\n    // settled, so membership resolves against the final bindings. The snapshot\n    // tree is structurally a ColumnGroupDef tree, so it feeds the resolver\n    // directly.\n    if (snapshot.columnGroups) {\n      this.columnGroupList = buildColumnGroups(\n        this.allColumns,\n        snapshot.columnGroups as ColumnGroupDef[],\n      );\n      this.columnGroupDepth = this.columnGroupList.reduce((m, g) => Math.max(m, g.depth()), 0);\n      this.columns = this.syncHiddenColumns();\n    }\n\n    // Grouping first, then filters and sort, so the collapse keys line up.\n    if (snapshot.groups) this.groupBy(...snapshot.groups);\n\n    if (this.filterModel) {\n      for (const c of this.allColumns) this.filterModel.get(c).clear();\n      for (const f of snapshot.filters ?? []) {\n        const column = this.allColumns.find((c) => c.binding === f.binding);\n        if (!column) continue;\n        const cf = this.filterModel.get(column);\n        cf.values = f.values ? new Set(f.values) : null;\n        cf.condition = f.condition ? { ...f.condition } : null;\n      }\n      this.filterModel.apply();\n      this.syncActiveFilters();\n    }\n\n    if (snapshot.sort === null) this.clearSort();\n    else if (snapshot.sort) this.sort(snapshot.sort.binding, snapshot.sort.ascending);\n\n    if (snapshot.frozen) {\n      this.freezeColumns(snapshot.frozen.columns);\n      this.freezeRows(snapshot.frozen.rows);\n    }\n\n    this.refresh();\n\n    if (snapshot.collapsedGroups) this.data.setCollapsedGroups(snapshot.collapsedGroups);\n\n    if (snapshot.selectionMode) this.selectionMode = snapshot.selectionMode as SelectionMode;\n    if (snapshot.activeCell) this.select(snapshot.activeCell.row, snapshot.activeCell.col);\n\n    this.refresh();\n\n    if (snapshot.scroll) {\n      this.viewportRenderer.viewport.scrollTop = snapshot.scroll.top;\n      this.viewportRenderer.viewport.scrollLeft = snapshot.scroll.left;\n      this.draw();\n    }\n  }\n\n  // Reorder columns to match the saved bindings and restore their widths. Any\n  // columns missing from the snapshot keep their current relative order at the end.\n  private applyColumnState(saved: { binding: string; width: number }[]): void {\n    const byBinding = new Map(this.allColumns.map((c) => [c.binding, c]));\n    const ordered: Column[] = [];\n    for (const s of saved) {\n      const col = byBinding.get(s.binding);\n      if (!col) continue;\n      col.width = s.width;\n      ordered.push(col);\n      byBinding.delete(s.binding);\n    }\n    for (const col of this.allColumns) if (byBinding.has(col.binding)) ordered.push(col);\n    this.allColumns = ordered;\n    this.columns = this.syncHiddenColumns();\n  }\n\n  setData(items: Row[]): void {\n    this.data.setItems(items);\n    this.refresh();\n  }\n\n  addColumn(def: ColumnDef, index?: number): void {\n    const col = new Column(def);\n    // `index` is a visible-column position; translate it to the authored array.\n    if (index == null) this.allColumns.push(col);\n    else {\n      const at = this.toAllColumnsIndex(index);\n      this.allColumns.splice(at < 0 ? this.allColumns.length : at, 0, col);\n    }\n    this.refresh();\n  }\n\n  removeColumn(index: number): void {\n    const at = this.toAllColumnsIndex(index);\n    if (at < 0) return;\n    this.allColumns.splice(at, 1);\n    this.refresh();\n  }\n\n  scrollTo(row: number, col?: number): void {\n    const vp = this.viewportRenderer.viewport;\n    vp.scrollTop = this.layout.getRowTop(row);\n    if (col != null) vp.scrollLeft = this.layout.getColLeft(col);\n    this.onScroll();\n  }\n\n  get canUndo(): boolean {\n    return this.undoStack.canUndo;\n  }\n\n  get canRedo(): boolean {\n    return this.undoStack.canRedo;\n  }\n\n  undo(): void {\n    this.undoStack.undo();\n  }\n\n  redo(): void {\n    this.undoStack.redo();\n  }\n\n  /** Begin editing a cell (no-op if the column isn't editable or the row is a group). */\n  editCell(row: number, col: number): void {\n    if (this.data.rowType(row) === 'group') return;\n    this.editor.begin({ row, col });\n  }\n\n  /** Set a cell's value programmatically. Recorded on the undo stack. */\n  setCellValue(row: number, col: number, value: unknown): void {\n    const column = this.columns[col];\n    if (!column || !column.editable) return;\n    const item = this.data.item(row);\n    if (item == null) return;\n    const oldValue = column.getValue(item);\n    if (value === oldValue) return;\n    this.undoStack.push(new EditAction(this.data, column, row, oldValue, value, () => this.draw()));\n    this.data.applyEdit(item, () => column.setValue(item, value));\n    this.draw();\n  }\n\n  /**\n   * Get a range of cells as tab-delimited text (rows separated by newlines),\n   * suitable for the clipboard or a spreadsheet. Defaults to the current selection.\n   */\n  getClipString(range?: CellRange): string {\n    const rng = range ?? this.selection;\n    if (!rng) return '';\n    const lines: string[] = [];\n    for (let row = rng.topRow; row <= rng.bottomRow; row++) {\n      if (this.data.rowType(row) === 'group') continue;\n      const item = this.data.item(row) as Row;\n      const cells: string[] = [];\n      for (let col = rng.leftCol; col <= rng.rightCol; col++) {\n        cells.push(item ? this.columns[col].format(item) : '');\n      }\n      lines.push(cells.join('\\t'));\n    }\n    return lines.join('\\n');\n  }\n\n  /**\n   * Parse tab-delimited text and write it into the grid starting at the top-left\n   * of `range` (defaults to the active cell). Read-only and calculated cells are\n   * skipped. The whole paste is a single undo step.\n   */\n  setClipString(text: string, range?: CellRange): void {\n    const anchor = range ?? this.selection;\n    if (!anchor) return;\n\n    const pasting = { text, cancel: false };\n    this.events.emit('pasting', pasting);\n    if (pasting.cancel) return;\n\n    const grid = this.parseClip(text);\n    const startRow = anchor.topRow;\n    const startCol = anchor.leftCol;\n    const edits: EditAction[] = [];\n    let lastRow = startRow;\n    let lastCol = startCol;\n\n    for (let r = 0; r < grid.length; r++) {\n      const row = startRow + r;\n      if (row >= this.layout.rowCount) break;\n      const item = this.data.item(row) as Row;\n      if (item == null) continue;\n      for (let c = 0; c < grid[r].length; c++) {\n        const col = startCol + c;\n        if (col >= this.layout.colCount) break;\n        const column = this.columns[col];\n        if (!column.editable || column.isCalculated) continue;\n        const newValue = column.parse(grid[r][c]);\n        const oldValue = column.getValue(item);\n        if (newValue === oldValue) continue;\n        edits.push(new EditAction(this.data, column, row, oldValue, newValue, () => {}));\n        lastRow = Math.max(lastRow, row);\n        lastCol = Math.max(lastCol, col);\n      }\n    }\n\n    if (!edits.length) return;\n    const batch = new BatchAction(edits, () => this.draw());\n    this.undoStack.push(batch);\n    batch.redo(); // apply all edits and redraw once\n\n    const range2: CellRange = {\n      topRow: startRow,\n      leftCol: startCol,\n      bottomRow: lastRow,\n      rightCol: lastCol,\n    };\n    this.events.emit('pasted', { range: range2 });\n  }\n\n  // Build the clipboard string for the current selection, honoring the cancelable\n  // copying/copied events. Returns null when there is nothing to copy.\n  private copyForClipboard(): string | null {\n    const range = this.selection;\n    if (!range) return null;\n    const copying = { range, cancel: false };\n    this.events.emit('copying', copying);\n    if (copying.cancel) return null;\n    const text = this.getClipString(range);\n    this.events.emit('copied', { range });\n    return text;\n  }\n\n  // Split pasted text into a grid of cells. Handles CRLF and a single trailing\n  // newline (spreadsheets usually add one).\n  private parseClip(text: string): string[][] {\n    const trimmed = text.replace(/\\r\\n/g, '\\n').replace(/\\n$/, '');\n    return trimmed.split('\\n').map((line) => line.split('\\t'));\n  }\n\n  /**\n   * Export the grid to a file. `options.format` selects the output\n   * ('csv' | 'xlsx' | 'pdf', default 'csv'); other options control the file\n   * name, whether to export all rows or just the selection, which columns to\n   * include, group-header inclusion, and whether to download. Returns the\n   * artifact + metadata, or null if the `exporting` event was canceled.\n   */\n  export(options?: ExportOptions): ExportResult | null {\n    return this.exportManager.export(options);\n  }\n\n  /**\n   * Export asynchronously: rows are built in chunks that yield to the event\n   * loop so the page stays responsive on large datasets. Reports progress via\n   * `options.onProgress`, shows the built-in overlay when\n   * `options.showProgress` is true, and honors `options.signal` for\n   * cancellation. Resolves to the artifact (or null if canceled).\n   */\n  exportAsync(options?: ExportOptions): Promise<ExportResult | null> {\n    return this.exportManager.exportAsync(options);\n  }\n\n  /** Build the format-agnostic export payload without rendering or downloading. */\n  exportData(options?: ExportOptions): ExportData {\n    return this.exportManager.buildData(options);\n  }\n\n  /** Register a custom export format (id + extension + mime + render). */\n  registerExportFormat = (...args: Parameters<ExportManager['registerFormat']>): void =>\n    this.exportManager.registerFormat(...args);\n\n  /**\n   * An export source over the FULL, unfiltered, ungrouped data — every row of\n   * the collection view's source array. Used when exporting a native Excel\n   * AutoFilter so the file holds all rows for Excel to filter.\n   */\n  private fullExportSource(): {\n    length: number;\n    grouped: boolean;\n    item(i: number): Record<string, unknown> | undefined;\n    rowType(): 'group' | 'data';\n    groupRow(): null;\n  } {\n    const items = this.data.collectionView.sourceCollection as Record<string, unknown>[];\n    return {\n      length: items.length,\n      grouped: false,\n      item: (i) => items[i],\n      rowType: () => 'data',\n      groupRow: () => null,\n    };\n  }\n\n  /**\n   * Active value-based column filters as `{ binding, values }`, for the exported\n   * AutoFilter. Only checkbox (value-set) filters are carried; operator/condition\n   * filters are omitted (Excel would need custom-filter encoding).\n   */\n  private activeExportFilters(): { binding: string; values: string[] }[] {\n    if (!this.filterModel) return [];\n    const out: { binding: string; values: string[] }[] = [];\n    for (const c of this.allColumns) {\n      const f = this.filterModel.get(c);\n      if (f.isActive && f.values && f.values.size > 0) {\n        out.push({ binding: c.binding, values: [...f.values] });\n      }\n    }\n    return out;\n  }\n\n  /** Resolve the current column-group bands into export header spans. */\n  private exportHeaderGroups(): {\n    spans: {\n      header: string;\n      startCol: number;\n      endCol: number;\n      row: number;\n      rowSpan: number;\n    }[];\n    rows: number;\n  } {\n    if (this.columnGroupList.length === 0) return { spans: [], rows: 0 };\n    const layout = buildColumnGroupLayout(this.columns, this.columnGroupList);\n    const spans = layout.cells\n      .filter((c) => c.group != null)\n      .map((c) => ({\n        header: c.group!.header,\n        startCol: c.startCol,\n        endCol: c.endCol,\n        row: c.row,\n        rowSpan: c.rowSpan,\n      }));\n    return { spans, rows: layout.rows };\n  }\n\n  /** Resize a column. Recorded on the undo stack. */\n  resizeColumn(index: number, width: number): void {\n    const column = this.columns[index];\n    if (!column || column.width === width) return;\n    if (this.emitCancel('resizingColumn', { col: index, width })) return;\n    this.undoStack.push(new ResizeColumnAction(column, column.width, width, () => this.refresh()));\n    column.width = width;\n    this.refresh();\n    this.events.emit('resizedColumn', { col: index, width });\n  }\n\n  /** Move a column to a new index. Recorded on the undo stack. */\n  moveColumn(from: number, to: number): void {\n    const last = this.columns.length - 1;\n    if (from === to || from < 0 || from > last || to < 0 || to > last) return;\n    if (this.emitCancel('columnReordering', { from, to })) return;\n    // Translate the visible from/to into positions in the authored array, which\n    // is what actually reorders (refresh re-derives the visible list from it).\n    const fromAll = this.toAllColumnsIndex(from);\n    const toAll = this.toAllColumnsIndex(to);\n    if (fromAll < 0 || toAll < 0) return;\n    this.undoStack.push(\n      new MoveColumnAction(this.allColumns, fromAll, toAll, () => this.refresh()),\n    );\n    moveColumn(this.allColumns, fromAll, toAll);\n    this.refresh();\n    this.events.emit('columnReordered', { from, to });\n  }\n\n  // Map a visible-column index to its position in the authored `allColumns`\n  // array. Returns -1 when out of range. With no hidden columns the two spaces\n  // coincide, so this is the identity in the common case.\n  private toAllColumnsIndex(visibleIndex: number): number {\n    const col = this.columns[visibleIndex];\n    if (!col) return -1;\n    return this.allColumns.indexOf(col);\n  }\n\n  /** Sort by a column's binding. Omit `ascending` to toggle, or pass null to clear. */\n  sort(binding: string, ascending?: boolean | null): void {\n    const col = this.columns.findIndex((c) => c.binding === binding);\n    if (col >= 0) this.sortByColumn(col, ascending);\n  }\n\n  // Cycle a column's sort: unsorted -> ascending -> descending -> unsorted.\n  private sortByColumn(col: number, ascending?: boolean | null): void {\n    const column = this.columns[col];\n    if (!column || !column.binding || column.isCalculated) return;\n\n    // Resolve the target direction (null = clear) before announcing it.\n    let target: boolean | null;\n    if (ascending === null) {\n      target = null;\n    } else if (ascending != null) {\n      target = ascending;\n    } else {\n      const cur = this.state.sort;\n      if (cur && cur.col === col) target = cur.ascending ? false : null;\n      else target = true;\n    }\n\n    if (this.emitCancel('sortingColumn', { col, binding: column.binding, ascending: target })) {\n      return;\n    }\n\n    if (target === null) {\n      this.clearSort();\n    } else {\n      this.state.sort = { col, ascending: target };\n      this.data.collectionView.sortConverter = this.sortConverter;\n      this.data.collectionView.sortDescriptions = [new SortDescription(column.binding, target)];\n      this.groupPanel?.render();\n    }\n    this.events.emit('sortedColumn', { col, binding: column.binding, ascending: target });\n  }\n\n  private clearSort(): void {\n    this.state.sort = null;\n    this.data.collectionView.sortDescriptions = [];\n    this.groupPanel?.render();\n  }\n\n  /** Remove every column filter and show all rows. */\n  clearFilters(): void {\n    if (!this.filterModel) return;\n    this.filterModel.clearAll();\n    this.syncActiveFilters();\n    this.refresh();\n    this.events.emit('filterChanged', { activeBindings: [] });\n  }\n\n  // Open the filter popup for a column, anchored to its header filter button.\n  private openFilter(col: number, anchor: DOMRect): void {\n    const column = this.columns[col];\n    if (!this.filterModel || !this.filterEditor || !column?.filterable) return;\n    const filter = this.filterModel.get(column);\n    const cur = this.state.sort;\n    this.filterEditor.open(anchor, {\n      column,\n      values: this.filterModel.distinctValues(column),\n      filter,\n      showSort: this.allowSorting && !!column.binding && !column.isCalculated,\n      sort: cur && cur.col === col ? (cur.ascending ? 'asc' : 'desc') : null,\n      onSort: (dir) => this.sortByColumn(col, dir),\n      onApply: (draft) => {\n        if (this.emitCancel('filtering', { binding: column.binding })) return;\n        filter.values = draft.values;\n        filter.condition = draft.condition;\n        this.filterModel!.apply();\n        this.afterFilterChanged();\n      },\n      onClear: () => {\n        if (this.emitCancel('filtering', { binding: column.binding })) return;\n        filter.clear();\n        this.filterModel!.apply();\n        this.afterFilterChanged();\n      },\n    });\n  }\n\n  private afterFilterChanged(): void {\n    this.syncActiveFilters();\n    this.refresh();\n    this.events.emit('filterChanged', {\n      activeBindings: this.columns\n        .filter((c) => this.filterModel!.isActive(c.binding))\n        .map((c) => c.binding),\n    });\n  }\n\n  // Rebuild the set of column indices that show an active filter glyph.\n  private syncActiveFilters(): void {\n    const active = new Set<number>();\n    if (this.filterModel) {\n      this.columns.forEach((c, i) => {\n        if (c.filterable && this.filterModel!.isActive(c.binding)) active.add(i);\n      });\n    }\n    this.state.activeFilters = active;\n  }\n\n  // Sort data-mapped columns by their display text rather than the raw key.\n  private readonly sortConverter = (sd: SortDescription, _item: Row, value: unknown): unknown => {\n    const column = this.columns.find((c) => c.binding === sd.property);\n    if (column?.dataMap?.sortByDisplayValues) return column.dataMap.getDisplayValue(value);\n    return value;\n  };\n\n  /** The current group-by column bindings, outermost first. */\n  get groupDescriptions(): PropertyGroupDescription[] {\n    return this.data.collectionView.groupDescriptions;\n  }\n\n  /** Replace the grouping with the given column bindings (outermost first). */\n  groupBy(...bindings: string[]): void {\n    const descs = bindings\n      .filter((b) => this.canGroupBy(b))\n      .slice(0, this.maxGroups)\n      .map((b) => new PropertyGroupDescription(b));\n    this.data.collectionView.groupDescriptions = descs;\n    this.afterGroupsChanged();\n  }\n\n  /** Add one more grouping level. Ignores duplicates, calculated columns, and the max. */\n  addGroup(binding: string): void {\n    const cv = this.data.collectionView;\n    if (!this.canGroupBy(binding)) return;\n    if (cv.groupDescriptions.some((g) => g.property === binding)) return;\n    if (cv.groupDescriptions.length >= this.maxGroups) return;\n    cv.groupDescriptions = [...cv.groupDescriptions, new PropertyGroupDescription(binding)];\n    this.afterGroupsChanged();\n  }\n\n  /** Remove the grouping level for a column. */\n  removeGroup(binding: string): void {\n    const cv = this.data.collectionView;\n    const next = cv.groupDescriptions.filter((g) => g.property !== binding);\n    if (next.length === cv.groupDescriptions.length) return;\n    cv.groupDescriptions = next;\n    this.afterGroupsChanged();\n  }\n\n  /** Remove all grouping. */\n  clearGroups(): void {\n    const cv = this.data.collectionView;\n    if (cv.groupDescriptions.length === 0) return;\n    cv.groupDescriptions = [];\n    this.afterGroupsChanged();\n  }\n\n  collapseAllGroups(): void {\n    this.data.collapseAllGroups();\n    this.refreshRows();\n  }\n\n  expandAllGroups(): void {\n    this.data.expandAllGroups();\n    this.refreshRows();\n  }\n\n  private canGroupBy(binding: string): boolean {\n    const col = this.columns.find((c) => c.binding === binding);\n    return !!binding && !!col && !col.isCalculated;\n  }\n\n  private moveGroup(from: number, to: number): void {\n    const cv = this.data.collectionView;\n    const arr = [...cv.groupDescriptions];\n    if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) return;\n    const [moved] = arr.splice(from, 1);\n    arr.splice(to, 0, moved);\n    cv.groupDescriptions = arr;\n    this.afterGroupsChanged();\n  }\n\n  private afterGroupsChanged(): void {\n    this.groupPanel?.render();\n    this.events.emit('groupsChanged', {\n      bindings: this.data.collectionView.groupDescriptions.map((g) => g.property),\n    });\n  }\n\n  private groupChips(): GroupChip[] {\n    const sort = this.state.sort;\n    const sortedBinding = sort ? this.columns[sort.col]?.binding : undefined;\n    return this.data.collectionView.groupDescriptions.map((g) => {\n      const col = this.columns.find((c) => c.binding === g.property);\n      return {\n        binding: g.property,\n        header: col?.header ?? g.property,\n        sort: sortedBinding === g.property ? (sort!.ascending ? 'asc' : 'desc') : null,\n      };\n    });\n  }\n\n  private toggleGroupAt(row: number): void {\n    const gr = this.data.groupRow(row);\n    if (!gr) return;\n    this.host.focus();\n    if (\n      this.emitCancel('groupCollapsedChanging', { pathKey: gr.pathKey, collapsed: !gr.collapsed })\n    ) {\n      return;\n    }\n    this.data.toggleGroup(gr.pathKey);\n    this.refreshRows();\n    this.events.emit('groupCollapsedChanged', { pathKey: gr.pathKey, collapsed: !gr.collapsed });\n  }\n\n  // Rebuild the row totals and redraw after the display rows change (collapse or\n  // expand) without re-arranging the collection view.\n  private refreshRows(): void {\n    this.layout.setRowCount(this.data.length);\n    this.renderer.resize(this.context());\n    this.draw();\n  }\n\n  // ---- Column groups (multi-level header) ------------------------------------\n\n  /** The active column-header groups, in authored order. */\n  get columnGroups(): ColumnGroup[] {\n    return this.columnGroupList;\n  }\n\n  /** Whether column-group headers animate when collapsing/expanding. */\n  get columnGroupAnimation(): boolean {\n    return this.host.classList.contains('apg-animated');\n  }\n\n  set columnGroupAnimation(on: boolean) {\n    this.host.classList.toggle('apg-animated', on);\n  }\n\n  /** Replace all column groups. Pass an empty array to remove grouping entirely. */\n  setColumnGroups(defs: ColumnGroupDef[]): void {\n    this.columnGroupList = buildColumnGroups(this.allColumns, defs);\n    this.applyColumnGroups();\n    this.events.emit('columnGroupsChanged', { keys: this.columnGroupList.map((g) => g.key) });\n  }\n\n  /** Add one column group. Bindings already owned by another group are dropped. */\n  addColumnGroup(def: ColumnGroupDef): void {\n    this.setColumnGroups([...this.columnGroupDefs(), def]);\n  }\n\n  /** Remove the column group with the given key. */\n  removeColumnGroup(key: string): void {\n    const next = this.columnGroupDefs().filter((g) => g.key !== key);\n    if (next.length === this.columnGroupList.length) return;\n    this.setColumnGroups(next);\n  }\n\n  /** Every group in the tree, flattened (top-level groups and all nested ones). */\n  private allGroups(): ColumnGroup[] {\n    const out: ColumnGroup[] = [];\n    for (const g of this.columnGroupList) out.push(...g.descendantGroups());\n    return out;\n  }\n\n  /**\n   * Collapse or expand a column group (at any nesting depth). Omit `collapsed`\n   * to toggle. Collapsing hides the group's descendant columns except its\n   * `collapseTo`; expanding shows them again. Cancelable through the\n   * `columnGroupCollapsing` event.\n   */\n  toggleColumnGroup(key: string, collapsed?: boolean): void {\n    const group = this.allGroups().find((g) => g.key === key);\n    if (!group || !group.collapsible) return;\n    const target = collapsed ?? !group.collapsed;\n    if (target === group.collapsed) return;\n    if (this.emitCancel('columnGroupCollapsing', { key, collapsed: target })) return;\n    group.collapsed = target;\n    this.applyColumnGroups();\n    this.events.emit('columnGroupCollapsedChanged', { key, collapsed: target });\n  }\n\n  /** Collapse every collapsible column group. */\n  collapseAllColumnGroups(): void {\n    this.setColumnGroupsCollapsed(true);\n  }\n\n  /** Expand every column group. */\n  expandAllColumnGroups(): void {\n    this.setColumnGroupsCollapsed(false);\n  }\n\n  private setColumnGroupsCollapsed(collapsed: boolean): void {\n    let changed = false;\n    for (const group of this.allGroups()) {\n      if (!group.collapsible || group.collapsed === collapsed) continue;\n      if (this.emitCancel('columnGroupCollapsing', { key: group.key, collapsed })) continue;\n      group.collapsed = collapsed;\n      changed = true;\n      this.events.emit('columnGroupCollapsedChanged', { key: group.key, collapsed });\n    }\n    if (changed) this.applyColumnGroups();\n  }\n\n  // Snapshot the current group tree back into plain defs, preserving collapse\n  // state and nesting, so add/remove can round-trip it.\n  private columnGroupDefs(): ColumnGroupDef[] {\n    return this.columnGroupList.map((g) => groupToDef(g));\n  }\n\n  // Rebuild each column's `hidden` flag from the current group collapse state and\n  // return the visible-column list. Walk the tree top-down: once inside a\n  // collapsed group, only its `collapseTo` descendant survives — every other\n  // descendant leaf is hidden. An inner collapsed group can't re-show a column\n  // its collapsed ancestor already hid.\n  private syncHiddenColumns(): Column[] {\n    const hidden = new Set<string>();\n    for (const group of this.columnGroupList) this.collectHidden(group, false, null, hidden);\n    for (const col of this.allColumns) col.hidden = hidden.has(col.binding);\n    return this.allColumns.filter((c) => !c.hidden);\n  }\n\n  // Depth-first: `keepBinding` is the one descendant leaf allowed to stay visible\n  // inside the nearest collapsed ancestor (null = none / not yet collapsed).\n  private collectHidden(\n    node: ColumnGroupNode,\n    underCollapsed: boolean,\n    keepBinding: string | null,\n    hidden: Set<string>,\n  ): void {\n    if (node.kind === 'leaf') {\n      if (underCollapsed && node.binding !== keepBinding) hidden.add(node.binding);\n      return;\n    }\n    // Entering this group: if it (or an ancestor) is collapsed, propagate that\n    // state. The outermost collapsed group owns which leaf survives, so keep the\n    // existing keepBinding when already collapsed; otherwise adopt this group's.\n    const nowCollapsed = underCollapsed || node.collapsed;\n    const keep = underCollapsed ? keepBinding : node.collapsed ? node.collapseTo : null;\n    for (const child of node.children) this.collectHidden(child, nowCollapsed, keep, hidden);\n  }\n\n  // Recompute the visible columns after a group changed, rebuild the layout,\n  // keep the active cell in range, and redraw. Parallels refreshRows() on the\n  // column axis.\n  private applyColumnGroups(): void {\n    const hadGroups = this.viewportRenderer.columnGroupInner != null;\n    this.columns = this.syncHiddenColumns();\n    this.layout.setColumns(this.columns);\n    this.clampSelectionToColumns();\n    this.syncFrozen();\n    this.renderer.resize(this.context());\n    // If the group-header band's presence changed and the scaffold can't show\n    // it, the visual gains/loses a row only after a rebuild; for v1 the band is\n    // created up front when any group exists, so just redraw.\n    void hadGroups;\n    this.draw();\n  }\n\n  // After columns shrink (a group collapsed), pull the active cell back into\n  // range so selection never points past the last visible column.\n  private clampSelectionToColumns(): void {\n    const active = this.selectionModel.getActive();\n    if (!active) return;\n    const maxCol = this.layout.colCount - 1;\n    if (maxCol < 0) return;\n    if (active.col > maxCol) {\n      this.selectionModel.moveTo({ row: active.row, col: maxCol }, false);\n      this.syncSelectionState();\n    }\n  }\n\n  dispose(): void {\n    this.unsubscribeData();\n    const header = this.viewportRenderer.headerInner;\n    header.removeEventListener('mousedown', this.onHeaderMouseDown);\n    header.removeEventListener('click', this.onHeaderClick);\n    this.scroll.dispose();\n    this.mouse.dispose();\n    this.keyboard.dispose();\n    this.resizer.dispose();\n    this.dragger?.dispose();\n    this.clipboard?.dispose();\n    this.exportManager.dispose();\n    this.groupPanel?.dispose();\n    this.filterEditor?.close();\n    this.events.clear();\n    this.undoStack.clear();\n    this.resizeObserver?.disconnect();\n    this.rowRenderer.clear();\n    this.rowHeaderRenderer.clear();\n    this.columnGroupRenderer?.clear();\n    this.viewportRenderer.dispose();\n    this.host.removeAttribute('tabindex');\n    this.host.style.removeProperty('--apg-row-height');\n    this.host.style.removeProperty('--apg-header-height');\n    this.host.style.removeProperty('--apg-group-header-height');\n    this.host.classList.remove('apg-animated');\n  }\n\n  private context(): RenderContext {\n    return {\n      layout: this.layout,\n      columns: this.columns,\n      data: this.data,\n      state: this.state,\n      groupHeaderTemplate: this.groupHeaderTemplate,\n      rowClass: this.rowClass,\n      rowStyle: this.rowStyle,\n      merge: this.mergeLookup(),\n      columnGroups: this.columnGroupList,\n    };\n  }\n\n  // Build the per-frame merge lookup, or undefined when merging is off. A custom\n  // manager takes over entirely; otherwise the default content-driven merge runs\n  // for columns that opted in.\n  private mergeLookup(): RenderContext['merge'] {\n    const manager = this.mergeManager ?? (this.anyMergeable ? contentMerge : undefined);\n    if (!manager) return undefined;\n    const rowCount = this.layout.rowCount;\n    const colCount = this.layout.colCount;\n    const value = (row: number, col: number): unknown => {\n      if (this.data.rowType(row) !== 'data') return null;\n      return this.columns[col].getValue(this.data.item(row) as Record<string, unknown>);\n    };\n    const mergeableCol = (col: number): boolean => this.columns[col].allowMerging;\n    return (row, col) => manager({ row, col, rowCount, colCount, value, mergeableCol });\n  }\n\n  // Emit a cancelable (\"-ing\") event and return true if a handler set cancel.\n  private emitCancel<K extends CancelableEvent>(\n    type: K,\n    payload: Omit<GridEvents[K], 'cancel'>,\n  ): boolean {\n    const e = { ...payload, cancel: false } as GridEvents[K];\n    this.events.emit(type, e);\n    return (e as unknown as { cancel: boolean }).cancel;\n  }\n\n  private syncViewportSize(): void {\n    const vp = this.viewportRenderer.viewport;\n    const width = vp.clientWidth - this.viewportRenderer.gutterLeft;\n    const height = vp.clientHeight - this.viewportRenderer.gutterTop;\n    this.viewport.setSize(Math.max(0, width), Math.max(0, height));\n    this.viewportRenderer.setViewport(vp.clientWidth, vp.clientHeight);\n  }\n\n  private draw(): void {\n    const vp = this.viewportRenderer.viewport;\n    this.viewport.update(vp.scrollTop, vp.scrollLeft);\n    this.renderer.render(this.context());\n  }\n\n  private measure(): void {\n    this.syncViewportSize();\n    this.draw();\n  }\n\n  private onScroll(): void {\n    const vp = this.viewportRenderer.viewport;\n    // The body panel is pinned to the viewport, so every scroll must reposition\n    // its rows — not only the scrolls that change the row/column range.\n    this.viewport.update(vp.scrollTop, vp.scrollLeft);\n    this.renderer.render(this.context());\n    this.events.emit('scrollChanged', { scrollTop: vp.scrollTop, scrollLeft: vp.scrollLeft });\n  }\n\n  private onSelect(cell: CellAddress, extend: boolean, isPress: boolean): void {\n    if (this.data.rowType(cell.row) === 'group') {\n      if (isPress) this.toggleGroupAt(cell.row);\n      return;\n    }\n    this.applyMove(cell, extend);\n    if (isPress) {\n      this.host.focus(); // mousedown preventDefault blocks the default focus, so do it here\n      this.events.emit('cellClick', cell);\n      this.editor.toggleBoolean(cell); // checkbox cells flip on click\n    }\n  }\n\n  // A header click sorts, unless it was really a resize or a reorder drag.\n  private readonly onHeaderMouseDown = (e: MouseEvent): void => {\n    this.headerDownX = e.clientX;\n  };\n\n  private readonly onHeaderClick = (e: MouseEvent): void => {\n    if (Math.abs(e.clientX - this.headerDownX) > 4) return; // was a drag, not a click\n    const btn = (e.target as HTMLElement).closest('.apg-filter-btn') as HTMLElement | null;\n    if (btn) {\n      this.openFilter(Number(btn.dataset.filter), btn.getBoundingClientRect());\n      return;\n    }\n    if (!this.allowSorting) return;\n    const header = this.viewportRenderer.headerInner;\n    const x = e.clientX - header.getBoundingClientRect().left;\n    const col = this.layout.colAtX(x);\n    const right = this.layout.getColLeft(col) + this.layout.getColWidth(col);\n    if (Math.abs(x - right) <= 5) return; // resize edge belongs to the resizer\n    this.sortByColumn(col);\n  };\n\n  private onDoubleClick(cell: CellAddress): void {\n    if (this.data.rowType(cell.row) === 'group') return;\n    this.events.emit('cellDoubleClick', cell);\n    this.editor.begin(cell);\n  }\n\n  private onActivate(): void {\n    const cell = this.selectionModel.getActive();\n    if (!cell) return;\n    if (this.editor.toggleBoolean(cell)) return; // Space toggles checkbox cells\n    this.editor.begin(cell);\n  }\n\n  private bounds(): GridBounds {\n    return { rowCount: this.layout.rowCount, colCount: this.layout.colCount };\n  }\n\n  private applyMove(cell: CellAddress, extend: boolean): void {\n    if (this.data.rowType(cell.row) === 'group') return;\n    if (this.emitCancel('selectionChanging', { row: cell.row, col: cell.col })) return;\n    if (!this.selectionModel.moveTo(cell, extend)) return;\n    this.data.collectionView.moveCurrentToPosition(this.data.dataIndexAt(cell.row)); // currency follows selection\n    this.syncSelectionState();\n    this.draw();\n    this.events.emit('selectionChanged', this.selectionModel.getActive());\n  }\n\n  private syncSelectionState(): void {\n    this.state.selection = this.selectionModel.getRange(this.bounds());\n    this.state.activeCell = this.selectionModel.getActive();\n  }\n\n  private onNav(action: NavAction, extend: boolean): void {\n    const current = this.selectionModel.getActive();\n    if (!current) {\n      this.select(0, 0);\n      return;\n    }\n    const pageRows = Math.max(1, Math.floor(this.viewport.height / this.rowHeight) - 1);\n    const next = { ...current };\n    switch (action) {\n      case 'up':\n        next.row -= 1;\n        break;\n      case 'down':\n        next.row += 1;\n        break;\n      case 'left':\n        next.col -= 1;\n        break;\n      case 'right':\n        next.col += 1;\n        break;\n      case 'home':\n        next.col = 0;\n        break;\n      case 'end':\n        next.col = this.layout.colCount - 1;\n        break;\n      case 'pageup':\n        next.row -= pageRows;\n        break;\n      case 'pagedown':\n        next.row += pageRows;\n        break;\n    }\n    next.row = clamp(next.row, 0, this.layout.rowCount - 1);\n    next.col = clamp(next.col, 0, this.layout.colCount - 1);\n    if (action === 'up' || action === 'pageup') next.row = this.nextDataRow(next.row, -1);\n    else if (action === 'down' || action === 'pagedown') next.row = this.nextDataRow(next.row, 1);\n    this.select(next.row, next.col, extend);\n  }\n\n  // Group-header rows aren't selectable, so vertical navigation steps over them.\n  private nextDataRow(row: number, dir: 1 | -1): number {\n    let r = row;\n    while (r >= 0 && r < this.layout.rowCount && this.data.rowType(r) === 'group') r += dir;\n    return clamp(r, 0, this.layout.rowCount - 1);\n  }\n\n  private scrollIntoView(cell: CellAddress): void {\n    const vp = this.viewportRenderer.viewport;\n    const dataWidth = vp.clientWidth - this.viewportRenderer.gutterLeft;\n    const dataHeight = vp.clientHeight - this.viewportRenderer.gutterTop;\n    const top = this.layout.getRowTop(cell.row);\n    const bottom = top + this.layout.getRowHeight(cell.row);\n    const left = this.layout.getColLeft(cell.col);\n    const right = left + this.layout.getColWidth(cell.col);\n\n    if (top < vp.scrollTop) vp.scrollTop = top;\n    else if (bottom > vp.scrollTop + dataHeight) vp.scrollTop = bottom - dataHeight;\n\n    if (left < vp.scrollLeft) vp.scrollLeft = left;\n    else if (right > vp.scrollLeft + dataWidth) vp.scrollLeft = right - dataWidth;\n\n    this.onScroll();\n  }\n}\n","import { Column, ColumnDef, CellStyle } from '../models/Column';\nimport { ColumnGroupDef } from '../models/ColumnGroup';\nimport { SelectionMode } from '../selection/SelectionModel';\nimport { CollectionView } from '../data/CollectionView';\nimport { GroupHeaderTemplate } from '../rendering/GroupHeader';\nimport { GroupPanelOptions, ResolvedGroupPanel } from '../rendering/GroupPanel';\nimport { MergeManager } from '../models/MergeManager';\n\nexport type HeadersVisibility = 'None' | 'Column' | 'Row' | 'All';\n\n/** Context passed to row-level conditional styling callbacks. */\nexport interface RowStyleContext<T = Record<string, unknown>> {\n  item: T;\n  row: number;\n}\n\nexport type RowClass<T = Record<string, unknown>> =\n  string | string[] | ((ctx: RowStyleContext<T>) => string | string[] | null | undefined);\n\nexport type RowStyle<T = Record<string, unknown>> =\n  CellStyle | ((ctx: RowStyleContext<T>) => CellStyle | null | undefined);\n\nexport interface GridOptions<T = Record<string, unknown>> {\n  columns: ColumnDef<T>[];\n  itemsSource?: T[] | CollectionView<T>;\n  /** Alias for `itemsSource`, kept for compatibility with the original grid. */\n  dataSource?: T[] | CollectionView<T>;\n  rowHeight?: number;\n  headerHeight?: number;\n  rowHeaderWidth?: number;\n  /** Multi-level column-header groups: bands that span a run of leaf columns. */\n  columnGroups?: ColumnGroupDef[];\n  /** Height of the column-group header row. Defaults to `headerHeight`. */\n  groupHeaderRowHeight?: number;\n  /** Animate column-group headers when they collapse/expand. Default false. */\n  columnGroupAnimation?: boolean;\n  /** Number of leading columns kept pinned to the left while the rest scroll. Default 0. */\n  frozenColumns?: number;\n  /** Number of leading rows kept pinned to the top while the rest scroll. Default 0. */\n  frozenRows?: number;\n  selectionMode?: SelectionMode;\n  headersVisibility?: HeadersVisibility;\n  /** Regular rows between alternating-colored rows. 0 disables. Default 1. */\n  alternatingRowStep?: number;\n  /** Allow users to drag column headers to reorder them. Default true. */\n  allowColumnReorder?: boolean;\n  /** Allow clicking a column header to sort by it. Default true. */\n  allowSorting?: boolean;\n  /** Enable copy/paste shortcuts (Ctrl+C / Ctrl+V). Default false. */\n  allowClipboard?: boolean;\n  /** Show a filter button on each column header. Per-column `filter` overrides it. Default false. */\n  allowFiltering?: boolean;\n  /** Merge adjacent equal-valued cells. Per-column `allowMerging` overrides it. Default false. */\n  allowMerging?: boolean;\n  /** Custom rule for how cells merge. Replaces the default content-driven merge. */\n  mergeManager?: MergeManager;\n  /**\n   * Show the grouping bar; drag column headers into it to group. `true` enables\n   * everything, `false` (default) hides it, or pass an options object to switch\n   * individual capabilities on and off.\n   */\n  groupPanel?: boolean | GroupPanelOptions;\n  /** Text shown in the empty grouping bar. Also settable via `groupPanel.placeholder`. */\n  groupPanelPlaceholder?: string;\n  /** Maximum number of grouping levels. Default 6. Also settable via `groupPanel.maxGroups`. */\n  maxGroups?: number;\n  /** Custom renderer for the label on group-header rows (after the chevron). */\n  groupHeaderTemplate?: GroupHeaderTemplate<T>;\n  /** CSS class(es) for each data row. A function enables conditional styling. */\n  rowClass?: RowClass<T>;\n  /** Inline styles for each data row. A function enables conditional styling. */\n  rowStyle?: RowStyle<T>;\n  /** Track added/removed/edited rows on the collection view. Default false. */\n  trackChanges?: boolean;\n}\n\nexport interface ResolvedOptions<T> {\n  columns: Column<T>[];\n  view: CollectionView<T>;\n  rowHeight: number;\n  headerHeight: number;\n  rowHeaderWidth: number;\n  columnGroups: ColumnGroupDef[];\n  groupHeaderRowHeight: number;\n  columnGroupAnimation: boolean;\n  frozenColumns: number;\n  frozenRows: number;\n  selectionMode: SelectionMode;\n  headersVisibility: HeadersVisibility;\n  alternatingRowStep: number;\n  allowColumnReorder: boolean;\n  allowSorting: boolean;\n  allowClipboard: boolean;\n  allowFiltering: boolean;\n  allowMerging: boolean;\n  mergeManager?: MergeManager;\n  groupPanel: boolean;\n  groupPanelOptions: ResolvedGroupPanel;\n  maxGroups: number;\n  groupHeaderTemplate?: GroupHeaderTemplate<T>;\n  rowClass?: RowClass<T>;\n  rowStyle?: RowStyle<T>;\n}\n\nconst DEFAULT_ROW_HEIGHT = 24;\nconst DEFAULT_HEADER_HEIGHT = 28;\nconst DEFAULT_ROW_HEADER_WIDTH = 48;\nconst DEFAULT_MAX_GROUPS = 6;\nconst DEFAULT_GROUP_PLACEHOLDER = 'Drag a column header here to group by that column';\n\nexport function resolveOptions<T>(options: GridOptions<T>): ResolvedOptions<T> {\n  const source = options.itemsSource ?? options.dataSource ?? [];\n  const view = source instanceof CollectionView ? source : new CollectionView<T>(source);\n  if (options.trackChanges != null) view.trackChanges = options.trackChanges;\n  const groupPanelOptions = resolveGroupPanel(\n    options.groupPanel,\n    options.groupPanelPlaceholder ?? DEFAULT_GROUP_PLACEHOLDER,\n    options.maxGroups ?? DEFAULT_MAX_GROUPS,\n  );\n  const allowFiltering = options.allowFiltering ?? false;\n  const allowMerging = options.allowMerging ?? false;\n  const columns = options.columns.map((def) => {\n    const col = new Column<T>(def);\n    col.filterable = def.filter ?? allowFiltering;\n    col.allowMerging = def.allowMerging ?? allowMerging;\n    return col;\n  });\n  const headerHeight = options.headerHeight ?? DEFAULT_HEADER_HEIGHT;\n  return {\n    columns,\n    view,\n    rowHeight: options.rowHeight ?? DEFAULT_ROW_HEIGHT,\n    headerHeight,\n    rowHeaderWidth: options.rowHeaderWidth ?? DEFAULT_ROW_HEADER_WIDTH,\n    columnGroups: options.columnGroups ?? [],\n    groupHeaderRowHeight: options.groupHeaderRowHeight ?? headerHeight,\n    columnGroupAnimation: options.columnGroupAnimation ?? false,\n    frozenColumns: Math.max(0, options.frozenColumns ?? 0),\n    frozenRows: Math.max(0, options.frozenRows ?? 0),\n    selectionMode: options.selectionMode ?? 'Cell',\n    headersVisibility: options.headersVisibility ?? 'All',\n    alternatingRowStep: options.alternatingRowStep ?? 1,\n    allowColumnReorder: options.allowColumnReorder ?? true,\n    allowSorting: options.allowSorting ?? true,\n    allowClipboard: options.allowClipboard ?? false,\n    allowFiltering,\n    allowMerging,\n    mergeManager: options.mergeManager,\n    groupPanel: !!options.groupPanel,\n    groupPanelOptions,\n    maxGroups: groupPanelOptions.maxGroups,\n    groupHeaderTemplate: options.groupHeaderTemplate,\n    rowClass: options.rowClass,\n    rowStyle: options.rowStyle,\n  };\n}\n\n// Grouping bar toggles: an options object overrides these, `true`/`false`/absent\n// fall back to defaults. Everything is on by default.\nfunction resolveGroupPanel(\n  opt: boolean | GroupPanelOptions | undefined,\n  placeholder: string,\n  maxGroups: number,\n): ResolvedGroupPanel {\n  const o: GroupPanelOptions = typeof opt === 'object' && opt != null ? opt : {};\n  return {\n    placeholder: o.placeholder ?? placeholder,\n    maxGroups: o.maxGroups ?? maxGroups,\n    allowDragToGroup: o.allowDragToGroup ?? true,\n    allowReorder: o.allowReorder ?? true,\n    allowSort: o.allowSort ?? true,\n    allowRemove: o.allowRemove ?? true,\n    contextMenu: o.contextMenu ?? true,\n  };\n}\n","import { CollectionView, CollectionViewOptions } from './CollectionView';\nimport { EventBus, EventHandler } from '../events/EventBus';\n\ntype FieldType = 'Number' | 'Date' | 'Boolean' | 'String';\n\nexport interface ODataOptions<T> extends CollectionViewOptions<T> {\n  /** Fields to retrieve ($select). Empty means all fields. */\n  fields?: string[];\n  /** Sort on the server via $orderby. Default true. */\n  sortOnServer?: boolean;\n  /** Filter on the server via $filter. Default true. */\n  filterOnServer?: boolean;\n  /** Page on the server via $top/$skip. Default true. */\n  pageOnServer?: boolean;\n  /** OData $filter expression applied on the server. */\n  filterDefinition?: string;\n  requestHeaders?: Record<string, string>;\n  /** Coerce specific fields after loading (e.g. { Freight: 'Number' }). */\n  dataTypes?: Record<string, FieldType>;\n}\n\ninterface LoadEvents {\n  loading: void;\n  loaded: void;\n  error: unknown;\n}\n\nconst ISO_DATE = /^\\d{4}-\\d{2}-\\d{2}T/;\n\n/**\n * A {@link CollectionView} backed by an OData service. Sorting, filtering, and\n * paging run on the server through $orderby/$filter/$top/$skip; the view holds\n * the current server page.\n */\nexport class ODataCollectionView<T = Record<string, unknown>> extends CollectionView<T> {\n  readonly url: string;\n  readonly tableName: string;\n  fields: string[];\n  filterDefinition: string;\n  sortOnServer: boolean;\n  filterOnServer: boolean;\n  pageOnServer: boolean;\n  requestHeaders: Record<string, string>;\n  dataTypes: Record<string, FieldType>;\n\n  protected loadEvents = new EventBus<LoadEvents>();\n  protected _isLoading = false;\n\n  constructor(url: string, tableName: string, options: ODataOptions<T> = {}) {\n    super([], options);\n    this.url = /\\/$/.test(url) ? url : `${url}/`;\n    this.tableName = tableName;\n    this.fields = options.fields ?? [];\n    this.filterDefinition = options.filterDefinition ?? '';\n    this.sortOnServer = options.sortOnServer ?? true;\n    this.filterOnServer = options.filterOnServer ?? true;\n    this.pageOnServer = options.pageOnServer ?? true;\n    this.requestHeaders = options.requestHeaders ?? {};\n    this.dataTypes = options.dataTypes ?? {};\n    this.load();\n  }\n\n  get isLoading(): boolean {\n    return this._isLoading;\n  }\n\n  onLoading(handler: EventHandler<void>): () => void {\n    return this.loadEvents.on('loading', handler);\n  }\n\n  onLoaded(handler: EventHandler<void>): () => void {\n    return this.loadEvents.on('loaded', handler);\n  }\n\n  onError(handler: EventHandler<unknown>): () => void {\n    return this.loadEvents.on('error', handler);\n  }\n\n  // The base setters (pageSize, sort, filter) call refresh(); reload from server.\n  refresh(): void {\n    if (!this.url) return; // guard: base constructor calls refresh() before url is set\n    this.load();\n  }\n\n  /** Load (or reload) the current page from the server. */\n  load(): void {\n    if (!this.url) return;\n    const top = this.pageOnServer ? this.pageSize : 0;\n    const skip = top > 0 ? this.pageIndex * top : 0;\n    this.fetchPage(skip, top)\n      .then(({ items, total }) => {\n        this._totalItemCount = total;\n        this.applyServerPage(items);\n      })\n      .catch((err) => this.failLoad(err));\n  }\n\n  protected applyServerPage(items: T[]): void {\n    this.source = items;\n    this.view = items;\n    this._position = items.length ? 0 : -1;\n    this.finishLoad();\n  }\n\n  protected finishLoad(): void {\n    this._isLoading = false;\n    this.loadEvents.emit('loaded', undefined);\n    this.onChanged('reset');\n  }\n\n  protected failLoad(err: unknown): void {\n    this._isLoading = false;\n    this.loadEvents.emit('error', err);\n  }\n\n  protected fetchPage(skip: number, top: number): Promise<{ items: T[]; total: number }> {\n    this._isLoading = true;\n    this.loadEvents.emit('loading', undefined);\n    const requestUrl = `${this.url}${this.tableName}?${this.buildQuery(skip, top)}`;\n    return fetch(requestUrl, { headers: this.requestHeaders })\n      .then((res) => {\n        if (!res.ok) throw new Error(`OData request failed (${res.status})`);\n        return res.json();\n      })\n      .then((data) => {\n        const value = (data.value ?? data) as T[];\n        const total = (data['@odata.count'] as number) ?? value.length;\n        this.coerceTypes(value);\n        return { items: value, total };\n      });\n  }\n\n  protected buildQuery(skip: number, top: number): string {\n    const params = ['$count=true'];\n    if (this.fields.length) params.push(`$select=${this.fields.join(',')}`);\n    if (this.sortOnServer && this.sortDescriptions.length) {\n      const orderby = this.sortDescriptions\n        .map((s) => encodeURIComponent(`${s.property} ${s.ascending ? 'asc' : 'desc'}`))\n        .join(',');\n      params.push(`$orderby=${orderby}`);\n    }\n    if (this.filterOnServer && this.filterDefinition) {\n      params.push(`$filter=${encodeURIComponent(this.filterDefinition)}`);\n    }\n    if (top > 0) params.push(`$top=${top}`);\n    if (skip > 0) params.push(`$skip=${skip}`);\n    return params.join('&');\n  }\n\n  // JSON has no Date type, so coerce configured fields (or anything that looks\n  // like an ISO date when no types are given).\n  private coerceTypes(items: T[]): void {\n    const types = this.dataTypes;\n    const hasTypes = Object.keys(types).length > 0;\n    for (const item of items) {\n      const rec = item as Record<string, unknown>;\n      for (const key in rec) {\n        const value = rec[key];\n        const type = types[key];\n        if (type === 'Date') rec[key] = value != null ? new Date(value as string) : null;\n        else if (type === 'Number') rec[key] = value != null ? Number(value) : null;\n        else if (!hasTypes && typeof value === 'string' && ISO_DATE.test(value)) {\n          rec[key] = new Date(value);\n        }\n      }\n    }\n  }\n}\n","import { ODataCollectionView } from './ODataCollectionView';\n\n/**\n * An {@link ODataCollectionView} that loads data incrementally for infinite\n * scrolling. The first load fetches one chunk; {@link loadMore} appends the next\n * chunk until every row has been retrieved.\n */\nexport class ODataVirtualCollectionView<\n  T = Record<string, unknown>,\n> extends ODataCollectionView<T> {\n  private _allLoaded = false;\n\n  /** True once every server row has been loaded. */\n  get allLoaded(): boolean {\n    return this._allLoaded;\n  }\n\n  // A full load resets to the first chunk (e.g. after sorting changes).\n  load(): void {\n    if (!this.url) return;\n    this._allLoaded = false;\n    this.fetchPage(0, this.pageSize)\n      .then(({ items, total }) => {\n        this._totalItemCount = total;\n        this.source = items;\n        this.view = items;\n        this._position = items.length ? 0 : -1;\n        this._allLoaded = items.length >= total;\n        this.finishLoad();\n      })\n      .catch((err) => this.failLoad(err));\n  }\n\n  /** Fetch and append the next chunk. No-op while loading or once all loaded. */\n  loadMore(): void {\n    if (this._isLoading || this._allLoaded || !this.url) return;\n    const skip = this.view.length;\n    this.fetchPage(skip, this.pageSize)\n      .then(({ items, total }) => {\n        this._totalItemCount = total;\n        const all = this.source.concat(items);\n        this.source = all;\n        this.view = all;\n        this._allLoaded = all.length >= total;\n        this.finishLoad();\n      })\n      .catch((err) => this.failLoad(err));\n  }\n}\n","import './styles/apgrid.scss';\n\nimport * as controls from './controls';\n\n/** Namespace holding the grid control and its data-mapping helpers (ap.controls.*). */\nexport { controls };\n\n// Core data\nexport { CollectionView } from './data/CollectionView';\nexport { ODataCollectionView } from './data/ODataCollectionView';\nexport { ODataVirtualCollectionView } from './data/ODataVirtualCollectionView';\nexport { SortDescription } from './models/SortDescription';\n\n// Grid module, also reachable through `controls`\nexport { Grid } from './core/Grid';\nexport { Grid as ApGrid } from './core/Grid';\nexport { Column } from './models/Column';\nexport { ColumnGroup, ColumnGroupLeaf } from './models/ColumnGroup';\nexport { DataMap } from './models/DataMap';\nexport { DataMapEditor } from './models/DataMapEditor';\nexport { PropertyGroupDescription } from './models/GroupDescription';\nexport { CollectionViewGroup } from './data/CollectionViewGroup';\nexport { ColumnFilter } from './models/ColumnFilter';\nexport { icons, iconEl } from './utils/icons';\n\n// Export module\nexport { ExportManager } from './export/ExportManager';\nexport { ExportRegistry } from './export/registry';\nexport { csvFormat } from './export/formats/csv';\nexport { xlsxFormat } from './export/formats/xlsx';\nexport { pdfFormat } from './export/formats/pdf';\n\nexport type { ColumnDef } from './models/Column';\nexport type { ColumnGroupDef } from './models/ColumnGroup';\nexport type { ColumnGroupNode } from './models/ColumnGroup';\nexport type {\n  DataType,\n  CellAlign,\n  DataMapEntry,\n  CellTemplateContext,\n  AggregateType,\n  CellStyle,\n  CellClassFn,\n  CellStyleFn,\n  CellClassRules,\n} from './models/Column';\nexport type { GroupHeaderContext, GroupHeaderTemplate } from './rendering/GroupHeader';\nexport type { GroupPanelOptions } from './rendering/GroupPanel';\nexport type { FilterOperator, FilterCondition, OperatorChoice } from './models/ColumnFilter';\nexport type { IconName } from './utils/icons';\nexport type {\n  GridOptions,\n  HeadersVisibility,\n  RowStyleContext,\n  RowClass,\n  RowStyle,\n} from './core/GridOptions';\nexport type { CellAddress, CellRange } from './models/Cell';\nexport { makeRange } from './models/Cell';\nexport type { MergeQuery, MergeManager } from './models/MergeManager';\nexport { contentMerge } from './models/MergeManager';\nexport type {\n  GridStateSnapshot,\n  ColumnStateSnapshot,\n  FilterStateSnapshot,\n  ColumnGroupStateSnapshot,\n} from './models/GridStateSnapshot';\nexport type { SelectionMode } from './selection/SelectionModel';\nexport type { GridEvents } from './events/GridEvents';\nexport type { UndoableAction } from './commands/UndoableAction';\nexport type { CollectionViewOptions, CollectionChange, ChangeAction } from './data/CollectionView';\nexport type { ODataOptions } from './data/ODataCollectionView';\nexport type {\n  ExportOptions,\n  ExportFormat,\n  ExportData,\n  ExportColumn,\n  ExportRow,\n  ExportCell,\n  ExportCellStyle,\n  ExportMerge,\n  ExportCellContext,\n  ExportHeaderContext,\n  CellCallback,\n  HeaderCallback,\n  ExportProgress,\n  CsvOptions,\n  PdfOptions,\n} from './export/types';\nexport type { ExportResult, ExportDeps } from './export/ExportManager';\n\nexport const VERSION = '0.1.0';\n"],"names":["__webpack_require__","exports","definition","Array","isArray","i","length","key","binding","o","Object","defineProperty","enumerable","value","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","DataMapEditor","EventBus","constructor","this","handlers","Map","on","type","handler","set","Set","add","_a","delete","emit","payload","clear","CollectionViewGroup","name","level","items","groups","isBottomLevel","itemCount","compareValues","a","b","Date","getTime","String","localeCompare","buildGroups","descriptions","sorts","groupLevel","leaves","desc","buckets","item","groupKey","id","bucketId","bucket","push","dir","some","s","property","ascending","ordered","values","sort","child","group","groupName","leaf","toLocaleDateString","CollectionView","source","options","itemsAdded","itemsRemoved","itemsEdited","view","events","_position","_filter","_sorts","_groups","_groupTree","_pageSize","_pageIndex","_totalItemCount","editTarget","editSnapshot","addTarget","updateDepth","refreshPending","_trackChanges","trackChanges","newItemCreator","_b","pageSize","refresh","sourceCollection","clearChanges","canSort","canFilter","filter","sortDescriptions","groupDescriptions","canChangePage","Math","max","pageIndex","pageCount","ceil","totalItemCount","moveToPage","index","target","min","undefined","moveToFirstPage","moveToLastPage","moveToNextPage","moveToPreviousPage","isEmpty","currentItem","currentPosition","isAddingNew","isEditingItem","currentAddItem","currentEditItem","contains","indexOf","moveCurrentToPosition","moveCurrentToFirst","moveCurrentToLast","moveCurrentToNext","moveCurrentToPrevious","moveCurrentTo","editItem","commitEdit","trackEdit","onChanged","cancelEdit","assign","addNew","commit","created","commitNew","cancelNew","splice","remove","trackRemove","removeAt","beginUpdate","endUpdate","isUpdating","deferUpdate","fn","current","arranged","arrange","result","page","idx","slice","applySort","start","sd","c","sortValue","raw","sortConverter","added","edited","action","sameKey","DataMap","itemsSource","selectedValuePath","displayMemberPath","isEditable","sortByDisplayValues","collectionView","onMapChanged","getKeyValues","dataItem","map","keyOf","getDisplayValues","displayOf","getDisplayValue","find","getKeyValue","displayValue","getDataItem","itemsFor","itemsFilter","Column","def","dataType","filterable","allowMerging","hidden","header","_c","width","_d","_e","align","_f","valueGetter","valueFormatter","cellTemplate","dataMap","dataMapEditor","_g","DropDownList","aggregate","cellClassDef","cellClass","cellStyleDef","cellStyle","cellClassRules","editable","_h","isCalculated","getValue","setValue","parse","text","trim","n","Number","isNaN","d","format","formatValue","cellClasses","row","ctx","cellContext","out","addClasses","cellInlineStyle","column","list","entry","token","split","GridState","scrollTop","scrollLeft","firstRow","lastRow","firstCol","lastCol","frozenCols","frozenRows","selection","activeCell","alternatingRowStep","activeFilters","listeners","subscribe","listener","emitChange","GridViewport","state","layout","height","setSize","update","rows","getVisibleRows","cols","getVisibleCols","first","rowCount","last","colCount","rangeChanged","ColumnGroupLeaf","kind","ColumnGroup","children","toLowerCase","replace","collapsible","collapsed","leafBindings","collapseTo","includes","collectLeaves","depth","descendantGroups","node","buildColumnGroups","columns","defs","known","claimed","resolveNode","resolveLeaf","label","has","warn","buildColumnGroupLayout","chains","indexChains","reduce","m","g","cells","leafHeaderCols","colChain","col","chain","end","startCol","endCol","rowSpan","leafCol","ancestors","next","message","console","GroupRowModel","allKeys","active","rebuild","cursor","walk","parentPath","pathKey","viewIndex","rowAt","isCollapsed","toggle","collapseAll","expandAll","collapsedKeys","setCollapsed","keys","DataView_DataView","groupModel","refreshGroups","grouped","dataIndexAt","rowType","groupRow","toggleGroup","collapseAllGroups","expandAllGroups","collapsedGroups","setCollapsedGroups","setItems","applyEdit","mutate","SortDescription","PropertyGroupDescription","converter","upperBound","arr","lo","hi","mid","clamp","LayoutEngine","rowHeight","_rowCount","colLefts","buildColLefts","totalHeight","totalWidth","getRowTop","getRowHeight","_row","getColLeft","getColWidth","frozenColsWidth","count","frozenRowsHeight","viewportHeight","floor","viewportWidth","rowAtY","y","colAtX","x","setRowCount","setColumns","lefts","createEl","tag","className","el","document","createElement","setTransform","style","transform","conditionalStyleKeys","WeakMap","setConditionalStyle","prev","ViewportRenderer","host","config","classList","gutterLeft","showRowHeader","rowHeaderWidth","groupHeight","showColumnHeader","columnGroupHeight","leafHeaderHeight","headerHeight","gutterTop","viewport","canvas","marginLeft","marginTop","top","mergeLayer","appendChild","groupInner","columnGroupInner","headerInner","display","rowHeaderInner","corner","left","frozenColsHeader","frozenRowsHeader","frozenCorner","append","showGroupPanel","panel","groupPanelHeight","groupPanel","resize","setViewport","bodyH","setFrozen","colsWidth","rowsHeight","show","dispose","icons","chevron","dragHandle","close","sortAsc","sortDesc","caretUp","caretRight","dot","filterActive","iconEl","span","innerHTML","ObjectPool","create","reset","free","acquire","pop","release","available","computeAggregate","sum","Infinity","isFinite","RowRenderer","rowClasses","rowPool","willChange","render","bodyFirst","freeData","freeGroup","data","acquireRow","repositionRow","fillGroup","fillCells","releaseRow","step","gr","paddingLeft","textContent","inner","groupHeaderTemplate","cell","it","rowSelected","topRow","bottomRow","activeCol","bodyFirstCol","applyRowStyle","cellEl","merge","selected","leftCol","rightCol","rowClass","classes","toClassList","resolveRowValue","rowStyle","HeaderRenderer","pool","inBand","columnGroups","fillHeaderCell","arrow","btn","dataset","title","ColumnGroupRenderer","onToggle","removeAttribute","onClick","e","closest","addEventListener","visible","fill","removeEventListener","right","RowHeaderRenderer","isGroup","CellRenderer","CellBand","yOffset","HeaderBand","RowHeaderBand","FrozenRenderer","vp","colsBand","rowsBand","cornerBand","colsHeader","rowsHeader","fCols","fRows","bodyFirstRow","cellEquals","makeRange","r1","c1","r2","c2","MergeRenderer","layer","seen","range","renderSpan","bottom","sel","rangeContains","Renderer","rowHeader","frozen","ScrollManager","scroller","tick","onScroll","passive","RANGE_MODES","SelectionModel","mode","anchor","getMode","setMode","getActive","getRange","bounds","anc","moveTo","extend","nextAnchor","changed","MouseHandler","onSelect","onDouble","dragging","onMouseDown","button","hitTest","preventDefault","shiftKey","onMouseMove","onMouseUp","onDoubleClick","window","rect","getBoundingClientRect","vx","clientX","vy","clientY","KeyboardHandler","onNav","onUndoRedo","onActivate","onKeyDown","ctrlKey","metaKey","toAction","ColumnResizer","preview","startX","startWidth","onDown","edgeAt","onMove","onUp","onHover","abs","ColumnDragger","groupZone","onGroupBy","onGroupHover","srcCol","overZone","marker","insertAt","isEdge","colAt","showGhost","moveGhost","isOverGroupZone","ghost","contentX","removeGhost","to","body","h","offsetHeight","ClipboardHandler","deps","onCopy","isEditing","clipboardData","getClip","setData","onPaste","getData","applyClip","csvFormat","extension","mimeType","opts","csv","delimiter","newline","bom","includeHeaders","escape","field","lines","join","table","crc32","bytes","t","Uint32Array","k","buildTable","crc","utf8","TextEncoder","ZipWriter","entries","chunks","offset","path","content","encode","nameBytes","Uint8Array","v","DataView","buffer","setUint32","setUint16","build","centralStart","rec","centralSize","eocd","concat","chunk","pos","xlsxFormat","styles","StyleCollector","sheet","headerRows","headerStyle","bold","italic","date","outline","parts","outlineLevels","round","colsXml","rowNum","headerGroups","hr","headerCellXml","colLetter","filterHeaderRow","bodyCellXml","attrs","dataStartRow","headerRow","autoFilter","ref","filters","f","escapeXml","autoFilterXml","merges","mergeXml","sheetXml","zip","CONTENT_TYPES","ROOT_RELS","WORKBOOK","WORKBOOK_RELS","fonts","fills","xfs","fontCache","fillCache","xfCache","JSON","stringify","cached","fontId","font","fillId","xf","color","hex","styleIndex","base","background","named","red","green","blue","black","white","orange","gray","grey","test","toUpperCase","sAttr","inlineStr","serial","epoch","UTC","getFullYear","getMonth","getDate","getHours","getMinutes","getSeconds","toExcelSerial","fromCharCode","pdfFormat","PdfDoc","PAGE","portrait","w","landscape","MARGIN","colX","pdf","orientation","fontSize","rowH","scale","tableWidth","pages","paginate","streams","pageStream","pageObjIds","objects","pageId","contentId","byteLen","serialize","headerH","rowsPerPage","firstPage","ops","pdf_text","tableTop","forEach","cellText","bg","rgb","line","ry","r","cellW","clipped","clip","textW","drawn","maxWidth","per","offsets","xrefStart","total","padStart","charCodeAt","latin1","size","fixed","escapePdf","parseInt","toFixed","x1","y1","x2","y2","ExportRegistry","formats","register","ids","buildExportData","input","prepare","buildRow","finish","hasGroupRows","outlineGroups","includeGroups","cellCallback","exportColumns","headerCallback","displayRows","currentDepth","maxOutline","runCellCallbacks","rowIndex","rowKind","indent","repeat","agg","dataCell","gridColOf","displayToExport","exportRow","displayRow","exportCol","exportCols","gc","exportRows","dr","er","ec","collectMerges","sets","passes","every","yieldToEventLoop","Promise","resolve","setTimeout","abortError","err","Error","ProgressOverlay","root","position","inset","flexDirection","alignItems","justifyContent","gap","zIndex","setAttribute","fontWeight","track","borderRadius","overflow","bar","transition","getComputedStyle","fraction","pct","hide","ExportManager","registry","registerFormat","bind","resolveFormat","onExporting","buildInput","finishExport","exportAsync","showProgress","overlay","onProgress","async","chunkSize","done","signal","aborted","buildExportDataAsync","buildData","formatId","fileName","download","URL","part","blob","Blob","url","createObjectURL","href","click","removeChild","revokeObjectURL","downloadBlob","onExported","allColumns","bindings","byBinding","pickColumns","selectionScoped","hg","gridIndex","filtered","useFull","fullSource","colByBinding","_k","_j","spans","ContextMenu","onOutside","onKey","isOpen","open","menu","disabled","icon","blankIcon","innerWidth","innerHeight","GroupPanel","cb","dragFrom","onContextMenu","chip","sorted","chips","onExpandAll","onCollapseAll","allowSort","onSort","allowRemove","onRemove","removeEl","onToggleSort","allowReorder","chipEls","querySelectorAll","insertBefore","onReorder","placeholderEl","placeholder","contextMenu","hostElement","highlight","TEXT_OPERATORS","op","NUMBER_OPERATORS","operatorsFor","filterKey","ColumnFilter","condition","isActive","cond","toNumber","needle","hay","startsWith","endsWith","testCondition","FilterModel","hasAny","distinctValues","others","apply","clearAll","VALUELESS","FilterEditor","condOp","condValue","dialog","showSort","sortRow","makeSort","valueInput","section","opSelect","choice","search","selectAllRow","selectAll","selectAllText","boxes","box","checked","syncSelectAll","parentElement","indeterminate","q","match","footer","clearBtn","applyBtn","onClear","draft","buildCondition","onApply","UndoStack","maxActions","actions","pointer","busy","canUndo","canRedo","actionCount","shift","onStateChanged","undo","redo","ResizeColumnAction","oldWidth","newWidth","onApplied","EditAction","oldValue","newValue","BatchAction","MoveColumnAction","from","moveColumn","TextEditor","onCommit","onCancel","stopPropagation","parent","toISOString","editorValue","focus","select","DropDownEditor","autocomplete","listEl","commitInput","li","toggleList","readOnly","Menu","renderList","matches","positionList","inputRect","vpRect","spaceBelow","flip","move","delta","scrollIntoView","block","exact","nextId","RadioEditor","relatedTarget","radio","createTextNode","minWidth","focusTarget","querySelector","EditorManager","editing","cancel","dropdown","toggleBoolean","begin","onBeginning","cellRect","editorFor","onStart","onEnding","onEnded","onEnd","RadioButtons","DOMRect","sameValue","contentMerge","mergeableCol","nodeToDef","groupToDef","groupToSnapshot","Grid","selectionModel","columnGroupList","columnGroupDepth","anyMergeable","headerDownX","undoStack","unsubscribeData","registerExportFormat","args","exportManager","_item","onHeaderMouseDown","onHeaderClick","openFilter","allowSorting","viewportRenderer","sortByColumn","resolved","dataSource","groupPanelOptions","opt","maxGroups","allowDragToGroup","resolveGroupPanel","groupPanelPlaceholder","allowFiltering","groupHeaderRowHeight","_l","columnGroupAnimation","_m","frozenColumns","_o","_p","selectionMode","_q","headersVisibility","_r","_s","allowColumnReorder","_t","_u","allowClipboard","_v","mergeManager","resolveOptions","syncHiddenColumns","hasColumnGroups","setProperty","tabIndex","rowRenderer","headerRenderer","columnGroupRenderer","toggleColumnGroup","rowHeaderRenderer","renderer","scroll","mouse","isPress","keyboard","resizer","resizeColumn","groupChips","removeGroup","moveGroup","dragToGroup","dragger","addGroup","filterModel","filterEditor","editor","draw","emitCancel","clipboard","copyForClipboard","setClipString","fullExportSource","exportHeaderGroups","mergeLookup","activeExportFilters","ResizeObserver","resizeObserver","measure","observe","syncViewportSize","selectedCell","syncSelectionState","applyMove","context","syncFrozen","invalidate","freezeColumns","freezeRows","toJSON","version","loadJSON","snapshot","applyColumnState","groupBy","cf","syncActiveFilters","clearSort","saved","addColumn","at","toAllColumnsIndex","removeColumn","scrollTo","editCell","setCellValue","getClipString","rng","pasting","grid","parseClip","startRow","edits","batch","range2","copying","export","exportData","fromAll","toAll","visibleIndex","findIndex","cur","clearFilters","activeBindings","afterFilterChanged","descs","canGroupBy","afterGroupsChanged","cv","clearGroups","refreshRows","moved","sortedBinding","toggleGroupAt","setColumnGroups","applyColumnGroups","addColumnGroup","columnGroupDefs","removeColumnGroup","allGroups","collapseAllColumnGroups","setColumnGroupsCollapsed","expandAllColumnGroups","collectHidden","underCollapsed","keepBinding","nowCollapsed","keep","clampSelectionToColumns","maxCol","disconnect","removeProperty","manager","clientWidth","clientHeight","pageRows","nextDataRow","dataWidth","dataHeight","ISO_DATE","ODataCollectionView","tableName","super","loadEvents","_isLoading","fields","filterDefinition","sortOnServer","filterOnServer","pageOnServer","requestHeaders","dataTypes","load","isLoading","onLoading","onLoaded","onError","skip","fetchPage","then","applyServerPage","catch","failLoad","finishLoad","requestUrl","buildQuery","fetch","headers","res","ok","status","json","coerceTypes","params","orderby","encodeURIComponent","types","hasTypes","ODataVirtualCollectionView","_allLoaded","allLoaded","loadMore","all","src_VERSION"],"sourceRoot":""}