Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ export const useCellVisibility = () => {
return undefined
}

// `.avt-body` is the table package's stable hook. The antd selectors stay as a fallback
// for the raw <Table> call sites this hook is also used from.
const root =
scrollContainer ??
element.closest<HTMLDivElement>(".avt-body") ??
element.closest<HTMLDivElement>(".ant-table-body") ??
element.closest<HTMLDivElement>(".ant-table-body-inner") ??
null
Expand Down
2 changes: 1 addition & 1 deletion web/oss/src/components/pages/agents/AgentsTableSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default function AgentsTableSection({

return (
<InfiniteVirtualTableFeatureShell<AppWorkflowRow>
className="grow min-h-0 [&_.ant-table-cell]:!align-middle [&_.ant-table-container]:!border-b"
className="grow min-h-0 [&_.avt-cell]:!align-middle [&_.avt-container]:!border-b"
tableScope={tableScope}
columns={columns}
rowKey={(record) => record.key}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ const ObservabilityTable = () => {
enableExport={false}
useSettingsDropdown={false}
store={store}
className="flex-1 min-h-0 [&_.ant-table-thead_tr:nth-child(2)]:hidden"
className="flex-1 min-h-0 [&_.avt-thead_tr:nth-child(2)]:hidden"
rowSelection={{
selectedRowKeys,
type: "checkbox",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ const SessionsTable: React.FC = () => {
resizableColumns
enableExport={false}
useSettingsDropdown={false}
className="flex-1 min-h-0 [&_.ant-table-tbody_.ant-table-cell]:align-top"
className="flex-1 min-h-0 [&_.avt-row_.avt-cell]:align-top"
tableProps={{
bordered: true,
loading: isLoading && sessionIds.length === 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export const PromptsTableSection = ({

return (
<InfiniteVirtualTableFeatureShell<PromptsTableRow>
className="grow min-h-0 [&_.ant-table-cell]:!align-middle [&_.ant-table-container]:!border-b"
className="grow min-h-0 [&_.avt-cell]:!align-middle [&_.avt-container]:!border-b"
tableScope={tableScope}
columns={columns}
rowKey={(record) => record.key}
Expand Down
4 changes: 3 additions & 1 deletion web/oss/src/styles/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ body {
transition: opacity 0.3s ease;
}

.ant-table-row:hover .hover-button-wrapper {
/* .avt-row is the table package's stable hook; the antd selector stays for raw <Table> users. */
.ant-table-row:hover .hover-button-wrapper,
.avt-row:hover .hover-button-wrapper {
opacity: 1;
}

Expand Down
80 changes: 80 additions & 0 deletions web/packages/agenta-entity-ui/tests/unit/tableClassHooks.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {AVT, stampTableDom, toAntdColumns} from "@agenta/ui/table"
import {describe, expect, it} from "vitest"

/**
* The table's stable class hooks. App code targets `avt-*` so a selector does not depend on
* antd's DOM, which the render-leaf swap will replace. If these break, consumer styling
* silently stops applying, so the contract is pinned here rather than left to a browser pass.
*/

interface FakeNode {
classes: Set<string>
classList: {add: (c: string) => void}
}

const node = (): FakeNode => {
const classes = new Set<string>()
return {classes, classList: {add: (c: string) => classes.add(c)}}
}

/** Minimal stand-in for the mounted table: querySelector over a fixed selector map. */
const container = (found: Record<string, FakeNode>) =>
({
querySelector: (selector: string) => found[selector] ?? null,
}) as unknown as HTMLElement

describe("stampTableDom", () => {
it("stamps the structural hooks onto antd's nodes", () => {
const nodes = {
".ant-table-container": node(),
".ant-table-body": node(),
".ant-table-thead": node(),
}
stampTableDom(container(nodes))

expect([...nodes[".ant-table-container"].classes]).toEqual([AVT.container])
expect([...nodes[".ant-table-body"].classes]).toEqual([AVT.body])
expect([...nodes[".ant-table-thead"].classes]).toEqual([AVT.header])
})

it("skips nodes that are not present rather than throwing", () => {
expect(() => stampTableDom(container({}))).not.toThrow()
expect(() => stampTableDom(null)).not.toThrow()
})
})

describe("toAntdColumns cell hooks", () => {
interface Row {
id: string
}

it("adds the cell hooks to a plain column", () => {
const [column] = toAntdColumns<Row>([{key: "id", title: "ID"}])

expect(column.onCell?.({id: "a"}, 0)).toEqual({className: AVT.cell})
expect(column.onHeaderCell?.(column, 0)).toEqual({className: AVT.headerCell})
})

it("keeps a column's own cell props and appends the hook", () => {
const [column] = toAntdColumns<Row>([
{
key: "id",
onCell: () => ({className: "mine", colSpan: 2}),
},
])

expect(column.onCell?.({id: "a"}, 0)).toEqual({
className: `mine ${AVT.cell}`,
colSpan: 2,
})
})

it("reaches columns nested in a group", () => {
const [group] = toAntdColumns<Row>([
{key: "g", title: "Group", children: [{key: "id", title: "ID"}]},
])
const child = (group as {children: (typeof group)[]}).children[0]

expect(child.onCell?.({id: "a"}, 0)).toEqual({className: AVT.cell})
})
})
28 changes: 26 additions & 2 deletions web/packages/agenta-ui/src/InfiniteVirtualTable/antdColumns.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type {ColumnsType as AntdColumnsType} from "antd/es/table"

import type {ColumnDefs} from "./columnDef"
import type {ColumnCellProps, ColumnDefs} from "./columnDef"
import {isColumnGroupDef} from "./columnDef"
import {AVT} from "./tableDom"

/**
* The one place the table's own column model meets antd's.
Expand All @@ -11,8 +13,30 @@ import type {ColumnDefs} from "./columnDef"
* rather than inferred. Keep the assertion here; do not import antd column types elsewhere in
* this directory.
*/

const withClass = (props: ColumnCellProps | undefined, className: string): ColumnCellProps => ({
...props,
className: props?.className ? `${props.className} ${className}` : className,
})

/**
* Stamps the stable cell hooks. Cells are recycled by virtualization, so they cannot be
* stamped from a mount effect the way the structural nodes are.
*/
const withCellHooks = <RecordType>(columns: ColumnDefs<RecordType>): ColumnDefs<RecordType> =>
columns.map((column) => {
const next = {
...column,
onCell: (record: RecordType, index?: number) =>
withClass(column.onCell?.(record, index), AVT.cell),
onHeaderCell: (col: ColumnDefs<RecordType>[number], index?: number) =>
withClass(column.onHeaderCell?.(col, index), AVT.headerCell),
}
return isColumnGroupDef(column) ? {...next, children: withCellHooks(column.children)} : next
}) as ColumnDefs<RecordType>

export const toAntdColumns = <RecordType>(columns: ColumnDefs<RecordType>) =>
columns as unknown as AntdColumnsType<RecordType>
withCellHooks(columns) as unknown as AntdColumnsType<RecordType>

/** Columns arriving from an antd-typed call site, on their way into the table. */
export const fromAntdColumns = <RecordType>(columns: AntdColumnsType<RecordType>) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import useTableRowSelection from "../hooks/useTableRowSelection"
import {useTypeChipColumns} from "../hooks/useTypeChipColumns"
import {useTypeChipFeature} from "../hooks/useTypeChipFeature"
import ColumnVisibilityProvider from "../providers/ColumnVisibilityProvider"
import {ANTD_SELECTOR, AVT, stampTableDom} from "../tableDom"
import type {InfiniteVirtualTableProps} from "../types"
import {
buildColumnDescendantMap,
Expand Down Expand Up @@ -190,9 +191,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
return
}
const headerCells = Array.from(
container.querySelectorAll<HTMLTableCellElement>(
".ant-table-thead th[data-column-key]",
),
container.querySelectorAll<HTMLTableCellElement>(ANTD_SELECTOR.headerCellWithKey),
).filter((cell) => Number(cell.getAttribute("colspan") ?? "1") === 1)
if (!headerCells.length) {
columnDomRefs.current = new Map()
Expand Down Expand Up @@ -329,7 +328,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
const tables = container.querySelectorAll<HTMLTableElement>(".ant-table table")
tables.forEach((table) => {
const selectionCol = table.querySelector<HTMLTableColElement>(
"colgroup col.ant-table-selection-col",
ANTD_SELECTOR.selectionCol,
)
if (selectionCol) {
selectionCol.style.width = widthPx
Expand All @@ -339,7 +338,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
})

const headerCells = container.querySelectorAll<HTMLTableCellElement>(
".ant-table-thead th.ant-table-selection-column",
ANTD_SELECTOR.headerSelectionCell,
)
headerCells.forEach((cell) => {
cell.style.width = widthPx
Expand All @@ -366,7 +365,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
return
}
const headerEl =
container.querySelector<HTMLElement>(".ant-table-thead") ??
container.querySelector<HTMLElement>(ANTD_SELECTOR.header) ??
container.querySelector<HTMLElement>("table thead")
if (!headerEl) {
setTableHeaderHeight(null)
Expand Down Expand Up @@ -411,7 +410,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
const headerHeight =
(typeof tableHeaderHeight === "number" && Number.isFinite(tableHeaderHeight)
? tableHeaderHeight
: (containerRef.current?.querySelector(".ant-table-thead") as HTMLElement | null)
: (containerRef.current?.querySelector(ANTD_SELECTOR.header) as HTMLElement | null)
?.offsetHeight) ?? null

const computedY = Math.max((scrollY ?? 0) - (headerHeight ?? 0), 0)
Expand Down Expand Up @@ -692,6 +691,20 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
const columnVisibilityVersion = version
const tableComponentRef = tableRef as unknown as Ref<TableRef>

// Stable class hooks for app code, so a consumer's selector does not depend on antd's DOM.
// The structural nodes exist for the table's lifetime; rows and cells get theirs from
// rowClassName and the column adapter, because virtualization recycles them.
useEffect(() => {
stampTableDom(containerRef.current)
}, [dataSource])
Comment on lines +694 to +699

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

file="web/packages/agenta-ui/src/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx"

printf '%s\n' '--- outline ---'
ast-grep outline "$file" --lang tsx | head -200

printf '%s\n' '--- imports and relevant source ---'
sed -n '1,120p' "$file"
sed -n '640,790p' "$file"

printf '%s\n' '--- relevant symbols ---'
rg -n -C 5 'stampTableDom|toAntdColumns|use(Layout)?Effect|containerRef|finalColumns' "$file"

Repository: Agenta-AI/agenta

Length of output: 22377


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- candidate tableDom files ---'
fd -i 'tableDom' web/packages/agenta-ui

printf '%s\n' '--- tableDom symbols and implementation ---'
rg -n -C 8 'stampTableDom|AVT|ANTD_SELECTOR' web/packages/agenta-ui

printf '%s\n' '--- column adapter ---'
fd -i 'antdColumns' web/packages/agenta-ui
rg -n -C 5 'function toAntdColumns|const toAntdColumns|export .*toAntdColumns' web/packages/agenta-ui

printf '%s\n' '--- package metadata and test references ---'
fd -i 'package.json|test|spec' web/packages/agenta-ui | head -100
rg -n -C 4 'stampTableDom|avt-container|avt-body|avt-thead' web/packages/agenta-ui --glob '*.{ts,tsx,js,jsx,test,spec}'

Repository: Agenta-AI/agenta

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- isomorphic layout-effect conventions ---'
rg -n -C 4 'useIsomorphicLayoutEffect|typeof window.*useLayoutEffect|useLayoutEffect.*typeof window' web --glob '*.{ts,tsx,js,jsx}'

printf '%s\n' '--- InfiniteVirtualTable usage ---'
rg -n -C 3 '<InfiniteVirtualTable|InfiniteVirtualTable\(' web --glob '*.{ts,tsx,js,jsx}'

printf '%s\n' '--- consumers of structural AVT hooks ---'
rg -n -C 3 'avt-container|avt-body|avt-thead|AVT\.container|AVT\.body|AVT\.header' . --glob '*.{ts,tsx,css,less,scss,js,jsx}'

printf '%s\n' '--- package metadata ---'
cat web/packages/agenta-ui/package.json

Repository: Agenta-AI/agenta

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
from pathlib import Path
import re

path = Path("web/packages/agenta-ui/src/InfiniteVirtualTable/components/InfiniteVirtualTableInner.tsx")
text = path.read_text()

effect = re.search(
    r"useEffect\(\(\) => \{\s*stampTableDom\(containerRef\.current\)\s*\}, \[dataSource\]\)",
    text,
)
layout_effect = re.search(
    r"useLayoutEffect\(\(\) => \{\s*stampTableDom\(containerRef\.current\)\s*\}, \[dataSource\]\)",
    text,
)

dom = Path("web/packages/agenta-ui/src/InfiniteVirtualTable/tableDom.ts").read_text()
selectors = re.findall(r"\[ANTD_SELECTOR\.(\w+), AVT\.(\w+)\]", dom)

print({
    "passive_stamp_present": bool(effect),
    "layout_stamp_present": bool(layout_effect),
    "structural_mappings": selectors,
    "layout_effect_already_imported": "useLayoutEffect" in text.split("from \"react\"", 1)[0],
})
PY

Repository: Agenta-AI/agenta

Length of output: 350


🌐 Web query:

React official documentation useEffect after paint useLayoutEffect before browser repaint server rendering warning

💡 Result:

The fundamental difference between useEffect and useLayoutEffect lies in their execution timing relative to the browser's painting process [1][2][3]. useEffect: - Runs asynchronously after the browser has painted the updated screen [1][2]. - It is the default choice for most side effects (e.g., data fetching, subscriptions, setting up event handlers) because it avoids blocking the browser from updating the user interface [1][4][3]. useLayoutEffect: - Runs synchronously after React performs all DOM mutations, but before the browser paints those changes to the screen [1][2][3]. - It effectively blocks the browser from repainting until the effect completes [1][2]. - It is intended for specific use cases, such as measuring DOM elements or performing visual mutations that must occur before the user sees the rendered output to prevent visible "flicker" [1][2][3]. Server Rendering Warning: React issues a warning when useLayoutEffect is used during server-side rendering because this hook cannot execute on the server [5][6]. On the server, React renders components to a string or stream without a DOM environment; therefore, the code inside useLayoutEffect is skipped [5][7]. The warning serves as a safeguard because useLayoutEffect is typically used to fix visual inconsistencies or measure layout [8][6]. If a component relies on this effect for correct rendering, the server-rendered HTML sent to the client will likely look incorrect or "broken" until the client-side JavaScript loads and the effect eventually runs [6][7]. To resolve this warning: 1. Prefer useEffect: If the logic does not require immediate, blocking layout adjustments, switch to useEffect [1][5]. 2. Conditional Rendering: If a component depends on client-only layout logic, render it conditionally so it only appears after the component has mounted on the client [8][5]. This can be achieved by using state (e.g., initialized to false) that is set to true within a useEffect hook [8][5]. This prevents the "broken" UI from being displayed in the initial server-rendered HTML [6][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- package-local isomorphic hook and table entry point ---'
sed -n '1,100p' web/packages/agenta-ui/src/InfiniteVirtualTable/hooks/useContainerResize.ts
sed -n '1,90p' web/packages/agenta-ui/src/InfiniteVirtualTable/InfiniteVirtualTable.tsx

printf '%s\n' '--- package-level server/client markers and Next integration ---'
rg -n -C 2 '"use client"|next/|dynamic\(' web/packages/agenta-ui web/oss/src --glob '*.{ts,tsx,js,jsx}' | head -240

printf '%s\n' '--- focused table class-hook tests ---'
sed -n '1,100p' web/packages/agenta-entity-ui/tests/unit/tableClassHooks.test.ts

Repository: Agenta-AI/agenta

Length of output: 26811


Stamp structural hooks before the first paint.

useEffect can let the first client frame render without avt-container, avt-body, or avt-thead, so consumer selectors may not apply. Use a client/server-safe layout effect: useLayoutEffect on the client and useEffect during SSR.


const rowClassName = useMemo<TableProps<RecordType>["rowClassName"]>(() => {
const inherited = tablePropsWithShortcuts.rowClassName
if (!inherited) return AVT.row
if (typeof inherited !== "function") return cn(inherited, AVT.row)
return (record, index, indent) => cn(inherited(record, index, indent), AVT.row)
}, [tablePropsWithShortcuts.rowClassName])

useEffect(() => {
const key = resolvedScopeId
if (!key) return undefined
Expand Down Expand Up @@ -731,6 +744,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
<div
ref={containerRef}
className={cn(
AVT.root,
"[&_.ant-table-empty_.ant-table-body]:!overflow-x-hidden",
containerClassName,
)}
Expand All @@ -746,6 +760,7 @@ const InfiniteVirtualTableInnerBase = <RecordType extends object>({
rowSelection={tableRowSelection}
expandable={tableExpandable}
{...tablePropsWithShortcuts}
rowClassName={rowClassName}
scroll={{
x: scrollConfig.x,
y: scrollConfig.y,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {useLayoutEffect, useRef} from "react"

import type {ColumnDefs} from "../columnDef"
import {ANTD_SELECTOR} from "../tableDom"

interface ColumnDomRefs {
cols: HTMLTableColElement[]
Expand All @@ -24,9 +25,7 @@ const useColumnDomRefs = <RecordType>(
}

const headerCells = Array.from(
container.querySelectorAll<HTMLTableCellElement>(
".ant-table-thead th[data-column-key]",
),
container.querySelectorAll<HTMLTableCellElement>(ANTD_SELECTOR.headerCellWithKey),
).filter((cell) => Number(cell.getAttribute("colspan") ?? "1") === 1)

if (!headerCells.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {useMemo, useRef, type RefObject} from "react"

import type {TableProps} from "antd/es/table"

import {ANTD_SELECTOR} from "../tableDom"
import {shallowEqual} from "../utils/columnUtils"

interface UseScrollConfigOptions<RecordType> {
Expand Down Expand Up @@ -50,7 +51,7 @@ const useScrollConfig = <RecordType>({
const headerHeight =
(typeof tableHeaderHeight === "number" && Number.isFinite(tableHeaderHeight)
? tableHeaderHeight
: (containerRef.current?.querySelector(".ant-table-thead") as HTMLElement | null)
: (containerRef.current?.querySelector(ANTD_SELECTOR.header) as HTMLElement | null)
?.offsetHeight) ?? null

const computedY = Math.max((containerHeight ?? 0) - (headerHeight ?? 0), 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {useEffect, useRef, useState} from "react"

import {ANTD_SELECTOR} from "../tableDom"

interface ScrollContainerResult {
scrollContainer: HTMLDivElement | null
visibilityRoot: HTMLDivElement | null
Expand Down Expand Up @@ -33,7 +35,7 @@ const useScrollContainer = (
return
}

const tableBody = containerElement.querySelector<HTMLDivElement>(".ant-table-body") ?? null
const tableBody = containerElement.querySelector<HTMLDivElement>(ANTD_SELECTOR.body) ?? null

const isScrollable = (element: HTMLDivElement | null) => {
if (!element) return false
Expand All @@ -52,7 +54,7 @@ const useScrollContainer = (
}

const headerContainer =
containerElement.querySelector<HTMLDivElement>(".ant-table-container") ??
containerElement.querySelector<HTMLDivElement>(ANTD_SELECTOR.container) ??
containerElement

if (headerContainer !== lastVisibilityRootRef.current) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {useLayoutEffect, useState, type RefObject} from "react"
import type {TableProps} from "antd/es/table"

import type {ColumnDefs} from "../columnDef"
import {ANTD_SELECTOR} from "../tableDom"

interface UseTableHeaderHeightOptions<RecordType> {
containerRef: RefObject<HTMLDivElement | null>
Expand All @@ -29,7 +30,7 @@ const useTableHeaderHeight = <RecordType>({
return
}
const headerEl =
container.querySelector<HTMLElement>(".ant-table-thead") ??
container.querySelector<HTMLElement>(ANTD_SELECTOR.header) ??
container.querySelector<HTMLElement>("table thead")
if (!headerEl) {
setTableHeaderHeight(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
TableDeleteConfig,
TableExportConfig,
} from "../features/InfiniteVirtualTableFeatureShell"
import {ANTD_SELECTOR} from "../tableDom"
import type {
InfiniteTableRowBase,
InfiniteVirtualTableProps,
Expand All @@ -31,7 +32,7 @@ const dummySearchAtom = atom("")
const INTERACTIVE_SELECTOR =
"button, a, input, textarea, select, [role='button'], [role='menuitem'], [role='checkbox'], " +
".ant-btn, .ant-checkbox, .ant-checkbox-input, .ant-checkbox-inner, .ant-checkbox-wrapper, " +
".ant-select, .ant-dropdown-trigger, .ant-table-selection-column, .ag-table-actions-cell"
ANTD_SELECTOR.interactiveCell

/**
* Returns true when the click originated from an interactive element (button, link,
Expand Down
1 change: 1 addition & 0 deletions web/packages/agenta-ui/src/InfiniteVirtualTable/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export type {
ColumnSorterConfig,
} from "./columnDef"
export {toAntdColumns, fromAntdColumns} from "./antdColumns"
export {AVT, ANTD_SELECTOR, stampTableDom, type AvtClass} from "./tableDom"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Keep ANTD_SELECTOR internal.

Line 140 exposes Ant Design DOM selectors as a public API. web/packages/agenta-ui/src/InfiniteVirtualTable/tableDom.ts states that app code must use AVT and that ANTD_SELECTOR is an implementation detail. Remove this export so consumers cannot couple to the DOM that this PR intends to replace.

Proposed fix
-export {AVT, ANTD_SELECTOR, stampTableDom, type AvtClass} from "./tableDom"
+export {AVT, stampTableDom, type AvtClass} from "./tableDom"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export {AVT, ANTD_SELECTOR, stampTableDom, type AvtClass} from "./tableDom"
export {AVT, stampTableDom, type AvtClass} from "./tableDom"

export type {VisibilityRegistrationHandler} from "./components/ColumnVisibilityHeader"

// Shared hooks for cell renderers
Expand Down
Loading
Loading