const m = {
  expand: "▶",
  collapse: "▼",
  sortAsc: "▲",
  sortDesc: "▼",
  sortNone: "⇅",
  submenuArrow: "▶",
  dragHandle: "⋮⋮",
  toolPanel: "☰"
};
class p {
  /** Plugin version - override in subclass if needed */
  version = "1.0.0";
  /** CSS styles to inject into the grid's shadow DOM */
  styles;
  /** Custom cell renderers keyed by type name */
  cellRenderers;
  /** Custom header renderers keyed by type name */
  headerRenderers;
  /** Custom cell editors keyed by type name */
  cellEditors;
  /** The grid instance this plugin is attached to */
  grid;
  /** Plugin configuration - merged with defaults in attach() */
  config;
  /** User-provided configuration from constructor */
  userConfig;
  /**
   * Default configuration - subclasses should override this getter.
   * Note: This must be a getter (not property initializer) for proper inheritance
   * since property initializers run after parent constructor.
   */
  get defaultConfig() {
    return {};
  }
  constructor(t = {}) {
    this.userConfig = t;
  }
  /**
   * Called when the plugin is attached to a grid.
   * Override to set up event listeners, initialize state, etc.
   */
  attach(t) {
    this.grid = t, this.config = { ...this.defaultConfig, ...this.userConfig };
  }
  /**
   * Called when the plugin is detached from a grid.
   * Override to clean up event listeners, timers, etc.
   */
  detach() {
  }
  /**
   * Get another plugin instance from the same grid.
   * Use for inter-plugin communication.
   */
  getPlugin(t) {
    return this.grid?.getPlugin(t);
  }
  /**
   * Emit a custom event from the grid.
   */
  emit(t, e) {
    this.grid?.dispatchEvent?.(new CustomEvent(t, { detail: e, bubbles: !0 }));
  }
  /**
   * Request a re-render of the grid.
   */
  requestRender() {
    this.grid?.requestRender?.();
  }
  /**
   * Request a lightweight style update without rebuilding DOM.
   * Use this instead of requestRender() when only CSS classes need updating.
   */
  requestAfterRender() {
    this.grid?.requestAfterRender?.();
  }
  /**
   * Get the current rows from the grid.
   */
  get rows() {
    return this.grid?.rows ?? [];
  }
  /**
   * Get the original unfiltered/unprocessed rows from the grid.
   * Use this when you need all source data regardless of active filters.
   */
  get sourceRows() {
    return this.grid?.sourceRows ?? [];
  }
  /**
   * Get the current columns from the grid.
   */
  get columns() {
    return this.grid?.columns ?? [];
  }
  /**
   * Get only visible columns from the grid (excludes hidden).
   * Use this for rendering that needs to match the grid template.
   */
  get visibleColumns() {
    return this.grid?.visibleColumns ?? [];
  }
  /**
   * Get the shadow root of the grid.
   */
  get shadowRoot() {
    return this.grid?.shadowRoot ?? null;
  }
  /**
   * Get the disconnect signal for event listener cleanup.
   * This signal is aborted when the grid disconnects from the DOM.
   * Use this when adding event listeners that should be cleaned up automatically.
   *
   * Best for:
   * - Document/window-level listeners added in attach()
   * - Listeners on the grid element itself
   * - Any listener that should persist across renders
   *
   * Not needed for:
   * - Listeners on elements created in afterRender() (removed with element)
   *
   * @example
   * element.addEventListener('click', handler, { signal: this.disconnectSignal });
   * document.addEventListener('keydown', handler, { signal: this.disconnectSignal });
   */
  get disconnectSignal() {
    return this.grid?.disconnectSignal;
  }
  /**
   * Get the grid-level icons configuration.
   * Returns merged icons (user config + defaults).
   */
  get gridIcons() {
    const t = this.grid?.gridConfig?.icons ?? {};
    return { ...m, ...t };
  }
  /**
   * Resolve an icon value to string or HTMLElement.
   * Checks plugin config first, then grid-level icons, then defaults.
   *
   * @param iconKey - The icon key in GridIcons (e.g., 'expand', 'collapse')
   * @param pluginOverride - Optional plugin-level override
   * @returns The resolved icon value
   */
  resolveIcon(t, e) {
    return e !== void 0 ? e : this.gridIcons[t];
  }
  /**
   * Set an icon value on an element.
   * Handles both string (text/HTML) and HTMLElement values.
   *
   * @param element - The element to set the icon on
   * @param icon - The icon value (string or HTMLElement)
   */
  setIcon(t, e) {
    typeof e == "string" ? t.innerHTML = e : e instanceof HTMLElement && (t.innerHTML = "", t.appendChild(e.cloneNode(!0)));
  }
  /**
   * Log a warning message.
   */
  warn(t) {
    console.warn(`[tbw-grid:${this.name}] ${t}`);
  }
  // #endregion
}
const a = 100;
function h(s) {
  if (s == null)
    return a;
  if (typeof s == "number")
    return s;
  const t = parseFloat(s);
  return isNaN(t) ? a : t;
}
function c(s) {
  return s.map((t) => h(t.width));
}
function f(s) {
  const t = [];
  let e = 0;
  for (const i of s)
    t.push(e), e += h(i.width);
  return t;
}
function g(s) {
  return s.reduce((t, e) => t + h(e.width), 0);
}
function w(s, t, e, i, o) {
  const r = e.length;
  if (r === 0)
    return { startCol: 0, endCol: 0, visibleColumns: [] };
  let n = R(s, e, i);
  n = Math.max(0, n - o);
  const C = s + t;
  let u = n;
  for (let l = n; l < r; l++) {
    if (e[l] >= C) {
      u = l - 1;
      break;
    }
    u = l;
  }
  u = Math.min(r - 1, u + o);
  const d = [];
  for (let l = n; l <= u; l++)
    d.push(l);
  return { startCol: n, endCol: u, visibleColumns: d };
}
function R(s, t, e) {
  let i = 0, o = t.length - 1;
  for (; i < o; ) {
    const r = Math.floor((i + o) / 2);
    t[r] + e[r] <= s ? i = r + 1 : o = r;
  }
  return i;
}
function b(s, t, e) {
  return e ? s > t : !1;
}
class W extends p {
  name = "columnVirtualization";
  version = "1.0.0";
  get defaultConfig() {
    return {
      autoEnable: !0,
      threshold: 30,
      overscan: 3
    };
  }
  // #region Internal State
  isVirtualized = !1;
  startCol = 0;
  endCol = 0;
  scrollLeft = 0;
  totalWidth = 0;
  columnWidths = [];
  columnOffsets = [];
  // #endregion
  // #region Lifecycle
  attach(t) {
    super.attach(t);
    const e = this.columns;
    this.columnWidths = c(e), this.columnOffsets = f(e), this.totalWidth = g(e), this.endCol = e.length - 1;
  }
  detach() {
    this.columnWidths = [], this.columnOffsets = [], this.isVirtualized = !1, this.startCol = 0, this.endCol = 0, this.scrollLeft = 0, this.totalWidth = 0;
  }
  // #endregion
  // #region Hooks
  processColumns(t) {
    const e = b(t.length, this.config.threshold ?? 30, this.config.autoEnable ?? !0);
    if (this.isVirtualized = e ?? !1, this.columnWidths = c(t), this.columnOffsets = f(t), this.totalWidth = g(t), !e)
      return this.startCol = 0, this.endCol = t.length - 1, [...t];
    const i = this.grid.clientWidth || 800, o = w(
      this.scrollLeft,
      i,
      this.columnOffsets,
      this.columnWidths,
      this.config.overscan ?? 3
    );
    return this.startCol = o.startCol, this.endCol = o.endCol, o.visibleColumns.map((r) => t[r]);
  }
  afterRender() {
    if (!this.isVirtualized) return;
    const t = this.shadowRoot;
    if (!t) return;
    const e = this.columnOffsets[this.startCol] ?? 0, i = t.querySelector(".header-row"), o = t.querySelectorAll(".data-grid-row");
    i && (i.style.paddingLeft = `${e}px`), o.forEach((n) => {
      n.style.paddingLeft = `${e}px`;
    });
    const r = t.querySelector(".rows-viewport .rows");
    r && (r.style.width = `${this.totalWidth}px`);
  }
  onScroll(t) {
    !this.isVirtualized || Math.abs(t.scrollLeft - this.scrollLeft) < 1 || (this.scrollLeft = t.scrollLeft, this.requestRender());
  }
  // #endregion
  // #region Public API
  /**
   * Check if column virtualization is currently active.
   */
  getIsVirtualized() {
    return this.isVirtualized;
  }
  /**
   * Get the current visible column range.
   */
  getVisibleColumnRange() {
    return { start: this.startCol, end: this.endCol };
  }
  /**
   * Scroll the grid to bring a specific column into view.
   * @param columnIndex - Index of the column to scroll to
   */
  scrollToColumn(t) {
    const e = this.columnOffsets[t] ?? 0, i = this.grid;
    i.scrollLeft = e;
  }
  /**
   * Get the left offset for a specific column.
   * @param columnIndex - Index of the column
   */
  getColumnOffset(t) {
    return this.columnOffsets[t] ?? 0;
  }
  /**
   * Get the total width of all columns.
   */
  getTotalWidth() {
    return this.totalWidth;
  }
  // #endregion
}
export {
  W as ColumnVirtualizationPlugin
};
//# sourceMappingURL=index.js.map
