const P = {
  expand: "▶",
  collapse: "▼",
  sortAsc: "▲",
  sortDesc: "▼",
  sortNone: "⇅",
  submenuArrow: "▶",
  dragHandle: "⋮⋮",
  toolPanel: "☰"
};
class N {
  /** 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(e = {}) {
    this.userConfig = e;
  }
  /**
   * Called when the plugin is attached to a grid.
   * Override to set up event listeners, initialize state, etc.
   */
  attach(e) {
    this.grid = e, 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(e) {
    return this.grid?.getPlugin(e);
  }
  /**
   * Emit a custom event from the grid.
   */
  emit(e, i) {
    this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: i, 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 e = this.grid?.gridConfig?.icons ?? {};
    return { ...P, ...e };
  }
  /**
   * 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(e, i) {
    return i !== void 0 ? i : this.gridIcons[e];
  }
  /**
   * 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(e, i) {
    typeof i == "string" ? e.innerHTML = i : i instanceof HTMLElement && (e.innerHTML = "", e.appendChild(i.cloneNode(!0)));
  }
  /**
   * Log a warning message.
   */
  warn(e) {
    console.warn(`[tbw-grid:${this.name}] ${e}`);
  }
  // #endregion
}
const m = {
  sum: (t, e) => t.reduce((i, o) => i + (Number(o[e]) || 0), 0),
  avg: (t, e) => {
    const i = t.reduce((o, r) => o + (Number(r[e]) || 0), 0);
    return t.length ? i / t.length : 0;
  },
  count: (t) => t.length,
  min: (t, e) => Math.min(...t.map((i) => Number(i[e]) || 1 / 0)),
  max: (t, e) => Math.max(...t.map((i) => Number(i[e]) || -1 / 0)),
  first: (t, e) => t[0]?.[e],
  last: (t, e) => t[t.length - 1]?.[e]
}, v = /* @__PURE__ */ new Map(), h = {
  /**
   * Register a custom aggregator function.
   */
  register(t, e) {
    v.set(t, e);
  },
  /**
   * Unregister a custom aggregator function.
   */
  unregister(t) {
    v.delete(t);
  },
  /**
   * Get an aggregator function by reference.
   */
  get(t) {
    if (t !== void 0)
      return typeof t == "function" ? t : v.get(t) ?? m[t];
  },
  /**
   * Run an aggregator on a set of rows.
   */
  run(t, e, i, o) {
    const r = this.get(t);
    return r ? r(e, i, o) : void 0;
  },
  /**
   * Check if an aggregator exists.
   */
  has(t) {
    return v.has(t) || t in m;
  },
  /**
   * List all available aggregator names.
   */
  list() {
    return [...Object.keys(m), ...v.keys()];
  }
}, A = {
  sum: (t) => t.reduce((e, i) => e + i, 0),
  avg: (t) => t.length ? t.reduce((e, i) => e + i, 0) / t.length : 0,
  count: (t) => t.length,
  min: (t) => t.length ? Math.min(...t) : 0,
  max: (t) => t.length ? Math.max(...t) : 0,
  first: (t) => t[0] ?? 0,
  last: (t) => t[t.length - 1] ?? 0
};
function k(t) {
  return A[t] ?? A.sum;
}
h.register.bind(h);
h.unregister.bind(h);
h.get.bind(h);
h.run.bind(h);
h.list.bind(h);
const K = k;
function I(t) {
  const e = [];
  return !t.rowGroupFields?.length && !t.columnGroupFields?.length && e.push("At least one row or column group field is required"), t.valueFields?.length || e.push("At least one value field is required"), e;
}
function C(t, e) {
  return [...t, e].join("|");
}
function S(t, e) {
  const i = e.rowGroupFields ?? [], o = e.columnGroupFields ?? [], r = e.valueFields ?? [], n = V(t, o), a = L(
    t,
    i,
    o,
    n,
    r,
    0,
    // starting depth
    ""
    // parent key prefix
  ), s = H(a, n, r), l = Object.values(s).reduce((d, c) => d + c, 0);
  return {
    rows: a,
    columnKeys: n,
    totals: s,
    grandTotal: l
  };
}
function V(t, e) {
  if (e.length === 0) return ["value"];
  const i = /* @__PURE__ */ new Set();
  for (const o of t) {
    const r = e.map((n) => String(o[n] ?? "")).join("|");
    i.add(r);
  }
  return [...i].sort();
}
function M(t, e) {
  const i = /* @__PURE__ */ new Map();
  for (const o of t) {
    const r = String(o[e] ?? ""), n = i.get(r);
    n ? n.push(o) : i.set(r, [o]);
  }
  return i;
}
function L(t, e, i, o, r, n, a) {
  const s = [];
  if (e.length === 0) {
    const u = _(t, i, o, r), g = G(u);
    return s.push({
      rowKey: a || "all",
      rowLabel: a || "All",
      depth: n,
      values: u,
      total: g,
      isGroup: !1,
      rowCount: t.length
    }), s;
  }
  const l = e[0], d = e.slice(1), c = d.length > 0, p = M(t, l);
  for (const [u, g] of p) {
    const F = a ? `${a}|${u}` : u, y = _(g, i, o, r), E = G(y);
    let R;
    c && (R = L(
      g,
      d,
      i,
      o,
      r,
      n + 1,
      F
    )), s.push({
      rowKey: F,
      rowLabel: u || "(blank)",
      depth: n,
      values: y,
      total: E,
      isGroup: c,
      children: R,
      rowCount: g.length
    });
  }
  return s;
}
function _(t, e, i, o) {
  const r = {};
  for (const n of i)
    for (const a of o) {
      const l = (e.length > 0 ? t.filter((u) => e.map((g) => String(u[g] ?? "")).join("|") === n) : t).map((u) => Number(u[a.field]) || 0), d = K(a.aggFunc), c = l.length > 0 ? d(l) : null, p = C([n], a.field);
      r[p] = c;
    }
  return r;
}
function G(t) {
  let e = 0;
  for (const i of Object.values(t))
    e += i ?? 0;
  return e;
}
function H(t, e, i) {
  const o = {};
  function r(n) {
    for (const a of n)
      if (!a.isGroup || !a.children?.length)
        for (const s of e)
          for (const l of i) {
            const d = C([s], l.field);
            o[d] = (o[d] ?? 0) + (a.values[d] ?? 0);
          }
      else a.children && r(a.children);
  }
  return r(t), o;
}
function D(t, e, i = !0) {
  const o = [];
  function r(n) {
    o.push(n);
    const a = e ? e.has(n.rowKey) : i;
    if (n.children && a)
      for (const s of n.children)
        r(s);
  }
  for (const n of t)
    r(n);
  return o;
}
function w(t) {
  const e = [];
  function i(o) {
    if (o.isGroup && e.push(o.rowKey), o.children)
      for (const r of o.children)
        i(r);
  }
  for (const o of t)
    i(o);
  return e;
}
const z = ["sum", "avg", "count", "min", "max", "first", "last"];
function q(t, e, i, o) {
  const r = new AbortController(), n = { config: e, callbacks: o, signal: r.signal }, a = document.createElement("div");
  return a.className = "tbw-pivot-panel", a.appendChild(f("Options", () => U(i, n))), a.appendChild(f("Row Groups", () => T("rowGroups", n))), a.appendChild(f("Column Groups", () => T("columnGroups", n))), a.appendChild(f("Values", () => Z(n))), a.appendChild(f("Available Fields", () => j(n))), t.appendChild(a), () => {
    r.abort(), a.remove();
  };
}
function f(t, e) {
  const i = document.createElement("div");
  i.className = "tbw-pivot-section";
  const o = document.createElement("div");
  o.className = "tbw-pivot-section-header", o.textContent = t;
  const r = document.createElement("div");
  return r.className = "tbw-pivot-section-content", r.appendChild(e()), i.appendChild(o), i.appendChild(r), i;
}
function T(t, e) {
  const { config: i, callbacks: o, signal: r } = e, n = document.createElement("div");
  n.className = "tbw-pivot-drop-zone", n.setAttribute("data-zone", t);
  const a = t === "rowGroups" ? i.rowGroupFields ?? [] : i.columnGroupFields ?? [];
  if (a.length === 0) {
    const s = document.createElement("div");
    s.className = "tbw-pivot-placeholder", s.textContent = "Drag fields here or click to add", n.appendChild(s);
  } else
    for (const s of a)
      n.appendChild(O(s, t, e));
  return n.addEventListener(
    "dragover",
    (s) => {
      s.preventDefault(), n.classList.add("drag-over");
    },
    { signal: r }
  ), n.addEventListener(
    "dragleave",
    () => {
      n.classList.remove("drag-over");
    },
    { signal: r }
  ), n.addEventListener(
    "drop",
    (s) => {
      s.preventDefault(), n.classList.remove("drag-over");
      const l = s.dataTransfer?.getData("text/plain");
      l && o.onAddFieldToZone(l, t);
    },
    { signal: r }
  ), n;
}
function O(t, e, i) {
  const { callbacks: o, signal: r } = i, n = document.createElement("div");
  n.className = "tbw-pivot-field-chip", n.draggable = !0;
  const a = o.getAvailableFields().find((d) => d.field === t), s = document.createElement("span");
  s.className = "tbw-pivot-chip-label", s.textContent = a?.header ?? t;
  const l = document.createElement("button");
  return l.className = "tbw-pivot-chip-remove", l.innerHTML = "×", l.title = "Remove field", l.addEventListener(
    "click",
    (d) => {
      d.stopPropagation(), o.onRemoveFieldFromZone(t, e);
    },
    { signal: r }
  ), n.appendChild(s), n.appendChild(l), n.addEventListener(
    "dragstart",
    (d) => {
      d.dataTransfer?.setData("text/plain", t), d.dataTransfer?.setData("source-zone", e), n.classList.add("dragging");
    },
    { signal: r }
  ), n.addEventListener(
    "dragend",
    () => {
      n.classList.remove("dragging");
    },
    { signal: r }
  ), n;
}
function Z(t) {
  const { config: e, callbacks: i, signal: o } = t, r = document.createElement("div");
  r.className = "tbw-pivot-drop-zone tbw-pivot-values-zone", r.setAttribute("data-zone", "values");
  const n = e.valueFields ?? [];
  if (n.length === 0) {
    const a = document.createElement("div");
    a.className = "tbw-pivot-placeholder", a.textContent = "Drag numeric fields here for aggregation", r.appendChild(a);
  } else
    for (const a of n)
      r.appendChild($(a, t));
  return r.addEventListener(
    "dragover",
    (a) => {
      a.preventDefault(), r.classList.add("drag-over");
    },
    { signal: o }
  ), r.addEventListener(
    "dragleave",
    () => {
      r.classList.remove("drag-over");
    },
    { signal: o }
  ), r.addEventListener(
    "drop",
    (a) => {
      a.preventDefault(), r.classList.remove("drag-over");
      const s = a.dataTransfer?.getData("text/plain");
      s && i.onAddValueField(s, "sum");
    },
    { signal: o }
  ), r;
}
function $(t, e) {
  const { callbacks: i, signal: o } = e, r = document.createElement("div");
  r.className = "tbw-pivot-field-chip tbw-pivot-value-chip";
  const n = i.getAvailableFields().find((c) => c.field === t.field), a = document.createElement("div");
  a.className = "tbw-pivot-value-label-wrapper";
  const s = document.createElement("span");
  s.className = "tbw-pivot-chip-label", s.textContent = n?.header ?? t.field;
  const l = document.createElement("select");
  l.className = "tbw-pivot-agg-select", l.title = "Aggregation function";
  for (const c of z) {
    const p = document.createElement("option");
    p.value = c, p.textContent = c.toUpperCase(), p.selected = c === t.aggFunc, l.appendChild(p);
  }
  l.addEventListener(
    "change",
    () => {
      i.onUpdateValueAggFunc(t.field, l.value);
    },
    { signal: o }
  );
  const d = document.createElement("button");
  return d.className = "tbw-pivot-chip-remove", d.innerHTML = "×", d.title = "Remove value field", d.addEventListener(
    "click",
    (c) => {
      c.stopPropagation(), i.onRemoveValueField(t.field);
    },
    { signal: o }
  ), a.appendChild(s), a.appendChild(l), r.appendChild(a), r.appendChild(d), r;
}
function j(t) {
  const { config: e, callbacks: i, signal: o } = t, r = document.createElement("div");
  r.className = "tbw-pivot-available-fields";
  const n = i.getAvailableFields(), a = /* @__PURE__ */ new Set([
    ...e.rowGroupFields ?? [],
    ...e.columnGroupFields ?? [],
    ...e.valueFields?.map((l) => l.field) ?? []
  ]), s = n.filter((l) => !a.has(l.field));
  if (s.length === 0) {
    const l = document.createElement("div");
    l.className = "tbw-pivot-placeholder", l.textContent = "All fields are in use", r.appendChild(l);
  } else
    for (const l of s) {
      const d = document.createElement("div");
      d.className = "tbw-pivot-field-chip available", d.textContent = l.header, d.draggable = !0, d.title = `Drag to add "${l.field}" to a zone`, d.addEventListener(
        "dragstart",
        (c) => {
          c.dataTransfer?.setData("text/plain", l.field), d.classList.add("dragging");
        },
        { signal: o }
      ), d.addEventListener(
        "dragend",
        () => {
          d.classList.remove("dragging");
        },
        { signal: o }
      ), r.appendChild(d);
    }
  return r;
}
function U(t, e) {
  const { config: i, callbacks: o, signal: r } = e, n = document.createElement("div");
  return n.className = "tbw-pivot-options", n.appendChild(
    x(
      "Enable Pivot View",
      t,
      (a) => {
        o.onTogglePivot(a);
      },
      r
    )
  ), n.appendChild(
    x(
      "Show Row Totals",
      i.showTotals ?? !0,
      (a) => {
        o.onOptionChange("showTotals", a);
      },
      r
    )
  ), n.appendChild(
    x(
      "Show Grand Total",
      i.showGrandTotal ?? !0,
      (a) => {
        o.onOptionChange("showGrandTotal", a);
      },
      r
    )
  ), n;
}
function x(t, e, i, o) {
  const r = document.createElement("label");
  r.className = "tbw-pivot-checkbox";
  const n = document.createElement("input");
  n.type = "checkbox", n.checked = e, n.addEventListener("change", () => i(n.checked), { signal: o });
  const a = document.createElement("span");
  return a.textContent = t, r.appendChild(n), r.appendChild(a), r;
}
function B(t, e, i) {
  return e.className = "pivot-group-row", e.setAttribute("data-pivot-depth", String(t.__pivotDepth ?? 0)), e.setAttribute("role", "row"), e.innerHTML = "", i.columns.forEach((o, r) => {
    const n = document.createElement("div");
    if (n.className = "cell", n.setAttribute("data-col", String(r)), n.setAttribute("role", "gridcell"), r === 0) {
      const a = Number(t.__pivotIndent) || 0;
      n.style.paddingLeft = `${a}px`;
      const s = String(t.__pivotRowKey), l = document.createElement("button");
      l.type = "button", l.className = "pivot-toggle", l.setAttribute("aria-label", t.__pivotExpanded ? "Collapse group" : "Expand group"), i.setIcon(l, i.resolveIcon(t.__pivotExpanded ? "collapse" : "expand")), l.addEventListener("click", (p) => {
        p.stopPropagation(), i.onToggle(s);
      }), n.appendChild(l);
      const d = document.createElement("span");
      d.className = "pivot-label", d.textContent = String(t.__pivotLabel ?? ""), n.appendChild(d);
      const c = document.createElement("span");
      c.className = "pivot-count", c.textContent = ` (${Number(t.__pivotRowCount) || 0})`, n.appendChild(c);
    } else {
      const a = t[o.field];
      n.textContent = a != null ? String(a) : "";
    }
    e.appendChild(n);
  }), !0;
}
function W(t, e, i) {
  return e.className = "pivot-leaf-row", e.setAttribute("data-pivot-depth", String(t.__pivotDepth ?? 0)), e.innerHTML = "", i.forEach((o, r) => {
    const n = document.createElement("div");
    if (n.className = "cell", n.setAttribute("data-col", String(r)), n.setAttribute("role", "gridcell"), r === 0) {
      const a = Number(t.__pivotIndent) || 0;
      n.style.paddingLeft = `${a + 20}px`;
      const s = document.createElement("span");
      s.className = "pivot-label", s.textContent = String(t.__pivotLabel ?? ""), n.appendChild(s);
    } else {
      const a = t[o.field];
      n.textContent = a != null ? String(a) : "";
    }
    e.appendChild(n);
  }), !0;
}
function J(t, e, i) {
  return e.className = "pivot-grand-total-row", e.setAttribute("role", "presentation"), e.innerHTML = "", i.forEach((o, r) => {
    const n = document.createElement("div");
    if (n.className = "cell", n.setAttribute("data-col", String(r)), r === 0) {
      const a = document.createElement("span");
      a.className = "pivot-label", a.textContent = "Grand Total", n.appendChild(a);
    } else {
      const a = t[o.field];
      n.textContent = a != null ? String(a) : "";
    }
    e.appendChild(n);
  }), !0;
}
const Q = '.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;font-size:10px;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}';
class b extends N {
  name = "pivot";
  version = "1.0.0";
  /** Tool panel ID for shell integration */
  static PANEL_ID = "pivot";
  get defaultConfig() {
    return {
      active: !0,
      showTotals: !0,
      showGrandTotal: !0
    };
  }
  // #region Internal State
  isActive = !1;
  hasInitialized = !1;
  pivotResult = null;
  fieldHeaderMap = /* @__PURE__ */ new Map();
  expandedKeys = /* @__PURE__ */ new Set();
  defaultExpanded = !0;
  originalColumns = [];
  panelContainer = null;
  grandTotalFooter = null;
  /**
   * Check if the plugin has valid pivot configuration (at least value fields).
   */
  hasValidPivotConfig() {
    return (this.config.valueFields?.length ?? 0) > 0;
  }
  // #endregion
  // #region Lifecycle
  detach() {
    this.isActive = !1, this.hasInitialized = !1, this.pivotResult = null, this.fieldHeaderMap.clear(), this.originalColumns = [], this.panelContainer = null, this.cleanupGrandTotalFooter();
  }
  // #endregion
  // #region Shell Integration
  getToolPanel() {
    return {
      id: b.PANEL_ID,
      title: "Pivot",
      icon: "⊞",
      tooltip: "Configure pivot table",
      order: 90,
      render: (e) => this.renderPanel(e)
    };
  }
  // #endregion
  // #region Hooks
  processRows(e) {
    if (!this.hasInitialized && this.config.active !== !1 && this.hasValidPivotConfig() && (this.hasInitialized = !0, this.isActive = !0), !this.isActive)
      return [...e];
    const i = I(this.config);
    if (i.length > 0)
      return this.warn(`Config errors: ${i.join(", ")}`), [...e];
    if (this.buildFieldHeaderMap(), this.defaultExpanded = this.config.defaultExpanded ?? !0, this.expandedKeys.size === 0 && this.defaultExpanded && this.pivotResult) {
      const n = w(this.pivotResult.rows);
      for (const a of n)
        this.expandedKeys.add(a);
    }
    if (this.pivotResult = S(e, this.config), this.expandedKeys.size === 0 && this.defaultExpanded) {
      const n = w(this.pivotResult.rows);
      for (const a of n)
        this.expandedKeys.add(a);
    }
    const o = this.config.indentWidth ?? 20;
    return D(
      this.pivotResult.rows,
      this.expandedKeys,
      this.defaultExpanded
    ).map((n) => ({
      __pivotRowKey: n.rowKey,
      __pivotLabel: n.rowLabel,
      __pivotDepth: n.depth,
      __pivotIsGroup: n.isGroup,
      __pivotHasChildren: !!n.children?.length,
      __pivotExpanded: this.expandedKeys.has(n.rowKey),
      __pivotRowCount: n.rowCount ?? 0,
      __pivotIndent: n.depth * o,
      __pivotTotal: n.total,
      ...n.values
    }));
  }
  processColumns(e) {
    if (!this.isActive || !this.pivotResult)
      return [...e];
    const i = [], o = (this.config.rowGroupFields ?? []).map((r) => this.fieldHeaderMap.get(r) ?? r).join(" / ");
    i.push({
      field: "__pivotLabel",
      header: o || "Group",
      width: 200
    });
    for (const r of this.pivotResult.columnKeys)
      for (const n of this.config.valueFields ?? []) {
        const a = C([r], n.field), s = n.header || this.fieldHeaderMap.get(n.field) || n.field;
        i.push({
          field: a,
          header: `${r} - ${s} (${n.aggFunc})`,
          width: 120,
          type: "number"
        });
      }
    return this.config.showTotals && i.push({
      field: "__pivotTotal",
      header: "Total",
      width: 100,
      type: "number"
    }), i;
  }
  renderRow(e, i) {
    const o = e;
    return o.__pivotRowKey && o.__pivotHasChildren ? B(o, i, {
      columns: this.gridColumns,
      onToggle: (r) => this.toggle(r),
      resolveIcon: (r) => this.resolveIcon(r),
      setIcon: (r, n) => this.setIcon(r, n)
    }) : o.__pivotRowKey !== void 0 && this.isActive ? W(o, i, this.gridColumns) : (this.cleanupPivotStyling(i), !1);
  }
  /**
   * Remove pivot-specific classes, attributes, and inline styles from a row element.
   * Called when pivot mode is disabled to clean up reused DOM elements.
   * Clears innerHTML so the grid's default renderer can rebuild the row.
   */
  cleanupPivotStyling(e) {
    (e.classList.contains("pivot-group-row") || e.classList.contains("pivot-leaf-row") || e.classList.contains("pivot-grand-total-row")) && (e.classList.remove("pivot-group-row", "pivot-leaf-row", "pivot-grand-total-row"), e.classList.add("data-grid-row"), e.removeAttribute("data-pivot-depth"), e.innerHTML = "");
  }
  afterRender() {
    this.isActive && this.config.showGrandTotal && this.pivotResult ? this.renderGrandTotalFooter() : this.cleanupGrandTotalFooter();
  }
  /**
   * Render the grand total row as a sticky footer pinned to the bottom.
   */
  renderGrandTotalFooter() {
    if (!this.pivotResult) return;
    const e = this.shadowRoot;
    if (!e) return;
    const i = e.querySelector(".tbw-scroll-area") ?? e.querySelector(".tbw-grid-content") ?? e.children[0];
    if (!i) return;
    this.grandTotalFooter || (this.grandTotalFooter = document.createElement("div"), this.grandTotalFooter.className = "pivot-grand-total-footer", i.appendChild(this.grandTotalFooter));
    const o = {
      __pivotRowKey: "__grandTotal",
      __pivotLabel: "Grand Total",
      __pivotIsGrandTotal: !0,
      __pivotTotal: this.pivotResult.grandTotal,
      ...this.pivotResult.totals
    };
    J(o, this.grandTotalFooter, this.gridColumns);
  }
  /**
   * Remove the grand total footer element.
   */
  cleanupGrandTotalFooter() {
    this.grandTotalFooter && (this.grandTotalFooter.remove(), this.grandTotalFooter = null);
  }
  // #endregion
  // #region Expand/Collapse API
  toggle(e) {
    this.expandedKeys.has(e) ? this.expandedKeys.delete(e) : this.expandedKeys.add(e), this.requestRender();
  }
  expand(e) {
    this.expandedKeys.add(e), this.requestRender();
  }
  collapse(e) {
    this.expandedKeys.delete(e), this.requestRender();
  }
  expandAll() {
    if (this.pivotResult) {
      const e = w(this.pivotResult.rows);
      for (const i of e)
        this.expandedKeys.add(i);
      this.requestRender();
    }
  }
  collapseAll() {
    this.expandedKeys.clear(), this.requestRender();
  }
  isExpanded(e) {
    return this.expandedKeys.has(e);
  }
  // #endregion
  // #region Public API
  enablePivot() {
    this.originalColumns.length === 0 && this.captureOriginalColumns(), this.isActive = !0, this.requestRender();
  }
  disablePivot() {
    this.isActive = !1, this.pivotResult = null, this.requestRender();
  }
  isPivotActive() {
    return this.isActive;
  }
  getPivotResult() {
    return this.pivotResult;
  }
  setRowGroupFields(e) {
    this.config.rowGroupFields = e, this.requestRender();
  }
  setColumnGroupFields(e) {
    this.config.columnGroupFields = e, this.requestRender();
  }
  setValueFields(e) {
    this.config.valueFields = e, this.requestRender();
  }
  refresh() {
    this.pivotResult = null, this.requestRender();
  }
  // #endregion
  // #region Tool Panel API
  showPanel() {
    this.grid.openToolPanel(b.PANEL_ID);
  }
  hidePanel() {
    this.grid.closeToolPanel();
  }
  togglePanel() {
    this.grid.toggleToolPanel(b.PANEL_ID);
  }
  isPanelVisible() {
    return this.grid.activeToolPanel === b.PANEL_ID;
  }
  // #endregion
  // #region Private Helpers
  get gridColumns() {
    return this.grid.columns ?? [];
  }
  buildFieldHeaderMap() {
    const e = this.getAvailableFields();
    this.fieldHeaderMap.clear();
    for (const i of e)
      this.fieldHeaderMap.set(i.field, i.header);
  }
  getAvailableFields() {
    return this.originalColumns.length > 0 ? this.originalColumns : this.captureOriginalColumns();
  }
  captureOriginalColumns() {
    const e = this.grid;
    try {
      const i = e.getAllColumns?.() ?? e.columns ?? [];
      return this.originalColumns = i.filter((o) => !o.field.startsWith("__pivot")).map((o) => ({
        field: o.field,
        header: o.header ?? o.field
      })), this.originalColumns;
    } catch {
      return [];
    }
  }
  renderPanel(e) {
    this.panelContainer = e, this.originalColumns.length === 0 && this.captureOriginalColumns();
    const i = {
      onTogglePivot: (o) => {
        o ? this.enablePivot() : this.disablePivot(), this.refreshPanel();
      },
      onAddFieldToZone: (o, r) => this.addFieldToZone(o, r),
      onRemoveFieldFromZone: (o, r) => this.removeFieldFromZone(o, r),
      onAddValueField: (o, r) => this.addValueField(o, r),
      onRemoveValueField: (o) => this.removeValueField(o),
      onUpdateValueAggFunc: (o, r) => this.updateValueAggFunc(o, r),
      onOptionChange: (o, r) => {
        this.config[o] = r, this.isActive && this.refresh();
      },
      getAvailableFields: () => this.getAvailableFields()
    };
    return q(e, this.config, this.isActive, i);
  }
  refreshPanel() {
    this.panelContainer && (this.panelContainer.innerHTML = "", this.renderPanel(this.panelContainer));
  }
  addFieldToZone(e, i) {
    if (i === "rowGroups") {
      const o = this.config.rowGroupFields ?? [];
      o.includes(e) || (this.config.rowGroupFields = [...o, e]);
    } else {
      const o = this.config.columnGroupFields ?? [];
      o.includes(e) || (this.config.columnGroupFields = [...o, e]);
    }
    this.removeFromOtherZones(e, i), this.isActive && this.refresh(), this.refreshPanel();
  }
  removeFieldFromZone(e, i) {
    i === "rowGroups" ? this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((o) => o !== e) : this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((o) => o !== e), this.isActive && this.refresh(), this.refreshPanel();
  }
  removeFromOtherZones(e, i) {
    i !== "rowGroups" && (this.config.rowGroupFields = (this.config.rowGroupFields ?? []).filter((o) => o !== e)), i !== "columnGroups" && (this.config.columnGroupFields = (this.config.columnGroupFields ?? []).filter((o) => o !== e)), i !== "values" && (this.config.valueFields = (this.config.valueFields ?? []).filter((o) => o.field !== e));
  }
  addValueField(e, i) {
    const o = this.config.valueFields ?? [];
    o.some((r) => r.field === e) || (this.config.valueFields = [...o, { field: e, aggFunc: i }]), this.removeFromOtherZones(e, "values"), this.isActive && this.refresh(), this.refreshPanel();
  }
  removeValueField(e) {
    this.config.valueFields = (this.config.valueFields ?? []).filter((i) => i.field !== e), this.isActive && this.refresh(), this.refreshPanel();
  }
  updateValueAggFunc(e, i) {
    const o = this.config.valueFields ?? [], r = o.findIndex((n) => n.field === e);
    r >= 0 && (o[r] = { ...o[r], aggFunc: i }, this.config.valueFields = [...o]), this.isActive && this.refresh();
  }
  // #endregion
  // #region Styles
  styles = Q;
  // #endregion
}
export {
  b as PivotPlugin
};
//# sourceMappingURL=index.js.map
