@@ -37,6 +37,7 @@ import {
3737 $getRoot ,
3838 $getSelection ,
3939 $isElementNode ,
40+ $isNodeSelection ,
4041 $isRangeSelection ,
4142 $isRootOrShadowRoot ,
4243 CAN_REDO_COMMAND ,
@@ -48,6 +49,7 @@ import {
4849 HISTORIC_TAG ,
4950 INDENT_CONTENT_COMMAND ,
5051 LexicalEditor ,
52+ LexicalNode ,
5153 NodeKey ,
5254 OUTDENT_CONTENT_COMMAND ,
5355 REDO_COMMAND ,
@@ -468,6 +470,21 @@ function ElementFormatDropdown({
468470 ) ;
469471}
470472
473+ function $findTopLevelElement ( node : LexicalNode ) {
474+ let topLevelElement =
475+ node . getKey ( ) === 'root'
476+ ? node
477+ : $findMatchingParent ( node , ( e ) => {
478+ const parent = e . getParent ( ) ;
479+ return parent !== null && $isRootOrShadowRoot ( parent ) ;
480+ } ) ;
481+
482+ if ( topLevelElement === null ) {
483+ topLevelElement = node . getTopLevelElementOrThrow ( ) ;
484+ }
485+ return topLevelElement ;
486+ }
487+
471488export default function ToolbarPlugin ( {
472489 editor,
473490 activeEditor,
@@ -486,6 +503,37 @@ export default function ToolbarPlugin({
486503 const [ isEditable , setIsEditable ] = useState ( ( ) => editor . isEditable ( ) ) ;
487504 const { toolbarState, updateToolbarState} = useToolbarState ( ) ;
488505
506+ const $handleHeadingNode = useCallback (
507+ ( selectedElement : LexicalNode ) => {
508+ const type = $isHeadingNode ( selectedElement )
509+ ? selectedElement . getTag ( )
510+ : selectedElement . getType ( ) ;
511+
512+ if ( type in blockTypeToBlockName ) {
513+ updateToolbarState (
514+ 'blockType' ,
515+ type as keyof typeof blockTypeToBlockName ,
516+ ) ;
517+ }
518+ } ,
519+ [ updateToolbarState ] ,
520+ ) ;
521+
522+ const $handleCodeNode = useCallback (
523+ ( element : LexicalNode ) => {
524+ if ( $isCodeNode ( element ) ) {
525+ const language =
526+ element . getLanguage ( ) as keyof typeof CODE_LANGUAGE_MAP ;
527+ updateToolbarState (
528+ 'codeLanguage' ,
529+ language ? CODE_LANGUAGE_MAP [ language ] || language : '' ,
530+ ) ;
531+ return ;
532+ }
533+ } ,
534+ [ updateToolbarState ] ,
535+ ) ;
536+
489537 const $updateToolbar = useCallback ( ( ) => {
490538 const selection = $getSelection ( ) ;
491539 if ( $isRangeSelection ( selection ) ) {
@@ -502,18 +550,7 @@ export default function ToolbarPlugin({
502550 }
503551
504552 const anchorNode = selection . anchor . getNode ( ) ;
505- let element =
506- anchorNode . getKey ( ) === 'root'
507- ? anchorNode
508- : $findMatchingParent ( anchorNode , ( e ) => {
509- const parent = e . getParent ( ) ;
510- return parent !== null && $isRootOrShadowRoot ( parent ) ;
511- } ) ;
512-
513- if ( element === null ) {
514- element = anchorNode . getTopLevelElementOrThrow ( ) ;
515- }
516-
553+ const element = $findTopLevelElement ( anchorNode ) ;
517554 const elementKey = element . getKey ( ) ;
518555 const elementDOM = activeEditor . getElementByKey ( elementKey ) ;
519556
@@ -545,26 +582,11 @@ export default function ToolbarPlugin({
545582
546583 updateToolbarState ( 'blockType' , type ) ;
547584 } else {
548- const type = $isHeadingNode ( element )
549- ? element . getTag ( )
550- : element . getType ( ) ;
551- if ( type in blockTypeToBlockName ) {
552- updateToolbarState (
553- 'blockType' ,
554- type as keyof typeof blockTypeToBlockName ,
555- ) ;
556- }
557- if ( $isCodeNode ( element ) ) {
558- const language =
559- element . getLanguage ( ) as keyof typeof CODE_LANGUAGE_MAP ;
560- updateToolbarState (
561- 'codeLanguage' ,
562- language ? CODE_LANGUAGE_MAP [ language ] || language : '' ,
563- ) ;
564- return ;
565- }
585+ $handleHeadingNode ( element ) ;
586+ $handleCodeNode ( element ) ;
566587 }
567588 }
589+
568590 // Handle buttons
569591 updateToolbarState (
570592 'fontColor' ,
@@ -622,7 +644,30 @@ export default function ToolbarPlugin({
622644 updateToolbarState ( 'isUppercase' , selection . hasFormat ( 'uppercase' ) ) ;
623645 updateToolbarState ( 'isCapitalize' , selection . hasFormat ( 'capitalize' ) ) ;
624646 }
625- } , [ activeEditor , editor , updateToolbarState ] ) ;
647+ if ( $isNodeSelection ( selection ) ) {
648+ const nodes = selection . getNodes ( ) ;
649+ for ( const selectedNode of nodes ) {
650+ const parentList = $getNearestNodeOfType < ListNode > (
651+ selectedNode ,
652+ ListNode ,
653+ ) ;
654+ if ( parentList ) {
655+ const type = parentList . getListType ( ) ;
656+ updateToolbarState ( 'blockType' , type ) ;
657+ } else {
658+ const selectedElement = $findTopLevelElement ( selectedNode ) ;
659+ $handleHeadingNode ( selectedElement ) ;
660+ $handleCodeNode ( selectedElement ) ;
661+ }
662+ }
663+ }
664+ } , [
665+ activeEditor ,
666+ editor ,
667+ updateToolbarState ,
668+ $handleHeadingNode ,
669+ $handleCodeNode ,
670+ ] ) ;
626671
627672 useEffect ( ( ) => {
628673 return editor . registerCommand (
0 commit comments