выступи в роли senior frontend developer, изучи код канвас таблицы
Суть проблемы: рисуются строки и в ячейках проверяется выводит ли ячейка просто текст или текст обернутый в несколько элементов верстки. Ранее проверки на текст не было и все ячейки с версткой (div, span, icons и так далее)  рендерилась только в overlay. Теперь после обновления drawRow идет проверка, если компонент рендерит только текст то он отрисуется через canvas
Необходимо оптимизировать рендеринг overlay слоя так чтобы в нем рендерились только компоненты, которые отображают не только текст (а еще иконки или несколько блоков и так далее)

export const drawRow = <T>(
  ctx: CanvasRenderingContext2D,
  record: T,
  rowIndex: number,
  headerHeight: number,
  columns: any[],
  data: T[],
  paddingLeft: number,
  paddingRight: number
) => {
  const rowHeight = 40;
  const yPos = headerHeight + rowIndex * rowHeight;

  let xPos = 0;
  columns.forEach((column) => {
    const { width = 120, align = 'left' } = column;
    const widthInt = getWidthNumber(width);

    // Рисуем границу
    ctx.strokeStyle = COLOR_BORDER;
    ctx.lineWidth = 1;
    ctx.strokeRect(xPos, yPos, widthInt, rowHeight);

    // Получаем значение
    const value = getCellValue(record, column, data);
    const renderText = value ?? '';

    // Обработка render-функций
    if (column.render) {
      const renderedContent = column.render(value, record, rowIndex);
      const { text, color } = getTextAndColorFromElement(renderedContent);
      if (text) {
        ctx.fillStyle = color;
        drawText(ctx, text, xPos, yPos, widthInt, rowHeight, align, paddingLeft, paddingRight);
      }
    }
    // Обычный текст (не чекбокс и не render)
    else if (column.key !== 'selection') {
      ctx.fillStyle = '#333';
      drawText(ctx, renderText.toString(), xPos, yPos, widthInt, rowHeight, align, paddingLeft, paddingRight);
    }

    xPos += widthInt;
  });
};

const drawText = (
  ctx: CanvasRenderingContext2D,
  text: string,
  xPos: number,
  yPos: number,
  width: number,
  rowHeight: number,
  align: CanvasTextAlign,
  paddingLeft: number,
  paddingRight: number
) => {
  ctx.font = "14px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif";
  ctx.textAlign = align;
  ctx.textBaseline = 'middle';

  const textX =
    align === 'left' ? xPos + paddingLeft : align === 'center' ? xPos + width / 2 : xPos + width - paddingRight;

  const textY = yPos + rowHeight / 2;

  ctx.fillText(text, textX, textY);
};

/* eslint-disable i18next/no-literal-string */
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { ColumnType, TablePaginationConfig } from 'antd/es/table';
import { SorterResult, TableCurrentDataSource } from 'antd/es/table/interface';

import FilterBlock from './components/FilterBlock/FilterBlock';

import { drawRow, getCellValue } from './utils';
import { drawHeader, getColumnXPosition, getRowYPosition, getWidthNumber, measureHeaderHeight } from './utils/utils';

import { TablePagination } from '../pagination';

import styles from './CanvasTable.module.scss';
import { CanvasTableProps, FilterConfig } from './types';
import { useTableData } from './useTableData';

const FONT_MAIN = "600 14px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif";
const CELL_PADDING_LEFT = 10;
const CELL_PADDING_RIGHT = 10;
// const COLOR_BORDER = '#f0f0f0';

