function v(l) {
  l && l.querySelectorAll(".cell-focus").forEach((e) => e.classList.remove("cell-focus"));
}
const m = 'input,select,textarea,[contenteditable="true"],[contenteditable=""],[tabindex]:not([tabindex="-1"])', R = document.createElement("template");
R.innerHTML = '<div class="cell" role="gridcell" part="cell"></div>';
const E = document.createElement("template");
E.innerHTML = '<div class="data-grid-row" role="row" part="row"></div>';
function p(l, e) {
  if (l._virtualization?.enabled) {
    const { rowHeight: o, container: n, viewportEl: c } = l._virtualization, a = n, u = c?.clientHeight ?? a?.clientHeight ?? 0;
    if (a && u > 0) {
      const d = l._focusRow * o;
      d < a.scrollTop ? a.scrollTop = d : d + o > a.scrollTop + u && (a.scrollTop = d - u + o);
    }
  }
  const r = l._activeEditRows !== void 0 && l._activeEditRows !== -1;
  r || l.refreshVirtualWindow(!1), v(l._bodyEl), Array.from(l._bodyEl.querySelectorAll('[aria-selected="true"]')).forEach((o) => {
    o.setAttribute("aria-selected", "false");
  });
  const t = l._focusRow, i = l._virtualization.start ?? 0, s = l._virtualization.end ?? l._rows.length;
  if (t >= i && t < s) {
    const o = l._bodyEl.querySelectorAll(".data-grid-row")[t - i];
    let n = o?.children[l._focusCol];
    if ((!n || !n.classList?.contains("cell")) && (n = o?.querySelector(`.cell[data-col="${l._focusCol}"]`) ?? o?.querySelector(".cell[data-col]")), n) {
      n.classList.add("cell-focus"), n.setAttribute("aria-selected", "true");
      const c = l.querySelector(".tbw-scroll-area");
      if (c && n && !r) {
        const a = l._getHorizontalScrollOffsets?.(o ?? void 0, n) ?? { left: 0, right: 0 };
        if (!a.skipScroll) {
          const u = n.getBoundingClientRect(), d = c.getBoundingClientRect(), g = u.left - d.left + c.scrollLeft, h = g + u.width, w = c.scrollLeft + a.left, f = c.scrollLeft + c.clientWidth - a.right;
          g < w ? c.scrollLeft = g - a.left : h > f && (c.scrollLeft = h - c.clientWidth + a.right);
        }
      }
      if (l._activeEditRows !== void 0 && l._activeEditRows !== -1 && n.classList.contains("editing")) {
        const a = n.querySelector(m);
        if (a && document.activeElement !== a)
          try {
            a.focus({ preventScroll: !0 });
          } catch {
          }
      } else if (!n.contains(document.activeElement)) {
        n.hasAttribute("tabindex") || n.setAttribute("tabindex", "-1");
        try {
          n.focus({ preventScroll: !0 });
        } catch {
        }
      }
    }
  }
}
const b = '<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>', y = {
  expand: "▶",
  collapse: "▼",
  sortAsc: "▲",
  sortDesc: "▼",
  sortNone: "⇅",
  submenuArrow: "▶",
  dragHandle: "⋮⋮",
  toolPanel: "☰",
  filter: b,
  filterActive: b,
  print: "🖨️"
};
class _ {
  /**
   * Plugin dependencies - declare other plugins this one requires.
   *
   * Dependencies are validated when the plugin is attached.
   * Required dependencies throw an error if missing.
   * Optional dependencies log an info message if missing.
   *
   * @example
   * ```typescript
   * static readonly dependencies: PluginDependency[] = [
   *   { name: 'editing', required: true, reason: 'Tracks cell edits for undo/redo' },
   *   { name: 'selection', required: false, reason: 'Enables selection-based undo' },
   * ];
   * ```
   */
  static dependencies;
  /**
   * Plugin manifest - declares owned properties, config rules, and hook priorities.
   *
   * This is read by the configuration validator to:
   * - Validate that required plugins are loaded when their properties are used
   * - Execute configRules to detect invalid/conflicting settings
   * - Order hook execution based on priority
   *
   * @example
   * ```typescript
   * static override readonly manifest: PluginManifest<MyConfig> = {
   *   ownedProperties: [
   *     { property: 'myProp', level: 'column', description: 'the "myProp" column property' },
   *   ],
   *   configRules: [
   *     { id: 'myPlugin/conflict', severity: 'warn', message: '...', check: (c) => c.a && c.b },
   *   ],
   * };
   * ```
   */
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  static manifest;
  /**
   * Plugin version - defaults to grid version for built-in plugins.
   * Third-party plugins can override with their own semver.
   */
  version = typeof __GRID_VERSION__ < "u" ? __GRID_VERSION__ : "dev";
  /** 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;
  /**
   * Plugin-level AbortController for event listener cleanup.
   * Created fresh in attach(), aborted in detach().
   * This ensures event listeners are properly cleaned up when plugins are re-attached.
   */
  #e;
  /**
   * 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.
   *
   * @example
   * ```ts
   * attach(grid: GridElement): void {
   *   super.attach(grid);
   *   // Set up document-level listeners with auto-cleanup
   *   document.addEventListener('keydown', this.handleEscape, {
   *     signal: this.disconnectSignal
   *   });
   * }
   * ```
   */
  attach(e) {
    this.#e?.abort(), this.#e = new AbortController(), 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.
   *
   * @example
   * ```ts
   * detach(): void {
   *   // Clean up any state not handled by disconnectSignal
   *   this.selectedRows.clear();
   *   this.cache = null;
   * }
   * ```
   */
  detach() {
    this.#e?.abort(), this.#e = void 0;
  }
  /**
   * Get another plugin instance from the same grid.
   * Use for inter-plugin communication.
   *
   * @example
   * ```ts
   * const selection = this.getPlugin(SelectionPlugin);
   * if (selection) {
   *   const selectedRows = selection.getSelectedRows();
   * }
   * ```
   */
  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 }));
  }
  /**
   * Emit a cancelable custom event from the grid.
   * @returns `true` if the event was cancelled (preventDefault called), `false` otherwise
   */
  emitCancelable(e, r) {
    const t = new CustomEvent(e, { detail: r, bubbles: !0, cancelable: !0 });
    return this.grid?.dispatchEvent?.(t), t.defaultPrevented;
  }
  /**
   * Request a re-render of the grid.
   */
  requestRender() {
    this.grid?.requestRender?.();
  }
  /**
   * Request a re-render and restore focus styling afterward.
   * Use this when a plugin action (like expand/collapse) triggers a render
   * but needs to maintain keyboard navigation focus.
   */
  requestRenderWithFocus() {
    this.grid?.requestRenderWithFocus?.();
  }
  /**
   * 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 grid as an HTMLElement for direct DOM operations.
   * Use sparingly - prefer the typed GridElementRef API when possible.
   *
   * @example
   * ```ts
   * const width = this.gridElement.clientWidth;
   * this.gridElement.classList.add('my-plugin-active');
   * ```
   */
  get gridElement() {
    return this.grid;
  }
  /**
   * 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.#e?.signal ?? this.grid?.disconnectSignal;
  }
  /**
   * Get the grid-level icons configuration.
   * Returns merged icons (user config + defaults).
   */
  get gridIcons() {
    const e = this.grid?.gridConfig?.icons ?? {};
    return { ...y, ...e };
  }
  // #region Animation Helpers
  /**
   * Check if animations are enabled at the grid level.
   * Respects gridConfig.animation.mode and the CSS variable set by the grid.
   *
   * Plugins should use this to skip animations when:
   * - Animation mode is 'off' or `false`
   * - User prefers reduced motion and mode is 'reduced-motion' (default)
   *
   * @example
   * ```ts
   * private get animationStyle(): 'slide' | 'fade' | false {
   *   if (!this.isAnimationEnabled) return false;
   *   return this.config.animation ?? 'slide';
   * }
   * ```
   */
  get isAnimationEnabled() {
    const e = this.grid?.effectiveConfig?.animation?.mode ?? "reduced-motion";
    if (e === !1 || e === "off") return !1;
    if (e === !0 || e === "on") return !0;
    const r = this.gridElement;
    return r ? getComputedStyle(r).getPropertyValue("--tbw-animation-enabled").trim() !== "0" : !0;
  }
  /**
   * Get the animation duration in milliseconds from CSS variable.
   * Falls back to 200ms if not set.
   *
   * Plugins can use this for their animation timing to stay consistent
   * with the grid-level animation.duration setting.
   *
   * @example
   * ```ts
   * element.animate(keyframes, { duration: this.animationDuration });
   * ```
   */
  get animationDuration() {
    const e = this.gridElement;
    if (e) {
      const r = getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(), t = parseInt(r, 10);
      if (!isNaN(t)) return t;
    }
    return 200;
  }
  // #endregion
  /**
   * 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
}
const C = '@layer tbw-plugins{.dg-row-drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;-webkit-user-select:none;user-select:none;color:var(--tbw-row-reorder-handle-color, var(--tbw-color-fg-muted));transition:color var(--tbw-transition-duration, .12s) var(--tbw-transition-ease, ease);font-size:var(--tbw-font-size, 1em);letter-spacing:-2px}.dg-row-drag-handle:hover{color:var(--tbw-row-reorder-handle-hover, var(--tbw-color-fg))}.dg-row-drag-handle:active{cursor:grabbing}.data-grid-row.dragging{opacity:.6}.data-grid-row.drop-target{position:relative}.data-grid-row.drop-target.drop-before:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background-color:var(--tbw-row-reorder-indicator, var(--tbw-color-accent));z-index:10}.data-grid-row.drop-target.drop-after:after{content:"";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--tbw-row-reorder-indicator, var(--tbw-color-accent));z-index:10}.data-grid-row.keyboard-moving{background-color:var(--tbw-row-reorder-moving-bg, var(--tbw-focus-background));box-shadow:0 0 0 1px var(--tbw-row-reorder-moving-border, var(--tbw-color-accent)) inset}.data-grid-row.flip-animating{transition:transform var(--tbw-animation-duration, .2s) ease-out;will-change:transform;z-index:1}}', A = "__tbw_row_drag";
class L extends _ {
  /** @internal */
  name = "rowReorder";
  /** @internal */
  styles = C;
  /** @internal */
  get defaultConfig() {
    return {
      enableKeyboard: !0,
      showDragHandle: !0,
      dragHandlePosition: "left",
      dragHandleWidth: 40,
      debounceMs: 150,
      animation: "flip"
    };
  }
  /**
   * Resolve animation type from plugin config.
   * Uses base class isAnimationEnabled to respect grid-level settings.
   */
  get animationType() {
    return this.isAnimationEnabled ? this.config.animation !== void 0 ? this.config.animation : "flip" : !1;
  }
  // #region Internal State
  isDragging = !1;
  draggedRowIndex = null;
  dropRowIndex = null;
  pendingMove = null;
  debounceTimer = null;
  /** Column index to use when flushing pending move */
  lastFocusCol = 0;
  // #endregion
  // #region Lifecycle
  /** @internal */
  detach() {
    this.clearDebounceTimer(), this.isDragging = !1, this.draggedRowIndex = null, this.dropRowIndex = null, this.pendingMove = null;
  }
  // #endregion
  // #region Hooks
  /** @internal */
  processColumns(e) {
    if (!this.config.showDragHandle)
      return [...e];
    const r = {
      field: A,
      header: "",
      width: this.config.dragHandleWidth ?? 40,
      resizable: !1,
      sortable: !1,
      filterable: !1,
      meta: {
        lockPosition: !0,
        suppressMovable: !0,
        utility: !0
      },
      viewRenderer: () => {
        const t = document.createElement("div");
        return t.className = "dg-row-drag-handle", t.setAttribute("aria-label", "Drag to reorder"), t.setAttribute("role", "button"), t.setAttribute("tabindex", "-1"), t.draggable = !0, this.setIcon(t, this.resolveIcon("dragHandle")), t;
      }
    };
    return this.config.dragHandlePosition === "right" ? [...e, r] : [r, ...e];
  }
  /** @internal */
  afterRender() {
    if (!this.config.showDragHandle) return;
    const e = this.gridElement;
    if (!e) return;
    e.querySelectorAll(".dg-row-drag-handle").forEach((i) => {
      const s = i;
      if (s.getAttribute("data-drag-bound")) return;
      s.setAttribute("data-drag-bound", "true");
      const o = s.closest(".data-grid-row");
      o && this.setupHandleDragListeners(s, o);
    }), e.querySelectorAll(".data-grid-row").forEach((i) => {
      const s = i;
      s.getAttribute("data-drop-bound") || (s.setAttribute("data-drop-bound", "true"), this.setupRowDropListeners(s));
    });
  }
  /**
   * Handle Ctrl+Arrow keyboard shortcuts for row reordering.
   * @internal
   */
  onKeyDown(e) {
    if (!this.config.enableKeyboard || !e.ctrlKey || e.key !== "ArrowUp" && e.key !== "ArrowDown")
      return;
    const r = this.grid, t = r._focusRow, i = r._rows ?? this.sourceRows;
    if (t < 0 || t >= i.length) return;
    const s = e.key === "ArrowUp" ? "up" : "down", o = s === "up" ? t - 1 : t + 1;
    if (o < 0 || o >= i.length) return;
    const n = i[t];
    if (!(this.config.canMove && !this.config.canMove(n, t, o, s)))
      return this.handleKeyboardMove(n, t, o, s, r._focusCol), e.preventDefault(), e.stopPropagation(), !0;
  }
  /**
   * Flush pending keyboard moves when user clicks a cell.
   * This commits the move immediately so focus works correctly.
   * @internal
   */
  onCellClick() {
    this.flushPendingMove();
  }
  // #endregion
  // #region Public API
  /**
   * Move a row to a new position programmatically.
   * @param fromIndex - Current index of the row
   * @param toIndex - Target index
   */
  moveRow(e, r) {
    const t = [...this.sourceRows];
    if (e < 0 || e >= t.length || r < 0 || r >= t.length || e === r) return;
    const i = r < e ? "up" : "down", s = t[e];
    this.config.canMove && !this.config.canMove(s, e, r, i) || this.executeMove(s, e, r, "keyboard");
  }
  /**
   * Check if a row can be moved to a position.
   * @param fromIndex - Current index of the row
   * @param toIndex - Target index
   */
  canMoveRow(e, r) {
    const t = this.sourceRows;
    if (e < 0 || e >= t.length || r < 0 || r >= t.length || e === r) return !1;
    if (!this.config.canMove) return !0;
    const i = r < e ? "up" : "down";
    return this.config.canMove(t[e], e, r, i);
  }
  // #endregion
  // #region Private Methods
  /**
   * Set up drag start/end listeners on the drag handle element.
   */
  setupHandleDragListeners(e, r) {
    e.addEventListener("dragstart", (t) => {
      const i = this.getRowIndex(r);
      i < 0 || (this.isDragging = !0, this.draggedRowIndex = i, t.dataTransfer && (t.dataTransfer.effectAllowed = "move", t.dataTransfer.setData("text/plain", String(i))), r.classList.add("dragging"));
    }), e.addEventListener("dragend", () => {
      this.isDragging = !1, this.draggedRowIndex = null, this.dropRowIndex = null, this.clearDragClasses();
    });
  }
  /**
   * Set up drop target listeners on a row element.
   * All rows are valid drop targets during drag operations.
   */
  setupRowDropListeners(e) {
    e.addEventListener("dragover", (r) => {
      if (r.preventDefault(), !this.isDragging || this.draggedRowIndex === null) return;
      const t = this.getRowIndex(e);
      if (t < 0 || t === this.draggedRowIndex) return;
      const i = e.getBoundingClientRect(), s = i.top + i.height / 2, o = r.clientY < s;
      this.dropRowIndex = o ? t : t + 1, e.classList.add("drop-target"), e.classList.toggle("drop-before", o), e.classList.toggle("drop-after", !o);
    }), e.addEventListener("dragleave", () => {
      e.classList.remove("drop-target", "drop-before", "drop-after");
    }), e.addEventListener("drop", (r) => {
      r.preventDefault();
      const t = this.draggedRowIndex;
      let i = this.dropRowIndex;
      if (!(!this.isDragging || t === null || i === null) && (i > t && i--, t !== i)) {
        const o = this.sourceRows[t], n = i < t ? "up" : "down";
        (!this.config.canMove || this.config.canMove(o, t, i, n)) && this.executeMove(o, t, i, "drag");
      }
    });
  }
  /**
   * Handle debounced keyboard moves.
   * Rows move immediately for visual feedback, but the event emission is debounced.
   */
  handleKeyboardMove(e, r, t, i, s) {
    this.pendingMove ? this.pendingMove.currentIndex = t : this.pendingMove = {
      originalIndex: r,
      currentIndex: t,
      row: e
    }, this.lastFocusCol = s;
    const o = this.grid, n = [...o._rows ?? this.sourceRows], [c] = n.splice(r, 1);
    n.splice(t, 0, c), o._rows = n, o._focusRow = t, o._focusCol = s, o.refreshVirtualWindow(!0), p(o), this.clearDebounceTimer(), this.debounceTimer = setTimeout(() => {
      this.flushPendingMove();
    }, this.config.debounceMs ?? 300);
  }
  /**
   * Flush the pending move by emitting the event.
   * Called when debounce timer fires or user clicks elsewhere.
   */
  flushPendingMove() {
    if (this.clearDebounceTimer(), !this.pendingMove) return;
    const { originalIndex: e, currentIndex: r, row: t } = this.pendingMove;
    if (this.pendingMove = null, e === r) return;
    const i = {
      row: t,
      fromIndex: e,
      toIndex: r,
      rows: [...this.sourceRows],
      source: "keyboard"
    };
    if (this.emitCancelable("row-move", i)) {
      const o = [...this.sourceRows], [n] = o.splice(r, 1);
      o.splice(e, 0, n);
      const c = this.grid;
      c._rows = o, c._focusRow = e, c._focusCol = this.lastFocusCol, c.refreshVirtualWindow(!0), p(c);
    }
  }
  /**
   * Execute a row move and emit the event.
   */
  executeMove(e, r, t, i) {
    const s = [...this.sourceRows], [o] = s.splice(r, 1);
    s.splice(t, 0, o);
    const n = {
      row: e,
      fromIndex: r,
      toIndex: t,
      rows: s,
      source: i
    };
    if (!this.emitCancelable("row-move", n))
      if (this.animationType === "flip" && this.gridElement) {
        const a = this.captureRowPositions();
        this.grid.rows = s, requestAnimationFrame(() => {
          this.gridElement.offsetHeight, this.animateFLIP(a, r, t);
        });
      } else
        this.grid.rows = s;
  }
  /**
   * Capture row positions before reorder.
   * Maps visual row index to its top position.
   */
  captureRowPositions() {
    const e = /* @__PURE__ */ new Map();
    return this.gridElement?.querySelectorAll(".data-grid-row").forEach((r) => {
      const t = this.getRowIndex(r);
      t >= 0 && e.set(t, r.getBoundingClientRect().top);
    }), e;
  }
  /**
   * Apply FLIP animation for row reorder.
   * Uses CSS transitions - JS sets initial transform and toggles class.
   * @param oldPositions - Row positions captured before DOM change
   * @param fromIndex - Original index of moved row
   * @param toIndex - New index of moved row
   */
  animateFLIP(e, r, t) {
    const i = this.gridElement;
    if (!i || e.size === 0) return;
    const s = Math.min(r, t), o = Math.max(r, t), n = [];
    if (i.querySelectorAll(".data-grid-row").forEach((a) => {
      const u = a, d = this.getRowIndex(u);
      if (d < 0 || d < s || d > o) return;
      let g;
      d === t ? g = r : r < t ? g = d + 1 : g = d - 1;
      const h = e.get(g);
      if (h === void 0) return;
      const w = u.getBoundingClientRect().top, f = h - w;
      Math.abs(f) > 1 && n.push({ el: u, deltaY: f });
    }), n.length === 0) return;
    n.forEach(({ el: a, deltaY: u }) => {
      a.style.transform = `translateY(${u}px)`;
    }), i.offsetHeight;
    const c = this.animationDuration;
    requestAnimationFrame(() => {
      n.forEach(({ el: a }) => {
        a.classList.add("flip-animating"), a.style.transform = "";
      }), setTimeout(() => {
        n.forEach(({ el: a }) => {
          a.style.transform = "", a.classList.remove("flip-animating");
        });
      }, c + 50);
    });
  }
  /**
   * Get the row index from a row element by checking data-row attribute on cells.
   * This is consistent with how other plugins retrieve row indices.
   */
  getRowIndex(e) {
    const r = e.querySelector(".cell[data-row]");
    return r ? parseInt(r.getAttribute("data-row") ?? "-1", 10) : -1;
  }
  /**
   * Clear all drag-related classes from rows.
   */
  clearDragClasses() {
    this.gridElement?.querySelectorAll(".data-grid-row").forEach((e) => {
      e.classList.remove("dragging", "drop-target", "drop-before", "drop-after");
    });
  }
  /**
   * Clear the debounce timer.
   */
  clearDebounceTimer() {
    this.debounceTimer && (clearTimeout(this.debounceTimer), this.debounceTimer = null);
  }
  // #endregion
}
export {
  A as ROW_DRAG_HANDLE_FIELD,
  L as RowReorderPlugin
};
//# sourceMappingURL=index.js.map
