diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/InfiniteScrollVariableHeightRows_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/InfiniteScrollVariableHeightRows_spec.ts
new file mode 100644
index 000000000000..b3a1d716add6
--- /dev/null
+++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/TableV2/InfiniteScrollVariableHeightRows_spec.ts
@@ -0,0 +1,173 @@
+import { featureFlagIntercept } from "../../../../../support/Objects/FeatureFlags";
+import { propPane, table } from "../../../../../support/Objects/ObjectsCore";
+
+const DEFAULT_ROW_HEIGHT = 40;
+
+describe(
+ "Table Widget Dynamic Row Height",
+ { tags: ["@tag.Widget", "@tag.Table"] },
+ function () {
+ before(() => {
+ featureFlagIntercept({
+ release_tablev2_infinitescroll_enabled: true,
+ });
+
+ // Set up a table with test data
+ cy.dragAndDropToCanvas("tablewidgetv2", { x: 300, y: 300 });
+
+ // Create test data with varying content lengths
+ const testData = [
+ {
+ id: 1,
+ name: "Short text",
+ description: "This is a short description",
+ },
+ {
+ id: 2,
+ name: "Medium length text",
+ description:
+ "This description is a bit longer and might wrap to the next line depending on column width",
+ },
+ {
+ id: 3,
+ name: "Very long text content",
+ description:
+ "This is a very long description that will definitely wrap to multiple lines when cell wrapping is enabled. It contains enough text to ensure that the row height will need to expand significantly to accommodate all the content properly.",
+ },
+ ];
+
+ // Set the table data
+ propPane.EnterJSContext("Table data", JSON.stringify(testData));
+
+ // Turn on Infinite Scroll
+ propPane.TogglePropertyState("Infinite scroll", "On");
+ });
+
+ it("1. Should maintain fixed height when cell wrapping is disabled and no HTML cells are present", () => {
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr").each(($row) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined) {
+ expect(Math.ceil(height)).to.equal(DEFAULT_ROW_HEIGHT);
+ }
+ });
+ });
+ });
+
+ it("2. Should increase row height when cell wrapping is enabled", () => {
+ // turn on cell wrapping
+ table.EditColumn("description", "v2");
+ propPane.TogglePropertyState("Cell wrapping", "On");
+ propPane.NavigateBackToPropertyPane();
+
+ // get the height of the row with the longest text
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr").each(($row) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined) {
+ expect(Math.ceil(height)).to.be.greaterThan(DEFAULT_ROW_HEIGHT);
+ }
+ });
+ });
+ });
+
+ it("3. Should update row heights when content changes", () => {
+ // check and store current row height in variable
+ let currentRowHeight = 0;
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr").each(($row) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined) {
+ currentRowHeight = Math.ceil(height);
+ }
+ });
+ });
+
+ // updated table data with extermely long text
+ const updatedTestData = [
+ {
+ id: 4,
+ name: "Short text",
+ description: "This is a short description",
+ },
+ {
+ id: 5,
+ name: "Extremely long text",
+ description:
+ "This is an extremely long description that will definitely wrap to multiple lines when cell wrapping is enabled. It contains enough text to ensure that the row height will need to expand significantly to accommodate all the content properly. We're adding even more text here to make sure the row expands further than before. The height measurement should reflect this change in content length appropriately. Additionally, this text continues with more detailed information about how the wrapping behavior works in practice. When dealing with variable height rows, it's important to validate that the table can handle content of any length gracefully. This extra text helps us verify that the row height calculations are working correctly even with very long content that spans multiple lines. The table should automatically adjust the row height to fit all of this content while maintaining proper scrolling and layout behavior. We want to ensure there are no visual glitches or truncation issues when displaying such lengthy content.",
+ },
+ ];
+
+ // update the table data
+ propPane.EnterJSContext("Table data", JSON.stringify(updatedTestData));
+
+ // Find the tallest row in the table
+ let maxHeight = 0;
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr")
+ .each(($row, index) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined && height > maxHeight) {
+ maxHeight = height;
+ }
+ });
+ })
+ .then(() => {
+ expect(maxHeight).to.be.greaterThan(currentRowHeight);
+ });
+ });
+
+ it("4. Should revert to fixed height when cell wrapping is disabled", () => {
+ // turn off cell wrapping
+ table.EditColumn("description", "v2");
+ propPane.TogglePropertyState("Cell wrapping", "Off");
+ propPane.NavigateBackToPropertyPane();
+
+ // get the height of the row with the longest text
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr").each(($row) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined) {
+ expect(Math.ceil(height)).to.equal(DEFAULT_ROW_HEIGHT);
+ }
+ });
+ });
+ });
+
+ it("5. Should handle HTML content in cells with proper height adjustment", () => {
+ // Create test data with HTML content
+ const htmlTestData = [
+ {
+ id: 6,
+ name: "HTML content",
+ description:
+ "
This is a formatted description with
multiple line breaks
and formatting
",
+ },
+ ];
+
+ // Update the table data
+ propPane.EnterJSContext("Table data", JSON.stringify(htmlTestData));
+
+ // update the column type to html
+ table.EditColumn("description", "v2");
+ propPane.SelectPropertiesDropDown("Column type", "HTML");
+ propPane.NavigateBackToPropertyPane();
+
+ // get the height of the row with the longest text
+ cy.get(".t--widget-tablewidgetv2 .tbody .tr").each(($row) => {
+ cy.wrap($row)
+ .invoke("outerHeight")
+ .then((height) => {
+ if (height !== undefined) {
+ expect(Math.ceil(height)).to.be.greaterThan(DEFAULT_ROW_HEIGHT);
+ }
+ });
+ });
+ });
+ },
+);
diff --git a/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx b/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx
index db17453607dd..95281c1191de 100644
--- a/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/Row.tsx
@@ -1,24 +1,32 @@
import type { Key } from "react";
-import React from "react";
+import React, { useEffect, useRef, useState } from "react";
import type { Row as ReactTableRowType } from "react-table";
-import type { ListChildComponentProps } from "react-window";
+import type { ListChildComponentProps, VariableSizeList } from "react-window";
import { renderBodyCheckBoxCell } from "../cellComponents/SelectionCheckboxCell";
import { MULTISELECT_CHECKBOX_WIDTH, StickyType } from "../Constants";
import { useAppsmithTable } from "../TableContext";
+import { useRowHeightMeasurement } from "../VirtualTable/useRowHeightMeasurement";
+import useColumnVariableHeight from "../VirtualTable/useColumnVariableHeight";
interface RowType {
className?: string;
index: number;
row: ReactTableRowType>;
style?: ListChildComponentProps["style"];
+ listRef?: React.RefObject;
+ rowHeights?: React.RefObject<{ [key: number]: number }>;
+ rowNeedsMeasurement?: React.RefObject<{ [key: number]: boolean }>;
}
export function Row(props: RowType) {
+ const rowRef = useRef(null);
+ const [forceUpdate, setForceUpdate] = useState(0);
const {
accentColor,
borderRadius,
columns,
isAddRowInProgress,
+ isInfiniteScrollEnabled,
multiRowSelection,
prepareRow,
primaryColumnId,
@@ -27,6 +35,27 @@ export function Row(props: RowType) {
selectTableRow,
} = useAppsmithTable();
+ const wrappingColumns = useColumnVariableHeight(columns, props.row);
+
+ useRowHeightMeasurement({
+ index: props.index,
+ row: props.row,
+ rowRef,
+ rowHeights: props.rowHeights,
+ rowNeedsMeasurement: props.rowNeedsMeasurement,
+ listRef: props.listRef,
+ forceUpdate,
+ isInfiniteScrollEnabled,
+ });
+
+ useEffect(() => {
+ if (props.rowNeedsMeasurement && props.rowNeedsMeasurement.current) {
+ props.rowNeedsMeasurement.current[props.index] = true;
+ }
+
+ setForceUpdate((prev) => prev + 1);
+ }, [wrappingColumns]);
+
prepareRow?.(props.row);
const rowProps = {
...props.row.getRowProps(),
@@ -34,6 +63,7 @@ export function Row(props: RowType) {
display: "flex",
...(props.style || {}),
},
+ ref: rowRef,
};
const isRowSelected = multiRowSelection
? selectedRowIndices.includes(props.row.index)
diff --git a/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx b/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx
index 2c8777ed008c..911e5d21d217 100644
--- a/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/TableBodyCoreComponents/VirtualList.tsx
@@ -1,33 +1,10 @@
-import type { ListOnItemsRenderedProps, ReactElementType } from "react-window";
-import { FixedSizeList, areEqual } from "react-window";
import React, { type Ref } from "react";
-import type { ListChildComponentProps } from "react-window";
import type { Row as ReactTableRowType } from "react-table";
-import { WIDGET_PADDING } from "constants/WidgetConstants";
-import { Row } from "./Row";
-import type { TableSizes } from "../Constants";
+import type { ListOnItemsRenderedProps, ReactElementType } from "react-window";
+import type { VariableSizeList } from "react-window";
import type SimpleBar from "simplebar-react";
-import { EmptyRows } from "../cellComponents/EmptyCell";
-
-const rowRenderer = React.memo((rowProps: ListChildComponentProps) => {
- const { data, index, style } = rowProps;
-
- if (index < data.length) {
- const row = data[index];
-
- return (
-
- );
- } else {
- return ;
- }
-}, areEqual);
+import type { TableSizes } from "../Constants";
+import BaseVirtualList from "../VirtualTable/BaseVirtualList";
interface BaseVirtualListProps {
height: number;
@@ -36,48 +13,16 @@ interface BaseVirtualListProps {
innerElementType?: ReactElementType;
outerRef: Ref;
onItemsRendered?: (props: ListOnItemsRenderedProps) => void;
- infiniteLoaderListRef?: React.Ref;
+ infiniteLoaderListRef?: React.Ref;
itemCount: number;
pageSize: number;
}
-const BaseVirtualList = React.memo(function BaseVirtualList({
- height,
- infiniteLoaderListRef,
- innerElementType,
- itemCount,
- onItemsRendered,
- outerRef,
- rows,
- tableSizes,
-}: BaseVirtualListProps) {
- return (
-
- {rowRenderer}
-
- );
-});
-
/**
* The difference between next two components is in the number of arguments they expect.
*/
-export const FixedInfiniteVirtualList = React.memo(
- function FixedInfiniteVirtualList(props: BaseVirtualListProps) {
+export const VariableInfiniteVirtualList = React.memo(
+ function VariableInfiniteVirtualList(props: BaseVirtualListProps) {
return ;
},
);
diff --git a/app/client/src/widgets/TableWidgetV2/component/VirtualTable/BaseVirtualList.tsx b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/BaseVirtualList.tsx
new file mode 100644
index 000000000000..f355df2bed58
--- /dev/null
+++ b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/BaseVirtualList.tsx
@@ -0,0 +1,153 @@
+import { WIDGET_PADDING } from "constants/WidgetConstants";
+import React, { useCallback, useMemo, useRef } from "react";
+import type { Row as ReactTableRowType } from "react-table";
+import type {
+ ListChildComponentProps,
+ ListOnItemsRenderedProps,
+ ReactElementType,
+} from "react-window";
+import { VariableSizeList, areEqual } from "react-window";
+import type SimpleBar from "simplebar-react";
+import type { TableSizes } from "../Constants";
+import { Row } from "../TableBodyCoreComponents/Row";
+import { EmptyRows } from "../cellComponents/EmptyCell";
+
+type ExtendedListChildComponentProps = ListChildComponentProps & {
+ listRef: React.RefObject;
+ rowHeights: React.RefObject<{ [key: number]: number }>;
+ rowNeedsMeasurement: React.RefObject<{ [key: number]: boolean }>;
+};
+
+// Create a memoized row component using areEqual from react-window
+const MemoizedRow = React.memo(
+ (rowProps: ExtendedListChildComponentProps) => {
+ const { data, index, listRef, rowHeights, rowNeedsMeasurement, style } =
+ rowProps;
+
+ if (index < data.length) {
+ const row = data[index];
+
+ return (
+
+ );
+ } else {
+ return ;
+ }
+ },
+ (prevProps, nextProps) => {
+ // Check if any of the ref props have changed
+ if (
+ prevProps.listRef !== nextProps.listRef ||
+ prevProps.rowHeights !== nextProps.rowHeights ||
+ prevProps.rowNeedsMeasurement !== nextProps.rowNeedsMeasurement
+ ) {
+ return false;
+ }
+
+ // For all other props, use react-window's areEqual
+ return areEqual(prevProps, nextProps);
+ },
+);
+
+export interface BaseVirtualListProps {
+ height: number;
+ tableSizes: TableSizes;
+ rows: ReactTableRowType>[];
+ innerElementType?: ReactElementType;
+ outerRef?: React.Ref;
+ onItemsRendered?: (props: ListOnItemsRenderedProps) => void;
+ infiniteLoaderListRef?: React.Ref;
+ itemCount: number;
+ pageSize: number;
+}
+
+const BaseVirtualList = React.memo(function BaseVirtualList({
+ height,
+ infiniteLoaderListRef,
+ innerElementType,
+ itemCount,
+ onItemsRendered,
+ outerRef,
+ rows,
+ tableSizes,
+}: BaseVirtualListProps) {
+ const listRef = useRef(null);
+ const rowHeights = useRef<{ [key: number]: number }>({});
+ const rowNeedsMeasurement = useRef<{ [key: number]: boolean }>({});
+ const combinedRef = (list: VariableSizeList | null) => {
+ // Handle infiniteLoaderListRef
+ if (infiniteLoaderListRef) {
+ if (typeof infiniteLoaderListRef === "function") {
+ infiniteLoaderListRef(list);
+ } else {
+ (
+ infiniteLoaderListRef as React.MutableRefObject
+ ).current = list;
+ }
+ }
+
+ // Handle listRef - only if it's a mutable ref
+ if (listRef && "current" in listRef) {
+ (listRef as React.MutableRefObject).current =
+ list;
+ }
+ };
+
+ const getItemSize = useCallback(
+ (index: number) => {
+ try {
+ const rowHeight = rowHeights?.current?.[index] || tableSizes.ROW_HEIGHT;
+
+ return Math.max(rowHeight, tableSizes.ROW_HEIGHT);
+ } catch (error) {
+ return tableSizes.ROW_HEIGHT;
+ }
+ },
+ [rowHeights?.current, tableSizes.ROW_HEIGHT],
+ );
+
+ // Memoize the row renderer function
+ const rowRenderer = useMemo(() => {
+ return (props: ListChildComponentProps) => (
+
+ );
+ }, [listRef, rowHeights, rowNeedsMeasurement]);
+
+ return (
+
+ {rowRenderer}
+
+ );
+});
+
+export default BaseVirtualList;
diff --git a/app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx
index daedfdb589a8..648ca853f812 100644
--- a/app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx
+++ b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/InifiniteScrollBody/index.tsx
@@ -2,7 +2,7 @@ import React, { type Ref } from "react";
import { type ReactElementType } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import type SimpleBar from "simplebar-react";
-import { FixedInfiniteVirtualList } from "../../TableBodyCoreComponents/VirtualList";
+import { VariableInfiniteVirtualList } from "../../TableBodyCoreComponents/VirtualList";
import { useAppsmithTable } from "../../TableContext";
import { LoadingIndicator } from "../../LoadingIndicator";
import { useInfiniteVirtualization } from "./useInfiniteVirtualization";
@@ -40,7 +40,7 @@ const InfiniteScrollBodyComponent = React.forwardRef(
minimumBatchSize={pageSize}
>
{({ onItemsRendered, ref: infiniteLoaderRef }) => (
- >,
+) {
+ const variableHeightColumnsRef = useRef([]);
+ const previousRowDataRef = useRef | null>(null);
+
+ const columnsNeedingVariableHeight = columns
+ .map((col, index) => {
+ if (col.columnProperties?.allowCellWrapping) {
+ return index;
+ }
+
+ if (col.columnProperties?.columnType === ColumnTypes.HTML) {
+ return index;
+ }
+
+ return -1;
+ })
+ .filter((index) => index !== -1);
+
+ const columnsConfigChanged =
+ columnsNeedingVariableHeight.length !==
+ variableHeightColumnsRef.current.length ||
+ columnsNeedingVariableHeight.some(
+ (colIndex, i) => colIndex !== variableHeightColumnsRef.current[i],
+ );
+
+ const currentRowData = row?.original || {};
+ const rowDataChanged = hasRowDataChanged(
+ currentRowData,
+ previousRowDataRef.current,
+ );
+
+ if (columnsConfigChanged || rowDataChanged) {
+ variableHeightColumnsRef.current = columnsNeedingVariableHeight;
+ previousRowDataRef.current = { ...currentRowData };
+ }
+
+ return variableHeightColumnsRef.current;
+}
+
+function hasRowDataChanged(
+ currentData: Record,
+ previousData: Record | null,
+): boolean {
+ if (!previousData) return true;
+
+ const currentKeys = Object.keys(currentData);
+ const previousKeys = Object.keys(previousData);
+
+ if (currentKeys.length !== previousKeys.length) return true;
+
+ for (const key of currentKeys) {
+ if (currentData[key] !== previousData[key]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+export default useColumnVariableHeight;
diff --git a/app/client/src/widgets/TableWidgetV2/component/VirtualTable/useRowHeightMeasurement.tsx b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/useRowHeightMeasurement.tsx
new file mode 100644
index 000000000000..c5ee5e4c54a6
--- /dev/null
+++ b/app/client/src/widgets/TableWidgetV2/component/VirtualTable/useRowHeightMeasurement.tsx
@@ -0,0 +1,159 @@
+import { useEffect, useMemo, type RefObject } from "react";
+import type { Row as ReactTableRowType } from "react-table";
+import type { VariableSizeList } from "react-window";
+import { ColumnTypes } from "widgets/TableWidgetV2/constants";
+import { TABLE_SIZES } from "../Constants";
+
+interface CellWithColumnProps {
+ column: {
+ columnProperties?: {
+ allowCellWrapping?: boolean;
+ columnType: ColumnTypes;
+ };
+ };
+}
+
+interface UseRowHeightMeasurementProps {
+ index: number; // Index of the current row
+ row: ReactTableRowType>; // Row data from react-table
+ rowRef?: React.RefObject; // Reference to the row DOM element
+ rowHeights?: RefObject<{ [key: number]: number }>; // Object storing calculated heights for each row
+ rowNeedsMeasurement?: RefObject<{ [key: number]: boolean }>; // Tracks which rows need height measurement
+ listRef?: RefObject | null; // Reference to the virtualized list component
+ forceUpdate: number; // Trigger to force recalculation of row heights
+ isInfiniteScrollEnabled?: boolean;
+}
+
+/**
+ * Hook for dynamically measuring and managing row heights in a virtualized table
+ *
+ * This hook is crucial for tables with variable row heights when using features like:
+ * - Cell wrapping
+ * - HTML content in cells
+ * - Infinite scrolling
+ *
+ * The hook measures the actual rendered height of specific cells that might affect row height
+ * (cells with wrapping enabled or HTML content) and updates the virtualized list accordingly.
+ *
+ * The measurement process:
+ * 1. Identifies cells that might affect row height (HTML cells or cells with wrapping)
+ * 2. Measures their actual rendered height including margins and padding
+ * 3. Updates the height in rowHeights and marks the row as measured
+ * 4. Notifies the virtualized list to update its internal cache
+ */
+export function useRowHeightMeasurement({
+ forceUpdate,
+ index,
+ isInfiniteScrollEnabled,
+ listRef,
+ row,
+ rowHeights,
+ rowNeedsMeasurement,
+ rowRef,
+}: UseRowHeightMeasurementProps) {
+ const hasPreRequisitesForInfiniteScroll = useMemo(() => {
+ return (
+ isInfiniteScrollEnabled && rowNeedsMeasurement && rowHeights && rowRef
+ );
+ }, [isInfiniteScrollEnabled, rowNeedsMeasurement, rowHeights, rowRef]);
+
+ const isAlreadyCalculated =
+ rowNeedsMeasurement &&
+ rowNeedsMeasurement.current &&
+ rowNeedsMeasurement.current[index] === false;
+
+ const hasRowDataAndUIElement = rowRef?.current && row;
+
+ useEffect(() => {
+ if (!hasPreRequisitesForInfiniteScroll || !hasRowDataAndUIElement) return;
+
+ // Skip measurement if this row was already processed
+ if (isAlreadyCalculated) {
+ return;
+ }
+
+ const element = rowRef?.current;
+
+ if (!hasRowDataAndUIElement) return;
+
+ // Track cells that might affect row height
+ const cellIndexesWithAllowCellWrapping: number[] = [];
+ const cellIndexesWithHTMLCell: number[] = [];
+
+ if (row?.cells && Array.isArray(row.cells)) {
+ row.cells.forEach((cell, index: number) => {
+ const typedCell = cell as unknown as CellWithColumnProps;
+
+ if (typedCell?.column?.columnProperties?.allowCellWrapping) {
+ cellIndexesWithAllowCellWrapping.push(index);
+ }
+
+ if (
+ typedCell?.column?.columnProperties?.columnType === ColumnTypes.HTML
+ ) {
+ cellIndexesWithHTMLCell.push(index);
+ }
+ });
+ }
+
+ // Get all child elements
+ const children = element.children;
+ let normalCellHeight = 0;
+ let htmlCellHeight = 0;
+
+ cellIndexesWithAllowCellWrapping.forEach((index: number) => {
+ const child = children[index] as HTMLElement;
+ const dynamicContent = child.querySelector(
+ ".t--table-cell-tooltip-target",
+ );
+
+ if (dynamicContent) {
+ const styles = window.getComputedStyle(dynamicContent);
+
+ // Calculate total height including margins and padding
+ normalCellHeight +=
+ (dynamicContent as HTMLElement).offsetHeight +
+ parseFloat(styles.marginTop) +
+ parseFloat(styles.marginBottom) +
+ parseFloat(styles.paddingTop) +
+ parseFloat(styles.paddingBottom);
+ }
+ });
+
+ cellIndexesWithHTMLCell.forEach((index: number) => {
+ const child = children[index] as HTMLElement;
+ const dynamicContent = child.querySelector(
+ '[data-testid="t--table-widget-v2-html-cell"]>span',
+ );
+
+ if (dynamicContent) {
+ const styles = window.getComputedStyle(dynamicContent);
+
+ htmlCellHeight +=
+ (dynamicContent as HTMLElement).offsetHeight +
+ parseFloat(styles.marginTop) +
+ parseFloat(styles.marginBottom) +
+ parseFloat(styles.paddingTop) * 2 +
+ parseFloat(styles.paddingBottom) * 2;
+ }
+ });
+
+ const totalHeight =
+ Math.max(normalCellHeight, htmlCellHeight) +
+ TABLE_SIZES.DEFAULT.VERTICAL_PADDING * 2;
+
+ rowHeights?.current && (rowHeights.current[index] = totalHeight);
+ rowNeedsMeasurement?.current &&
+ (rowNeedsMeasurement.current[index] = false);
+ // Notify the virtualized list to update its cache for this row
+ listRef?.current && listRef.current?.resetAfterIndex(index);
+ }, [
+ index,
+ row,
+ forceUpdate,
+ rowHeights,
+ rowNeedsMeasurement,
+ listRef,
+ rowRef,
+ ]);
+}