const Table = <RecordType extends object = any>({
  columns,
  dataSource = [],
  onRow,
  rowSelection,
  rowKey,
  pagination,
  onChange,
  scroll
}: CanvasTableProps<RecordType>) => {
  console.log('Table rerender');
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const ctxRef = useRef<CanvasRenderingContext2D | null>(null);

  const filterBlockRef = useRef<HTMLDivElement>(null);
  const activeFiltersRef = useRef<FilterConfig>({});

  const [isCanvasReady, setCanvasReady] = useState(false);

  const scrollContainerRef = useRef<HTMLDivElement>(null);
  const selectedRowRef = useRef<number | null>(null);
  const [tableWidth, setTableWidth] = useState<number>(0);
  const [headerHeight, setHeaderHeight] = useState<number>(0);

  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);

  const [filterPopup, setFilterPopup] = useState<{
    columnKey: string;
    position: { left: number; top: number };
  } | null>(null);

  const { processedColumns, sortConfig } = useTableData({
    columns
  });

  const finalColumns = useMemo(() => {
    if (!rowSelection) return processedColumns;

    const checkboxColumn: ColumnType<RecordType> = {
      key: 'selection',
      title: undefined,
      width: rowSelection.columnWidth || 50,
      render: () => ''
    };

    return [checkboxColumn, ...processedColumns];
  }, [processedColumns, rowSelection?.columnWidth, !!rowSelection]);

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas?.getContext('2d');
    if (!ctx || !canvas) return;
    ctx.font = FONT_MAIN;

    const newHeaderHeight = measureHeaderHeight(ctx, finalColumns, 16, 16);
    setHeaderHeight(newHeaderHeight);
  }, [finalColumns]);

  useEffect(() => {
    setCanvasReady(false);
    const canvas = canvasRef.current;
    if (!headerHeight || (!canvasRef.current && !ctxRef.current)) return;

    const ctx = ctxRef.current || canvasRef.current?.getContext('2d');
    if (!ctx) return;
    ctxRef.current = ctx;
    if (!canvas) return;

    ctx.font = FONT_MAIN;

    const newHeaderHeight = measureHeaderHeight(ctx, finalColumns, 16, 16);
    const rowHeight = 40;
    const totalWidth = finalColumns.reduce((sum, col) => sum + getWidthNumber(col.width || 0), 0);
    const totalHeight = dataSource.length * rowHeight + newHeaderHeight;

    setHeaderHeight(newHeaderHeight);
    setTableWidth(totalWidth);

    const ratio = window.devicePixelRatio || 1;
    canvas.width = totalWidth * ratio;
    canvas.height = totalHeight * ratio;
    canvas.style.width = `${totalWidth}px`;
    canvas.style.height = `${totalHeight}px`;

    ctx.setTransform(1, 0, 0, 1, 0, 0);
    ctx.scale(ratio, ratio);
    ctx.clearRect(0, 0, totalWidth, totalHeight);

    drawHeader(ctx, totalWidth, newHeaderHeight, finalColumns, sortConfig, activeFiltersRef.current);
    dataSource.forEach((record, index) =>
      drawRow(ctx, record, index, newHeaderHeight, finalColumns, dataSource, CELL_PADDING_LEFT, CELL_PADDING_RIGHT)
    );

    setCanvasReady(true);
  }, [finalColumns, dataSource, sortConfig, headerHeight]);


  const [internalPagination, setInternalPagination] = useState<TablePaginationConfig>({
    current: 1,
    pageSize: 10,
    ...pagination
  });

  const handlePaginationChange = useCallback(
    (page: number, pageSize: number) => {
      const newPagination = { ...internalPagination, current: page, pageSize };
      setInternalPagination(newPagination);
      onChange?.(
        newPagination,
        {},
        {} as SorterResult<RecordType>,
        {
          currentDataSource: dataSource
        } as TableCurrentDataSource<RecordType>
      );
    },
    [internalPagination, setInternalPagination, onChange, dataSource]
  );

  const handleApplyFilters = useCallback(
    (columnKey: string, values: string[]) => {
      const newFilters = { columnKey: activeFiltersRef.current[columnKey] };

      activeFiltersRef.current[columnKey] = values;

      onChange?.(
        internalPagination,
        newFilters,
        {},
        {
          currentDataSource: dataSource,
          action: 'filter'
        }
      );

      setFilterPopup(null);
    },
    [dataSource, internalPagination, onChange, activeFiltersRef.current]
  );

  useEffect(() => {
    console.log('sortConfig:', sortConfig);
  }, [sortConfig]);

  const availableFilters = useMemo(() => {
    if (!filterPopup) return [];
    return finalColumns.find((col) => col.key === filterPopup.columnKey)?.filters || [];
  }, [finalColumns, filterPopup?.columnKey]);

  const handleFilterClose = useCallback(() => {
    setFilterPopup(null);
  }, []);

  return (
    <div className={styles.tableContainer} onClick={handleClick}>
      <div
        ref={scrollContainerRef}
        className={styles.scrollContainer}
        style={{
          maxWidth: scroll?.x,
          maxHeight: scroll?.y,
          overflow: 'auto'
        }}
      >
        <div style={{ width: tableWidth }} className={styles.canvasWrapper}>
          <canvas ref={canvasRef} className={styles.canvas} />

          {filterPopup && (
            <FilterBlock
              ref={filterBlockRef}
              initialFilters={activeFiltersRef.current?.[filterPopup.columnKey] || []}
              filters={availableFilters}
              filterPopup={filterPopup}
              onApplyFilters={handleApplyFilters}
              onClose={handleFilterClose}
            />
          )}

          {/* Overlay для render-компонентов */}
          {isCanvasReady && (
            <div className={styles.overlay}>
              {/* Чекбоксы */}
              {dataSource.map((record, rowIndex) =>
                finalColumns.map((column, colIndex) => {
                  const xPos = getColumnXPosition(colIndex, finalColumns);
                  const yPos = getRowYPosition(rowIndex, headerHeight);

                  if (column.key === 'selection') {
                    const recordKey = typeof rowKey === 'function' ? rowKey(record) : (record as any).id;
                    const isChecked = selectedRowKeys.includes(recordKey);

                    return (
                      <div
                        key={`${rowIndex}-selection`}
                        className={styles.cellOverlay}
                        style={{
                          left: `${xPos}px`,
                          top: `${yPos}px`,
                          width: `${column.width || 50}px`,
                          height: '40px',
                          display: 'flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          padding: column.align === 'center' || column.align === 'right' ? '0 10px' : '0 10px 0 10px'
                        }}
                      >
                        <input
                          type="checkbox"
                          checked={isChecked}
                          onChange={(e) => {
                            const newKeys = e.target.checked
                              ? [...selectedRowKeys, recordKey]
                              : selectedRowKeys.filter((k) => k !== recordKey);

                            setSelectedRowKeys(newKeys);
                            rowSelection?.onChange?.(
                              newKeys,
                              dataSource.filter((r) =>
                                newKeys.includes(typeof rowKey === 'function' ? rowKey(r) : (r as any).id)
                              ),
                              { type: 'single' }
                            );
                          }}
                          className={styles.checkbox}
                        />
                      </div>
                    );
                  }

                  return null;
                })
              )}

              {/* Остальные ячейки с render */}
              {dataSource.map((record, rowIndex) =>
                finalColumns.map((column, colIndex) => {
                  const xPos = getColumnXPosition(colIndex, finalColumns);
                  const yPos = getRowYPosition(rowIndex, headerHeight);

                  if (column.key === 'selection') return null;
                  // Если нет render → не рендерим в overlay
                  if (!column.render) return null;

                  const value = getCellValue(record, column, dataSource);
                  const renderedValue = column.render
                    ? (column.render(
                        column.dataIndex ? (record as any)[column.dataIndex] : undefined,
                        record,
                        rowIndex
                      ) as React.ReactNode)
                    : value;

                  if (!column.render || typeof renderedValue === 'string' || typeof renderedValue === 'number') {
                    return null;
                  }

                  return (
                    <div
                      key={`${rowIndex}-${column.key}`}
                      className={styles.cellOverlay}
                      style={{
                        left: `${xPos}px`,
                        top: `${yPos}px`,
                        width: `${column.width || 120}px`,
                        height: '40px',
                        display: 'flex',
                        alignItems: 'center',
                        padding: column.align === 'center' || column.align === 'right' ? '0 10px' : '0 10px 0 10px',
                        justifyContent:
                          column.align === 'center' ? 'center' : column.align === 'right' ? 'flex-end' : 'flex-start'
                      }}
                    >
                      {renderedValue}
                    </div>
                  );
                })
              )}
            </div>
          )}
        </div>
      </div>
      {pagination && (
        <TablePagination
          pagination={internalPagination}
          onChange={handlePaginationChange}
          total={internalPagination.total || dataSource.length}
        />
      )}
    </div>
  );
};

export const CanvasTable = memo(Table) as typeof Table;