const v = {
  expand: "▶",
  collapse: "▼",
  sortAsc: "▲",
  sortDesc: "▼",
  sortNone: "⇅",
  submenuArrow: "▶",
  dragHandle: "⋮⋮",
  toolPanel: "☰"
};
class R {
  /** 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, n) {
    this.grid?.dispatchEvent?.(new CustomEvent(t, { detail: n, 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 { ...v, ...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, n) {
    return n !== void 0 ? n : 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, n) {
    typeof n == "string" ? t.innerHTML = n : n instanceof HTMLElement && (t.innerHTML = "", t.appendChild(n.cloneNode(!0)));
  }
  /**
   * Log a warning message.
   */
  warn(t) {
    console.warn(`[tbw-grid:${this.name}] ${t}`);
  }
  // #endregion
}
const f = {
  sum: (e, t) => e.reduce((n, i) => n + (Number(i[t]) || 0), 0),
  avg: (e, t) => {
    const n = e.reduce((i, r) => i + (Number(r[t]) || 0), 0);
    return e.length ? n / e.length : 0;
  },
  count: (e) => e.length,
  min: (e, t) => Math.min(...e.map((n) => Number(n[t]) || 1 / 0)),
  max: (e, t) => Math.max(...e.map((n) => Number(n[t]) || -1 / 0)),
  first: (e, t) => e[0]?.[t],
  last: (e, t) => e[e.length - 1]?.[t]
}, u = /* @__PURE__ */ new Map(), g = {
  /**
   * Register a custom aggregator function.
   */
  register(e, t) {
    u.set(e, t);
  },
  /**
   * Unregister a custom aggregator function.
   */
  unregister(e) {
    u.delete(e);
  },
  /**
   * Get an aggregator function by reference.
   */
  get(e) {
    if (e !== void 0)
      return typeof e == "function" ? e : u.get(e) ?? f[e];
  },
  /**
   * Run an aggregator on a set of rows.
   */
  run(e, t, n, i) {
    const r = this.get(e);
    return r ? r(t, n, i) : void 0;
  },
  /**
   * Check if an aggregator exists.
   */
  has(e) {
    return u.has(e) || e in f;
  },
  /**
   * List all available aggregator names.
   */
  list() {
    return [...Object.keys(f), ...u.keys()];
  }
};
g.register.bind(g);
g.unregister.bind(g);
const A = g.get.bind(g);
g.run.bind(g);
g.list.bind(g);
function p(e, t) {
  const n = document.createElement("div");
  n.className = "tbw-pinned-rows", n.setAttribute("role", "presentation"), n.setAttribute("aria-live", "polite");
  const i = document.createElement("div");
  i.className = "tbw-pinned-rows-left";
  const r = document.createElement("div");
  r.className = "tbw-pinned-rows-center";
  const s = document.createElement("div");
  if (s.className = "tbw-pinned-rows-right", e.showRowCount !== !1) {
    const o = document.createElement("span");
    o.className = "tbw-status-panel tbw-status-panel-row-count", o.textContent = `Total: ${t.totalRows} rows`, i.appendChild(o);
  }
  if (e.showFilteredCount && t.filteredRows !== t.totalRows) {
    const o = document.createElement("span");
    o.className = "tbw-status-panel tbw-status-panel-filtered-count", o.textContent = `Filtered: ${t.filteredRows}`, i.appendChild(o);
  }
  if (e.showSelectedCount && t.selectedRows > 0) {
    const o = document.createElement("span");
    o.className = "tbw-status-panel tbw-status-panel-selected-count", o.textContent = `Selected: ${t.selectedRows}`, s.appendChild(o);
  }
  if (e.customPanels)
    for (const o of e.customPanels) {
      const a = E(o, t);
      switch (o.position) {
        case "left":
          i.appendChild(a);
          break;
        case "center":
          r.appendChild(a);
          break;
        case "right":
          s.appendChild(a);
          break;
      }
    }
  return n.appendChild(i), n.appendChild(r), n.appendChild(s), n;
}
function m(e) {
  const t = document.createElement("div");
  return t.className = `tbw-aggregation-rows tbw-aggregation-rows-${e}`, t.setAttribute("role", "presentation"), t;
}
function w(e, t, n, i) {
  e.innerHTML = "";
  for (const r of t) {
    const s = document.createElement("div");
    if (s.className = "tbw-aggregation-row", s.setAttribute("role", "presentation"), r.id && s.setAttribute("data-aggregation-id", r.id), r.fullWidth) {
      const o = document.createElement("div");
      o.className = "tbw-aggregation-cell tbw-aggregation-cell-full", o.style.gridColumn = "1 / -1", o.textContent = r.label || "", s.appendChild(o);
    } else
      for (const o of n) {
        const a = document.createElement("div");
        a.className = "tbw-aggregation-cell", a.setAttribute("data-field", o.field);
        let c;
        const h = r.aggregators?.[o.field];
        if (h) {
          const d = A(h);
          d && (c = d(i, o.field, o));
        } else if (r.cells && Object.prototype.hasOwnProperty.call(r.cells, o.field)) {
          const d = r.cells[o.field];
          typeof d == "function" ? c = d(i, o.field, o) : c = d;
        }
        a.textContent = c != null ? String(c) : "", s.appendChild(a);
      }
    e.appendChild(s);
  }
}
function E(e, t) {
  const n = document.createElement("div");
  n.className = "tbw-status-panel tbw-status-panel-custom", n.id = `status-panel-${e.id}`;
  const i = e.render(t);
  return typeof i == "string" ? n.innerHTML = i : n.appendChild(i), n;
}
function b(e, t, n, i, r) {
  return {
    totalRows: e.length,
    filteredRows: r?.cachedResult?.length ?? e.length,
    selectedRows: i?.selected?.size ?? 0,
    columns: t,
    rows: e,
    grid: n
  };
}
const x = ".tbw-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-color-panel-bg)}.tbw-pinned-rows{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--tbw-pinned-rows-bg, var(--tbw-color-panel-bg));border-top:1px solid var(--tbw-pinned-rows-border, var(--tbw-color-border));font-size:12px;color:var(--tbw-pinned-rows-color, var(--tbw-color-fg-muted));min-height:32px;box-sizing:border-box;min-width:fit-content}.tbw-pinned-rows-left,.tbw-pinned-rows-center,.tbw-pinned-rows-right{display:flex;align-items:center;gap:16px}.tbw-pinned-rows-left{justify-content:flex-start}.tbw-pinned-rows-center{justify-content:center;flex:1}.tbw-pinned-rows-right{justify-content:flex-end}.tbw-status-panel{white-space:nowrap}.tbw-aggregation-rows{min-width:fit-content;background:var(--tbw-aggregation-bg, var(--tbw-color-header-bg))}.tbw-aggregation-rows-top{border-bottom:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-rows-bottom{border-top:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:var(--tbw-aggregation-font-weight, 600)}.tbw-aggregation-cell{padding:var(--tbw-cell-padding, 2px 8px);min-height:var(--tbw-row-height, 28px);display:flex;align-items:center;border-right:1px solid var(--tbw-color-border-cell)}.tbw-aggregation-cell:last-child{border-right:0}.tbw-aggregation-cell-full{grid-column:1 / -1;border-right:0}";
class y extends R {
  name = "pinnedRows";
  version = "1.0.0";
  get defaultConfig() {
    return {
      position: "bottom",
      showRowCount: !0,
      showSelectedCount: !0,
      showFilteredCount: !0
    };
  }
  // #region Internal State
  infoBarElement = null;
  topAggregationContainer = null;
  bottomAggregationContainer = null;
  footerWrapper = null;
  // #endregion
  // #region Lifecycle
  detach() {
    this.infoBarElement && (this.infoBarElement.remove(), this.infoBarElement = null), this.topAggregationContainer && (this.topAggregationContainer.remove(), this.topAggregationContainer = null), this.bottomAggregationContainer && (this.bottomAggregationContainer.remove(), this.bottomAggregationContainer = null), this.footerWrapper && (this.footerWrapper.remove(), this.footerWrapper = null);
  }
  // #endregion
  // #region Hooks
  afterRender() {
    const t = this.shadowRoot;
    if (!t) return;
    const n = t.querySelector(".tbw-scroll-area") ?? t.querySelector(".tbw-grid-content") ?? t.children[0];
    if (!n) return;
    const i = this.getSelectionState(), r = this.getFilterState(), s = b(
      this.rows,
      this.columns,
      this.grid,
      i,
      r
    ), o = this.config.aggregationRows || [], a = o.filter((l) => l.position === "top"), c = o.filter((l) => l.position !== "top");
    if (a.length > 0) {
      if (!this.topAggregationContainer) {
        this.topAggregationContainer = m("top");
        const l = t.querySelector(".header");
        l && l.nextSibling ? n.insertBefore(this.topAggregationContainer, l.nextSibling) : n.appendChild(this.topAggregationContainer);
      }
      w(
        this.topAggregationContainer,
        a,
        this.visibleColumns,
        this.rows
      );
    } else this.topAggregationContainer && (this.topAggregationContainer.remove(), this.topAggregationContainer = null);
    const h = this.config.showRowCount !== !1 || this.config.showSelectedCount && s.selectedRows > 0 || this.config.showFilteredCount && s.filteredRows !== s.totalRows || this.config.customPanels && this.config.customPanels.length > 0, d = h && this.config.position !== "top", C = c.length > 0 || d;
    if (h && this.config.position === "top")
      if (!this.infoBarElement)
        this.infoBarElement = p(this.config, s), n.insertBefore(this.infoBarElement, n.firstChild);
      else {
        const l = p(this.config, s);
        this.infoBarElement.replaceWith(l), this.infoBarElement = l;
      }
    else this.config.position === "top" && this.infoBarElement && (this.infoBarElement.remove(), this.infoBarElement = null);
    C ? (this.footerWrapper || (this.footerWrapper = document.createElement("div"), this.footerWrapper.className = "tbw-footer", n.appendChild(this.footerWrapper)), this.footerWrapper.innerHTML = "", c.length > 0 && (this.bottomAggregationContainer || (this.bottomAggregationContainer = m("bottom")), this.footerWrapper.appendChild(this.bottomAggregationContainer), w(
      this.bottomAggregationContainer,
      c,
      this.visibleColumns,
      this.rows
    )), d && (this.infoBarElement = p(this.config, s), this.footerWrapper.appendChild(this.infoBarElement))) : this.cleanupFooter();
  }
  // #endregion
  // #region Private Methods
  cleanup() {
    this.infoBarElement && (this.infoBarElement.remove(), this.infoBarElement = null), this.topAggregationContainer && (this.topAggregationContainer.remove(), this.topAggregationContainer = null), this.bottomAggregationContainer && (this.bottomAggregationContainer.remove(), this.bottomAggregationContainer = null), this.footerWrapper && (this.footerWrapper.remove(), this.footerWrapper = null);
  }
  cleanupFooter() {
    this.footerWrapper && (this.footerWrapper.remove(), this.footerWrapper = null), this.bottomAggregationContainer && (this.bottomAggregationContainer.remove(), this.bottomAggregationContainer = null), this.infoBarElement && this.config.position !== "top" && (this.infoBarElement.remove(), this.infoBarElement = null);
  }
  getSelectionState() {
    try {
      return this.grid?.getPluginState?.("selection") ?? null;
    } catch {
      return null;
    }
  }
  getFilterState() {
    try {
      return this.grid?.getPluginState?.("filtering") ?? null;
    } catch {
      return null;
    }
  }
  // #endregion
  // #region Public API
  /**
   * Refresh the status bar to reflect current grid state.
   */
  refresh() {
    this.requestRender();
  }
  /**
   * Get the current status bar context.
   * @returns The context with row counts and other info
   */
  getContext() {
    const t = this.getSelectionState(), n = this.getFilterState();
    return b(
      this.rows,
      this.columns,
      this.grid,
      t,
      n
    );
  }
  /**
   * Add a custom panel to the info bar.
   * @param panel - The panel configuration to add
   */
  addPanel(t) {
    this.config.customPanels || (this.config.customPanels = []), this.config.customPanels.push(t), this.requestRender();
  }
  /**
   * Remove a custom panel by ID.
   * @param id - The panel ID to remove
   */
  removePanel(t) {
    this.config.customPanels && (this.config.customPanels = this.config.customPanels.filter((n) => n.id !== t), this.requestRender());
  }
  /**
   * Add an aggregation row.
   * @param row - The aggregation row configuration
   */
  addAggregationRow(t) {
    this.config.aggregationRows || (this.config.aggregationRows = []), this.config.aggregationRows.push(t), this.requestRender();
  }
  /**
   * Remove an aggregation row by ID.
   * @param id - The aggregation row ID to remove
   */
  removeAggregationRow(t) {
    this.config.aggregationRows && (this.config.aggregationRows = this.config.aggregationRows.filter((n) => n.id !== t), this.requestRender());
  }
  // #endregion
  // #region Styles
  styles = x;
  // #endregion
}
export {
  y as PinnedRowsPlugin
};
//# sourceMappingURL=index.js.map
