const C = {
  expand: "▶",
  collapse: "▼",
  sortAsc: "▲",
  sortDesc: "▼",
  sortNone: "⇅",
  submenuArrow: "▶",
  dragHandle: "⋮⋮",
  toolPanel: "☰"
}, b = {
  /** Ask if a column can be moved. Context: ColumnConfig. Response: boolean | undefined */
  CAN_MOVE_COLUMN: "canMoveColumn"
};
class v {
  /** 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, r) {
    this.grid?.dispatchEvent?.(new CustomEvent(e, { detail: r, 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 { ...C, ...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, r) {
    return r !== void 0 ? r : 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, r) {
    typeof r == "string" ? e.innerHTML = r : r instanceof HTMLElement && (e.innerHTML = "", e.appendChild(r.cloneNode(!0)));
  }
  /**
   * Log a warning message.
   */
  warn(e) {
    console.warn(`[tbw-grid:${this.name}] ${e}`);
  }
  // #endregion
}
function w(i) {
  const e = i.meta ?? {};
  return e.lockPosition !== !0 && e.suppressMovable !== !0;
}
function h(i, e, r) {
  if (e === r || e < 0 || e >= i.length || r < 0 || r > i.length) return i;
  const s = [...i], [t] = s.splice(e, 1);
  return s.splice(r, 0, t), s;
}
const O = '.header-row>.cell[draggable=true]{cursor:grab;position:relative}.header-row>.cell.dragging{opacity:.5;cursor:grabbing}.header-row>.cell.drop-before:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}.header-row>.cell.drop-after:after{content:"";position:absolute;right:0;top:0;bottom:0;width:2px;background:var(--tbw-reorder-indicator, var(--tbw-color-accent));z-index:1}';
class E extends v {
  name = "reorder";
  version = "1.0.0";
  get defaultConfig() {
    return {
      animation: !0,
      animationDuration: 200
    };
  }
  // #region Internal State
  isDragging = !1;
  draggedField = null;
  draggedIndex = null;
  dropIndex = null;
  // #endregion
  // #region Lifecycle
  attach(e) {
    super.attach(e), e.addEventListener(
      "column-reorder-request",
      (r) => {
        const s = r.detail;
        s?.field && typeof s.toIndex == "number" && this.moveColumn(s.field, s.toIndex);
      },
      { signal: this.disconnectSignal }
    );
  }
  detach() {
    this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null;
  }
  // #endregion
  // #region Hooks
  // Note: No processColumns hook needed - we directly update the grid's column order
  afterRender() {
    const e = this.shadowRoot;
    if (!e) return;
    e.querySelectorAll(".header-row > .cell").forEach((s) => {
      const t = s, d = t.getAttribute("data-field");
      if (!d) return;
      const u = this.columns.find((n) => n.field === d), f = !this.grid.queryPlugins({
        type: b.CAN_MOVE_COLUMN,
        context: u
      }).includes(!1);
      if (!u || !w(u) || !f) {
        t.draggable = !1;
        return;
      }
      t.draggable = !0, !t.getAttribute("data-dragstart-bound") && (t.setAttribute("data-dragstart-bound", "true"), t.addEventListener("dragstart", (n) => {
        const o = this.getColumnOrder().indexOf(d);
        this.isDragging = !0, this.draggedField = d, this.draggedIndex = o, n.dataTransfer && (n.dataTransfer.effectAllowed = "move", n.dataTransfer.setData("text/plain", d)), t.classList.add("dragging");
      }), t.addEventListener("dragend", () => {
        this.isDragging = !1, this.draggedField = null, this.draggedIndex = null, this.dropIndex = null, e.querySelectorAll(".header-row > .cell").forEach((n) => {
          n.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
        });
      }), t.addEventListener("dragover", (n) => {
        if (n.preventDefault(), !this.isDragging || this.draggedField === d) return;
        const a = t.getBoundingClientRect(), o = a.left + a.width / 2, g = this.getColumnOrder().indexOf(d);
        this.dropIndex = n.clientX < o ? g : g + 1, t.classList.add("drop-target"), t.classList.toggle("drop-before", n.clientX < o), t.classList.toggle("drop-after", n.clientX >= o);
      }), t.addEventListener("dragleave", () => {
        t.classList.remove("drop-target", "drop-before", "drop-after");
      }), t.addEventListener("drop", (n) => {
        n.preventDefault();
        const a = this.draggedField, o = this.draggedIndex, l = this.dropIndex;
        if (!this.isDragging || a === null || o === null || l === null)
          return;
        const g = l > o ? l - 1 : l, p = this.getColumnOrder(), c = h(p, o, g), m = {
          field: a,
          fromIndex: o,
          toIndex: g,
          columnOrder: c
        };
        this.grid.setColumnOrder(c), this.emit("column-move", m), this.grid.requestStateChange?.();
      }));
    });
  }
  // #endregion
  // #region Public API
  /**
   * Get the current column order from the grid.
   * @returns Array of field names in display order
   */
  getColumnOrder() {
    return this.grid.getColumnOrder();
  }
  /**
   * Move a column to a new position.
   * @param field - The field name of the column to move
   * @param toIndex - The target index
   */
  moveColumn(e, r) {
    const s = this.getColumnOrder(), t = s.indexOf(e);
    if (t === -1) return;
    const d = h(s, t, r);
    this.grid.setColumnOrder(d), this.emit("column-move", {
      field: e,
      fromIndex: t,
      toIndex: r,
      columnOrder: d
    }), this.grid.requestStateChange?.();
  }
  /**
   * Set a specific column order.
   * @param order - Array of field names in desired order
   */
  setColumnOrder(e) {
    this.grid.setColumnOrder(e), this.grid.requestStateChange?.();
  }
  /**
   * Reset column order to the original configuration order.
   */
  resetColumnOrder() {
    const e = this.columns.map((r) => r.field);
    this.grid.setColumnOrder(e), this.grid.requestStateChange?.();
  }
  // #endregion
  // #region Styles
  styles = O;
  // #endregion
}
export {
  E as ReorderPlugin
};
//# sourceMappingURL=index.js.map
