Skip to content

Commit 6611d53

Browse files
fix(table): read table element from context to prevent stale-path crash on Enter (#5064)
When Enter splits or inserts a block before a table, useElementSelector's path becomes stale and resolves to the wrong node (e.g. the heading). Passing this non-table node to compileTableGrid crashes with: TypeError: Cannot read properties of undefined (reading 'forEach') Fix: useTableColSizes now reads the table element from useElement(KEYS.table) which always returns the context-bound table node, instead of re-reading from the editor via a potentially stale path. Closes #5064
1 parent 2938677 commit 6611d53

2 files changed

Lines changed: 28 additions & 25 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@platejs/table": patch
3+
---
4+
5+
Fix crash when pressing Enter before a table on the homepage editor. `useTableColSizes` now reads the table element from React context (`useElement`) instead of re-reading from the editor via a potentially stale path, preventing `compileTableGrid` from receiving a non-table node during mid-transaction re-renders.

packages/table/src/react/useTableElement.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import {
44
useEditorPlugin,
55
useEditorSelector,
66
useElement,
7-
useElementSelector,
87
} from '@platejs/core/react';
9-
import { PathApi } from '@platejs/plite';
8+
109
import { useClaimEditableDOMCommit } from '@platejs/plite-react/internal';
1110
import { KEYS, type TTableElement } from '@platejs/utils';
1211
import React from 'react';
@@ -52,31 +51,30 @@ export const useTableColSizes = ({
5251
} = {}): number[] => {
5352
const { editor } = useEditorPlugin(TablePlugin);
5453
const colSizeOverrides = useTableValue('colSizeOverrides');
55-
const tablePath = useElementSelector(([, path]) => path, {
56-
name: KEYS.table,
57-
});
58-
59-
const overriddenColSizes = useEditorSelector(
60-
() => {
61-
const tableNode = editor.read.nodes.get<TTableElement>(tablePath)?.[0];
62-
63-
if (!tableNode) return [];
64-
65-
const colSizes = editor
66-
.plugin(TablePlugin)
67-
.api.getOverriddenColumnSizes(
68-
tableNode,
69-
disableOverrides ? undefined : colSizeOverrides
70-
);
7154

72-
if (transformColSizes) {
73-
return transformColSizes(colSizes);
74-
}
55+
// Read the table element from React context rather than re-reading from the
56+
// editor via a path. During a transaction that inserts or splits a block
57+
// before the table (e.g. pressing Enter in a heading), the path from
58+
// useElementSelector can become stale and resolve to the wrong node, crashing
59+
// compileTableGrid. useElement always returns the context-bound table node.
60+
const tableElement = useElement<TTableElement>(KEYS.table);
61+
62+
const overriddenColSizes = React.useMemo(() => {
63+
if (!tableElement) return [];
64+
65+
const colSizes = editor
66+
.plugin(TablePlugin)
67+
.api.getOverriddenColumnSizes(
68+
tableElement,
69+
disableOverrides ? undefined : colSizeOverrides
70+
);
71+
72+
if (transformColSizes) {
73+
return transformColSizes(colSizes);
74+
}
7575

76-
return colSizes;
77-
},
78-
{ equalityFn: (a, b) => !!a && PathApi.equals(a, b) }
79-
);
76+
return colSizes;
77+
}, [tableElement, colSizeOverrides, disableOverrides, editor, transformColSizes]);
8078

8179
return overriddenColSizes;
8280
};

0 commit comments

Comments
 (0)