@@ -131,7 +131,7 @@ interface ToolbarButtonConfig {
131131 id : string ;
132132 label : string ;
133133 icon : React . FC < { className ?: string } > ;
134- group : 'history' | 'inline-format' | 'structure' | 'insert' | 'alignment' | 'utility' ;
134+ group : 'history' | 'inline-format' | 'structure' | 'insert' | 'alignment' | 'utility' | 'table' ;
135135 isActive ?: boolean ;
136136 disabled ?: boolean ;
137137 onClick : ( ) => void ;
@@ -986,6 +986,35 @@ const ToolbarPlugin: React.FC<{
986986 setIsTableModalOpen ( false ) ;
987987 } , [ runWithActiveTable ] ) ;
988988
989+ const selectTable = useCallback (
990+ ( ) =>
991+ runWithActiveTable ( selection => {
992+ const tableCell = $getTableCellNodeFromLexicalNode ( selection . anchor . getNode ( ) ) ;
993+ if ( ! tableCell ) {
994+ return ;
995+ }
996+ const tableNode = $getTableNodeFromLexicalNodeOrThrow ( tableCell ) ;
997+ const firstRow = tableNode . getFirstChild ( ) ;
998+ const lastRow = tableNode . getLastChild ( ) ;
999+
1000+ if ( ! $isTableRowNode ( firstRow ) || ! $isTableRowNode ( lastRow ) ) {
1001+ return ;
1002+ }
1003+
1004+ const firstCell = firstRow . getFirstChild ( ) ;
1005+ const lastCell = lastRow . getLastChild ( ) ;
1006+
1007+ if ( ! $isTableCellNode ( firstCell ) || ! $isTableCellNode ( lastCell ) ) {
1008+ return ;
1009+ }
1010+
1011+ const tableSelection = $createTableSelection ( ) ;
1012+ tableSelection . set ( tableNode . getKey ( ) , firstCell . getKey ( ) , lastCell . getKey ( ) ) ;
1013+ $setSelection ( tableSelection ) ;
1014+ } ) ,
1015+ [ runWithActiveTable ] ,
1016+ ) ;
1017+
9891018 const toggleHeaderRow = useCallback (
9901019 ( ) =>
9911020 runWithActiveTable ( selection => {
@@ -1279,9 +1308,93 @@ const ToolbarPlugin: React.FC<{
12791308 ] ,
12801309 ) ;
12811310
1311+ const tableContextActions = useMemo < ToolbarButtonConfig [ ] > (
1312+ ( ) => [
1313+ {
1314+ id : 'insert-column-before' ,
1315+ label : 'Insert column before' ,
1316+ icon : TableIcon ,
1317+ group : 'table' ,
1318+ disabled : readOnly || ! isInTable ,
1319+ onClick : ( ) => insertTableColumn ( false ) ,
1320+ } ,
1321+ {
1322+ id : 'insert-column-after' ,
1323+ label : 'Insert column after' ,
1324+ icon : TableIcon ,
1325+ group : 'table' ,
1326+ disabled : readOnly || ! isInTable ,
1327+ onClick : ( ) => insertTableColumn ( true ) ,
1328+ } ,
1329+ {
1330+ id : 'insert-row-before' ,
1331+ label : 'Insert row before' ,
1332+ icon : TableIcon ,
1333+ group : 'table' ,
1334+ disabled : readOnly || ! isInTable ,
1335+ onClick : ( ) => insertTableRow ( false ) ,
1336+ } ,
1337+ {
1338+ id : 'insert-row-after' ,
1339+ label : 'Insert row after' ,
1340+ icon : TableIcon ,
1341+ group : 'table' ,
1342+ disabled : readOnly || ! isInTable ,
1343+ onClick : ( ) => insertTableRow ( true ) ,
1344+ } ,
1345+ {
1346+ id : 'delete-row' ,
1347+ label : 'Delete row' ,
1348+ icon : TableIcon ,
1349+ group : 'table' ,
1350+ disabled : readOnly || ! isInTable ,
1351+ onClick : deleteTableRow ,
1352+ } ,
1353+ {
1354+ id : 'delete-column' ,
1355+ label : 'Delete column' ,
1356+ icon : TableIcon ,
1357+ group : 'table' ,
1358+ disabled : readOnly || ! isInTable ,
1359+ onClick : deleteTableColumn ,
1360+ } ,
1361+ {
1362+ id : 'delete-table' ,
1363+ label : 'Delete table' ,
1364+ icon : TableIcon ,
1365+ group : 'table' ,
1366+ disabled : readOnly || ! isInTable ,
1367+ onClick : deleteTable ,
1368+ } ,
1369+ {
1370+ id : 'select-table' ,
1371+ label : 'Select table' ,
1372+ icon : TableIcon ,
1373+ group : 'table' ,
1374+ disabled : readOnly || ! isInTable ,
1375+ onClick : selectTable ,
1376+ } ,
1377+ ] ,
1378+ [
1379+ deleteTable ,
1380+ deleteTableColumn ,
1381+ deleteTableRow ,
1382+ insertTableColumn ,
1383+ insertTableRow ,
1384+ isInTable ,
1385+ readOnly ,
1386+ selectTable ,
1387+ ] ,
1388+ ) ;
1389+
1390+ const contextMenuActions = useMemo (
1391+ ( ) => [ ...toolbarButtons , ...tableContextActions ] ,
1392+ [ tableContextActions , toolbarButtons ] ,
1393+ ) ;
1394+
12821395 useEffect ( ( ) => {
1283- onActionsChange ( toolbarButtons ) ;
1284- } , [ toolbarButtons , onActionsChange ] ) ;
1396+ onActionsChange ( contextMenuActions ) ;
1397+ } , [ contextMenuActions , onActionsChange ] ) ;
12851398
12861399 const renderedToolbarElements = useMemo (
12871400 ( ) => {
@@ -1606,6 +1719,7 @@ const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(
16061719 const selectionActions = contextActions . filter ( action =>
16071720 [ 'inline-format' , 'alignment' , 'structure' , 'utility' ] . includes ( action . group ) ,
16081721 ) ;
1722+ const tableActions = contextActions . filter ( action => action . group === 'table' ) ;
16091723 const insertActions = contextActions . filter ( action => action . group === 'insert' ) ;
16101724
16111725 const items : ContextMenuItem [ ] = [ ] ;
@@ -1623,6 +1737,18 @@ const RichTextEditor = forwardRef<RichTextEditorHandle, RichTextEditorProps>(
16231737 } ) ;
16241738 }
16251739
1740+ if ( items . length > 0 && tableActions . length > 0 && items [ items . length - 1 ] ?. type !== 'separator' ) {
1741+ items . push ( { type : 'separator' } ) ;
1742+ }
1743+
1744+ if ( tableActions . length > 0 ) {
1745+ items . push ( {
1746+ label : 'Table' ,
1747+ submenu : mapActionsToMenuItems ( tableActions ) ,
1748+ disabled : tableActions . every ( action => action . disabled ) ,
1749+ } ) ;
1750+ }
1751+
16261752 if ( items . length > 0 && insertActions . length > 0 ) {
16271753 items . push ( { type : 'separator' } ) ;
16281754 }
0 commit comments