From 5543c563c723ffc50d891c664c9a006a23efbe2b Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Wed, 3 Dec 2025 15:29:21 +0100 Subject: [PATCH 1/2] Memoized Floating UI options in `TableHandlesController` --- .../TableHandles/TableHandlesController.tsx | 201 +++++++++++------- 1 file changed, 119 insertions(+), 82 deletions(-) diff --git a/packages/react/src/components/TableHandles/TableHandlesController.tsx b/packages/react/src/components/TableHandles/TableHandlesController.tsx index 88379030b4..a039f9b9b2 100644 --- a/packages/react/src/components/TableHandles/TableHandlesController.tsx +++ b/packages/react/src/components/TableHandles/TableHandlesController.tsx @@ -12,6 +12,7 @@ import { FC, useMemo, useState } from "react"; import { offset, size } from "@floating-ui/react"; import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js"; import { useExtensionState } from "../../hooks/useExtension.js"; +import { FloatingUIOptions } from "../Popovers/FloatingUIOptions.js"; import { GenericPopover, GenericPopoverReference, @@ -143,6 +144,119 @@ export const TableHandlesController = < }; }, [editor, state]); + const floatingUIOptions = useMemo< + | { + rowTableHandle: FloatingUIOptions; + columnTableHandle: FloatingUIOptions; + tableCellHandle: FloatingUIOptions; + extendRowsButton: FloatingUIOptions; + extendColumnsButton: FloatingUIOptions; + } + | undefined + >( + () => + state !== undefined + ? { + rowTableHandle: { + useFloatingOptions: { + open: + state.show && + state.rowIndex !== undefined && + (!onlyShownElement || onlyShownElement === "rowTableHandle"), + placement: "left", + middleware: [offset(-10)], + }, + elementProps: { + style: { + zIndex: 10, + }, + }, + }, + columnTableHandle: { + useFloatingOptions: { + open: + state.show && + state.colIndex !== undefined && + (!onlyShownElement || + onlyShownElement === "columnTableHandle"), + placement: "top", + middleware: [offset(-12)], + }, + elementProps: { + style: { + zIndex: 10, + }, + }, + }, + tableCellHandle: { + useFloatingOptions: { + open: + state.show && + state.rowIndex !== undefined && + state.colIndex !== undefined && + (!onlyShownElement || onlyShownElement === "tableCellHandle"), + placement: "top-end", + middleware: [offset({ mainAxis: -15, crossAxis: -1 })], + }, + elementProps: { + style: { + zIndex: 10, + }, + }, + }, + extendRowsButton: { + useFloatingOptions: { + open: + state.show && + state.showAddOrRemoveRowsButton && + (!onlyShownElement || + onlyShownElement === "extendRowsButton"), + placement: "bottom", + middleware: [ + size({ + apply({ rects, elements }) { + Object.assign(elements.floating.style, { + width: `${rects.reference.width}px`, + }); + }, + }), + ], + }, + elementProps: { + style: { + zIndex: 10, + }, + }, + }, + extendColumnsButton: { + useFloatingOptions: { + open: + state.show && + state.showAddOrRemoveColumnsButton && + (!onlyShownElement || + onlyShownElement === "extendColumnsButton"), + placement: "right", + middleware: [ + size({ + apply({ rects, elements }) { + Object.assign(elements.floating.style, { + height: `${rects.reference.height}px`, + }); + }, + }), + ], + }, + elementProps: { + style: { + zIndex: 10, + }, + }, + }, + } + : undefined, + [onlyShownElement, state], + ); + if (!state) { return null; } @@ -155,19 +269,7 @@ export const TableHandlesController = < <> {state.show && state.rowIndex !== undefined && @@ -182,19 +284,7 @@ export const TableHandlesController = < {state.show && state.colIndex !== undefined && @@ -209,20 +299,7 @@ export const TableHandlesController = < {state.show && state.rowIndex !== undefined && @@ -237,27 +314,7 @@ export const TableHandlesController = < {state.show && state.showAddOrRemoveRowsButton && @@ -272,27 +329,7 @@ export const TableHandlesController = < {state.show && state.showAddOrRemoveColumnsButton && From f33f1573aa750368f06a30697b39b950c341470c Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Fri, 5 Dec 2025 12:14:01 +0100 Subject: [PATCH 2/2] Fixed extend button positions not updating when dragging in some cases --- .../TableHandles/TableHandlesController.tsx | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/packages/react/src/components/TableHandles/TableHandlesController.tsx b/packages/react/src/components/TableHandles/TableHandlesController.tsx index a039f9b9b2..de1e01795c 100644 --- a/packages/react/src/components/TableHandles/TableHandlesController.tsx +++ b/packages/react/src/components/TableHandles/TableHandlesController.tsx @@ -45,25 +45,20 @@ export const TableHandlesController = < const state = useExtensionState(TableHandlesExtension); - const references = useMemo< - | { - tableReference: undefined; - cellReference: undefined; - rowReference: undefined; - columnReference: undefined; - } - | { - tableReference: GenericPopoverReference; - cellReference: GenericPopoverReference; - rowReference: GenericPopoverReference; - columnReference: GenericPopoverReference; - } - >(() => { - if ( - state === undefined || - state.rowIndex === undefined || - state.colIndex === undefined - ) { + const references = useMemo<{ + tableReference?: GenericPopoverReference; + cellReference?: GenericPopoverReference; + rowReference?: GenericPopoverReference; + columnReference?: GenericPopoverReference; + }>(() => { + const references: { + tableReference?: GenericPopoverReference; + cellReference?: GenericPopoverReference; + rowReference?: GenericPopoverReference; + columnReference?: GenericPopoverReference; + } = {}; + + if (state === undefined) { return {}; } @@ -85,7 +80,11 @@ export const TableHandlesController = < return {}; } - const tableReference = { element: tableElement }; + references.tableReference = { element: tableElement }; + + if (state.rowIndex === undefined || state.colIndex === undefined) { + return references; + } const rowBeforePos = editor.prosemirrorState.doc .resolve(tableBeforePos + 1) @@ -99,9 +98,8 @@ export const TableHandlesController = < return {}; } - const cellReference = { element: cellElement }; - - const rowReference = { + references.cellReference = { element: cellElement }; + references.rowReference = { element: tableElement, getBoundingClientRect: () => { const tableBoundingRect = tableElement.getBoundingClientRect(); @@ -118,7 +116,7 @@ export const TableHandlesController = < ); }, }; - const columnReference = { + references.columnReference = { element: tableElement, getBoundingClientRect: () => { const tableBoundingRect = tableElement.getBoundingClientRect(); @@ -136,12 +134,7 @@ export const TableHandlesController = < }, }; - return { - tableReference, - cellReference, - rowReference, - columnReference, - }; + return references; }, [editor, state]); const floatingUIOptions = useMemo<