'Antd Resizable table columns in TypeScript

I'm implementing antd <Table> component and need to make columns resizable with react-resizable. I was following the example in the documentation, but since my project in in TypeScript and using functional components I had to refactor it and I've faced issues with typings. When I'm trying to implement that onHeaderCell from example:

const initialColumns: ColumnProps<Row>[] = myData.columns.map((column, index) => {
  return {
    ...
    onHeaderCell: (c: ColumnType<Row>) => ({
          width: c.width,
          onResize: handleResize(index),
        }),
    ...
  })

I'm getting this error:

... The types returned by 'onHeaderCell(...)' are incompatible between these types. Type '{ width: string | number | undefined; onResize: (e: SyntheticEvent<Element, Event>, resizeData: ResizeCallbackData) => void; }' has no properties in common with type 'HTMLAttributes'.

My handleResize looks like this:

const handleResize = (index: number) => (e: React.SyntheticEvent<Element, Event>, resizeData: ResizeCallbackData) => {
    const { size } = resizeData
    updateColumns((cols) => {
      const nextColumns = [...cols]
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width,
      }
      return nextColumns
    })
  }

I've moved ResizableTitle into separate component and <Table /> is implemented this way

const components = {
    header: {
      cell: ResizableTitle,
    },
  }

  return (
    <Table
      bordered
      components={components}
      columns={columns} // columns come from the useState<ColumnProps<Row>[]>()
      ...
    />
  )

How can I change this to get desired results?



Solution 1:[1]

So I found a solution without using react-resizable

const [resizingColumnIndex, _setResizingColumnIndex] = useState<number>();
const resizingColumnIndexRef = useRef(resizingColumnIndex);
  
const setResizingColumnIndex = (index: number | undefined) => {
    resizingColumnIndexRef.current = index;
    _setResizingColumnIndex(index);
};

const resizeListener = (e: MouseEvent) => {
  if (resizingColumnIndexRef.current) {
    handleResize(resizingColumnIndexRef.current, e.movementX);
  }
  window.onmouseup = (e: MouseEvent) => {
    window.removeEventListener("mousemove", resizeListener);
    setResizingColumnIndex(undefined);
  };
};

In each column title I'm adding

<div
  className="resizeHandle"
  onMouseDown={() => {
    setResizingColumnIndex(index);
    window.addEventListener("mousemove", resizeListener, { passive: true });
  }}
/>

having style of

  .resizeHandle {
    position: absolute;
    width: 10px;
    height: 100%;
    bottom: 0;
    right: -5px;
    cursor: col-resize;
    z-index: 5;
  }

Finally the handleResize function that updates columns kept in state of the component

  const handleResize = (index: number, delta: number) => {
    updateColumns(prevColumns => {
      const indexNewWidth = Number(prevColumns[index].width) + delta;
      const nextWidth = indexNewWidth >= MIN_COLUMN_WIDTH ? indexNewWidth : MIN_COLUMN_WIDTH;
      return prevColumns.map((col, i) => (i === index ? { ...col, width: nextWidth } : col));
    });
    setTableWidth(prevWidth => prevWidth + delta);
  };

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sergei Klinov