@@ -635,6 +635,182 @@ describe('blocksListWrapper', () => {
635635 expect ( block . styleId ) . toBe ( 'Heading1' ) ;
636636 expect ( block . headingLevel ) . toBe ( 1 ) ;
637637 } ) ;
638+
639+ it ( 'resolves fontSize from Normal style when inline marks have no fontSize' , ( ) => {
640+ const textNode = createNode ( 'text' , [ ] , {
641+ text : 'No inline fontSize' ,
642+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Times New Roman' } } ] ,
643+ } ) ;
644+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
645+ attrs : { paraId : 'p1' , sdBlockId : 'p1' } ,
646+ isBlock : true ,
647+ inlineContent : true ,
648+ } ) ;
649+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
650+ // Mock editor with converter that has translatedLinkedStyles
651+ const editor = {
652+ state : { doc } ,
653+ converter : {
654+ translatedLinkedStyles : {
655+ docDefaults : { runProperties : { fontSize : 24 } } ,
656+ latentStyles : { } ,
657+ styles : {
658+ Normal : { runProperties : { fontSize : 20 } } ,
659+ } ,
660+ } ,
661+ } ,
662+ } as unknown as Editor ;
663+
664+ const result = blocksListWrapper ( editor ) ;
665+ const block = result . blocks [ 0 ] as any ;
666+ // Normal style has fontSize 20 half-points = 10pt
667+ expect ( block . fontSize ) . toBe ( 10 ) ;
668+ } ) ;
669+
670+ it ( 'resolves fontSize from basedOn chain when block has a styleId' , ( ) => {
671+ const textNode = createNode ( 'text' , [ ] , {
672+ text : 'Heading text' ,
673+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Times New Roman' } } ] ,
674+ } ) ;
675+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
676+ attrs : { paraId : 'p1' , sdBlockId : 'p1' , paragraphProperties : { styleId : 'Heading1' } } ,
677+ isBlock : true ,
678+ inlineContent : true ,
679+ } ) ;
680+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
681+ const editor = {
682+ state : { doc } ,
683+ converter : {
684+ translatedLinkedStyles : {
685+ docDefaults : { runProperties : { fontSize : 20 } } ,
686+ latentStyles : { } ,
687+ styles : {
688+ Normal : { runProperties : { fontSize : 20 } } ,
689+ Heading1 : { basedOn : 'Normal' , runProperties : { fontSize : 28 } } ,
690+ } ,
691+ } ,
692+ } ,
693+ } as unknown as Editor ;
694+
695+ const result = blocksListWrapper ( editor ) ;
696+ const block = result . blocks [ 0 ] as any ;
697+ // Heading1 has fontSize 28 half-points = 14pt
698+ expect ( block . fontSize ) . toBe ( 14 ) ;
699+ } ) ;
700+
701+ it ( 'walks basedOn chain when style has no fontSize' , ( ) => {
702+ const textNode = createNode ( 'text' , [ ] , {
703+ text : 'List text' ,
704+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Arial' } } ] ,
705+ } ) ;
706+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
707+ attrs : { paraId : 'p1' , sdBlockId : 'p1' , paragraphProperties : { styleId : 'ListParagraph' } } ,
708+ isBlock : true ,
709+ inlineContent : true ,
710+ } ) ;
711+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
712+ const editor = {
713+ state : { doc } ,
714+ converter : {
715+ translatedLinkedStyles : {
716+ docDefaults : { } ,
717+ latentStyles : { } ,
718+ styles : {
719+ Normal : { runProperties : { fontSize : 22 } } ,
720+ ListParagraph : { basedOn : 'Normal' , runProperties : { } } ,
721+ } ,
722+ } ,
723+ } ,
724+ } as unknown as Editor ;
725+
726+ const result = blocksListWrapper ( editor ) ;
727+ const block = result . blocks [ 0 ] as any ;
728+ // ListParagraph has no fontSize, basedOn Normal which has 22 hp = 11pt
729+ expect ( block . fontSize ) . toBe ( 11 ) ;
730+ } ) ;
731+
732+ it ( 'falls back to docDefaults when no style defines fontSize' , ( ) => {
733+ const textNode = createNode ( 'text' , [ ] , {
734+ text : 'Default text' ,
735+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Calibri' } } ] ,
736+ } ) ;
737+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
738+ attrs : { paraId : 'p1' , sdBlockId : 'p1' } ,
739+ isBlock : true ,
740+ inlineContent : true ,
741+ } ) ;
742+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
743+ const editor = {
744+ state : { doc } ,
745+ converter : {
746+ translatedLinkedStyles : {
747+ docDefaults : { runProperties : { fontSize : 24 } } ,
748+ latentStyles : { } ,
749+ styles : { Normal : { runProperties : { } } } ,
750+ } ,
751+ } ,
752+ } as unknown as Editor ;
753+
754+ const result = blocksListWrapper ( editor ) ;
755+ const block = result . blocks [ 0 ] as any ;
756+ // docDefaults has fontSize 24 hp = 12pt
757+ expect ( block . fontSize ) . toBe ( 12 ) ;
758+ } ) ;
759+
760+ it ( 'falls back to 10pt OOXML default when nothing defines fontSize' , ( ) => {
761+ const textNode = createNode ( 'text' , [ ] , {
762+ text : 'Bare text' ,
763+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Courier' } } ] ,
764+ } ) ;
765+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
766+ attrs : { paraId : 'p1' , sdBlockId : 'p1' } ,
767+ isBlock : true ,
768+ inlineContent : true ,
769+ } ) ;
770+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
771+ const editor = {
772+ state : { doc } ,
773+ converter : {
774+ translatedLinkedStyles : {
775+ docDefaults : { } ,
776+ latentStyles : { } ,
777+ styles : { } ,
778+ } ,
779+ } ,
780+ } as unknown as Editor ;
781+
782+ const result = blocksListWrapper ( editor ) ;
783+ const block = result . blocks [ 0 ] as any ;
784+ expect ( block . fontSize ) . toBe ( 10 ) ;
785+ } ) ;
786+
787+ it ( 'inline fontSize takes precedence over style chain' , ( ) => {
788+ const textNode = createNode ( 'text' , [ ] , {
789+ text : 'Explicit size' ,
790+ marks : [ { type : { name : 'textStyle' } , attrs : { fontFamily : 'Arial' , fontSize : 16 } } ] ,
791+ } ) ;
792+ const paragraph = createNode ( 'paragraph' , [ textNode ] , {
793+ attrs : { paraId : 'p1' , sdBlockId : 'p1' , paragraphProperties : { styleId : 'Heading1' } } ,
794+ isBlock : true ,
795+ inlineContent : true ,
796+ } ) ;
797+ const doc = createNode ( 'doc' , [ paragraph ] , { isBlock : false } ) ;
798+ const editor = {
799+ state : { doc } ,
800+ converter : {
801+ translatedLinkedStyles : {
802+ docDefaults : { runProperties : { fontSize : 20 } } ,
803+ latentStyles : { } ,
804+ styles : { Heading1 : { runProperties : { fontSize : 28 } } } ,
805+ } ,
806+ } ,
807+ } as unknown as Editor ;
808+
809+ const result = blocksListWrapper ( editor ) ;
810+ const block = result . blocks [ 0 ] as any ;
811+ // Inline fontSize 16 takes precedence over Heading1's 28hp (14pt)
812+ expect ( block . fontSize ) . toBe ( 16 ) ;
813+ } ) ;
638814} ) ;
639815
640816// ---------------------------------------------------------------------------
0 commit comments