@@ -58,13 +58,45 @@ export class FormattingToolbarView implements PluginView {
5858 pmView . dom . addEventListener ( "mouseup" , this . viewMouseupHandler ) ;
5959 pmView . dom . addEventListener ( "dragstart" , this . dragHandler ) ;
6060 pmView . dom . addEventListener ( "dragover" , this . dragHandler ) ;
61+ pmView . dom . addEventListener ( "blur" , this . blurHandler ) ;
6162
6263 // Setting capture=true ensures that any parent container of the editor that
6364 // gets scrolled will trigger the scroll event. Scroll events do not bubble
6465 // and so won't propagate to the document by default.
6566 pmView . root . addEventListener ( "scroll" , this . scrollHandler , true ) ;
6667 }
6768
69+ blurHandler = ( event : FocusEvent ) => {
70+ if ( this . preventHide ) {
71+ this . preventHide = false ;
72+
73+ return ;
74+ }
75+
76+ const editorWrapper = this . pmView . dom . parentElement ! ;
77+
78+ // Checks if the focus is moving to an element outside the editor. If it is,
79+ // the toolbar is hidden.
80+ if (
81+ // An element is clicked.
82+ event &&
83+ event . relatedTarget &&
84+ // Element is inside the editor.
85+ ( editorWrapper === ( event . relatedTarget as Node ) ||
86+ editorWrapper . contains ( event . relatedTarget as Node ) ||
87+ ( event . relatedTarget as HTMLElement ) . matches (
88+ ".bn-ui-container, .bn-ui-container *"
89+ ) )
90+ ) {
91+ return ;
92+ }
93+
94+ if ( this . state ?. show ) {
95+ this . state . show = false ;
96+ this . emitUpdate ( ) ;
97+ }
98+ } ;
99+
68100 viewMousedownHandler = ( ) => {
69101 this . preventShow = true ;
70102 } ;
@@ -90,6 +122,10 @@ export class FormattingToolbarView implements PluginView {
90122 } ;
91123
92124 update ( view : EditorView , oldState ?: EditorState ) {
125+ // Delays the update to handle edge case with drag and drop, where the view
126+ // is blurred asynchronously and happens only after the state update.
127+ // Wrapping in a setTimeout gives enough time to wait for the blur event to
128+ // occur before updating the toolbar.
93129 const { state, composing } = view ;
94130 const { doc, selection } = state ;
95131 const isSame =
@@ -146,6 +182,7 @@ export class FormattingToolbarView implements PluginView {
146182 this . pmView . dom . removeEventListener ( "mouseup" , this . viewMouseupHandler ) ;
147183 this . pmView . dom . removeEventListener ( "dragstart" , this . dragHandler ) ;
148184 this . pmView . dom . removeEventListener ( "dragover" , this . dragHandler ) ;
185+ this . pmView . dom . removeEventListener ( "blur" , this . blurHandler ) ;
149186
150187 this . pmView . root . removeEventListener ( "scroll" , this . scrollHandler , true ) ;
151188 }
0 commit comments