@@ -271,6 +271,27 @@ const Editor = forwardRef<any, RichTextEditorProps>(
271271 redo : function ( ) {
272272 ( this as any ) . quill . history . redo ( ) ;
273273 } ,
274+ clean : function ( ) {
275+ const quill = ( this as any ) . quill ;
276+ const range = quill . getSelection ( true ) ;
277+ if ( range ) {
278+ // Remove all formatting
279+ quill . removeFormat ( range ) ;
280+ // Set default font size
281+ quill . formatText (
282+ range . index ,
283+ range . length ,
284+ 'size' ,
285+ '14px'
286+ ) ;
287+ quill . formatText (
288+ range . index ,
289+ range . length ,
290+ 'font' ,
291+ 'arial'
292+ ) ;
293+ }
294+ } ,
274295 fullscreen : function ( ) {
275296 // Handled by manual event listener below (needs to toggle icon and fullscreen state)
276297 } ,
@@ -282,9 +303,53 @@ const Editor = forwardRef<any, RichTextEditorProps>(
282303
283304 quillRef . current = quill ;
284305
306+ // Set default formats
285307 quill . format ( 'size' , '14px' ) ;
286308 quill . format ( 'font' , 'arial' ) ;
287309
310+ /** ----------------------------------------------
311+ * Update toolbar pickers to show active state on initial load
312+ * ---------------------------------------------- */
313+ const toolbarModule = quill . getModule ( 'toolbar' ) ;
314+ const updatePicker = ( pickerClass : string , value : string ) => {
315+ const picker =
316+ toolbarModule . container . querySelector ( pickerClass ) ;
317+ const label = picker ?. querySelector ( '.ql-picker-label' ) ;
318+ // Picker options may not be in DOM until first opened, so we need to trigger their creation
319+ const pickerButton = picker ?. querySelector (
320+ '.ql-picker-label'
321+ ) as HTMLElement ;
322+ if (
323+ pickerButton &&
324+ ! picker ?. querySelector ( '.ql-picker-options' )
325+ ) {
326+ // Trigger picker to render options by simulating a click
327+ pickerButton . click ( ) ;
328+ pickerButton . click ( ) ; // Click again to close it
329+ }
330+
331+ const options = picker ?. querySelector ( '.ql-picker-options' ) ;
332+ const option = options ?. querySelector (
333+ `[data-value="${ value } "]`
334+ ) as HTMLElement ;
335+
336+ if ( label && option ) {
337+ const labelSpan = label . querySelector ( 'span' ) ;
338+ if ( labelSpan )
339+ labelSpan . textContent = option . textContent ;
340+ label . setAttribute ( 'data-value' , value ) ;
341+ options
342+ . querySelectorAll ( '.ql-picker-item' )
343+ . forEach ( ( item : any ) => {
344+ item . classList . remove ( 'ql-selected' ) ;
345+ } ) ;
346+ option . classList . add ( 'ql-selected' ) ;
347+ }
348+ } ;
349+
350+ updatePicker ( '.ql-size' , '14px' ) ;
351+ updatePicker ( '.ql-font' , 'arial' ) ;
352+
288353 /** ----------------------------------------------
289354 * Enhanced color picker with hex input and remove button
290355 * ---------------------------------------------- */
@@ -687,6 +752,9 @@ const Editor = forwardRef<any, RichTextEditorProps>(
687752 const currentFormat = quill . getFormat ( range ) ;
688753 const hadHeader = currentFormat . header ;
689754
755+ // Update lastFontSize ref when size is changed
756+ lastFontSize . current = value ;
757+
690758 // Apply the size change
691759 const result = originalFormat ( name , value , source ) ;
692760
@@ -711,6 +779,12 @@ const Editor = forwardRef<any, RichTextEditorProps>(
711779 return result ;
712780 }
713781 }
782+
783+ // When font is being changed, update lastFont ref
784+ if ( name === 'font' && value !== null && value !== false ) {
785+ lastFont . current = value ;
786+ }
787+
714788 return originalFormat ( name , value , source ) ;
715789 } ;
716790
@@ -726,12 +800,29 @@ const Editor = forwardRef<any, RichTextEditorProps>(
726800 if ( f . font ) lastFont . current = f . font ;
727801 } ) ;
728802
803+ // Update last font/size when format is changed via toolbar
804+ quill . on (
805+ Quill . events . TEXT_CHANGE ,
806+ ( delta , oldDelta , source ) => {
807+ // When format is applied via toolbar (source === 'api'), update refs
808+ if ( source === 'api' ) {
809+ const range = quill . getSelection ( true ) ;
810+ if ( range ) {
811+ const f = quill . getFormat ( range ) ;
812+ if ( f . size ) lastFontSize . current = f . size ;
813+ if ( f . font ) lastFont . current = f . font ;
814+ }
815+ }
816+ }
817+ ) ;
818+
729819 quill . on (
730820 Quill . events . TEXT_CHANGE ,
731821 ( delta , oldDelta , source ) => {
732822 if ( source !== 'user' ) return ;
733823
734824 let index = 0 ;
825+ let hasDeletion = false ;
735826
736827 delta . ops ?. forEach ( ( op ) => {
737828 if ( typeof op . insert === 'string' ) {
@@ -788,8 +879,23 @@ const Editor = forwardRef<any, RichTextEditorProps>(
788879 index += text . length ;
789880 } else if ( typeof op . retain === 'number' ) {
790881 index += op . retain ;
882+ } else if ( typeof op . delete === 'number' ) {
883+ hasDeletion = true ;
791884 }
792885 } ) ;
886+
887+ // After deletions, update lastFont and lastFontSize to match current cursor format
888+ if ( hasDeletion ) {
889+ const range = quill . getSelection ( true ) ;
890+ if ( range ) {
891+ const currentFormat = quill . getFormat ( range ) ;
892+ // Update font and size- use current format or default to last set values
893+ lastFont . current =
894+ currentFormat . font || lastFont . current ;
895+ lastFontSize . current =
896+ currentFormat . size || lastFontSize . current ;
897+ }
898+ }
793899 }
794900 ) ;
795901 } ) ( ) ;
0 commit comments