@@ -28,15 +28,24 @@ export const parseTextBounds = (
2828 textList . forEach ( ( text ) => {
2929 if ( styles . textDecorationLine . length || text . trim ( ) . length > 0 ) {
3030 if ( FEATURES . SUPPORT_RANGE_BOUNDS ) {
31- if ( ! FEATURES . SUPPORT_WORD_BREAKING ) {
32- textBounds . push (
33- new TextBounds (
34- text ,
35- Bounds . fromDOMRectList ( context , createRange ( node , offset , text . length ) . getClientRects ( ) )
36- )
37- ) ;
31+ const clientRects = createRange ( node , offset , text . length ) . getClientRects ( ) ;
32+ if ( clientRects . length > 1 ) {
33+ const subSegments = segmentGraphemes ( text ) ;
34+ let subOffset = 0 ;
35+ subSegments . forEach ( ( subSegment ) => {
36+ textBounds . push (
37+ new TextBounds (
38+ subSegment ,
39+ Bounds . fromDOMRectList (
40+ context ,
41+ createRange ( node , subOffset + offset , subSegment . length ) . getClientRects ( )
42+ )
43+ )
44+ ) ;
45+ subOffset += subSegment . length ;
46+ } ) ;
3847 } else {
39- textBounds . push ( new TextBounds ( text , getRangeBounds ( context , node , offset , text . length ) ) ) ;
48+ textBounds . push ( new TextBounds ( text , Bounds . fromDOMRectList ( context , clientRects ) ) ) ;
4049 }
4150 } else {
4251 const replacementNode = node . splitText ( text . length ) ;
@@ -82,12 +91,32 @@ const createRange = (node: Text, offset: number, length: number): Range => {
8291 return range ;
8392} ;
8493
85- const getRangeBounds = ( context : Context , node : Text , offset : number , length : number ) : Bounds => {
86- return Bounds . fromClientRect ( context , createRange ( node , offset , length ) . getBoundingClientRect ( ) ) ;
94+ export const segmentGraphemes = ( value : string ) : string [ ] => {
95+ if ( FEATURES . SUPPORT_NATIVE_TEXT_SEGMENTATION ) {
96+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
97+ const segmenter = new ( Intl as any ) . Segmenter ( void 0 , { granularity : 'grapheme' } ) ;
98+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99+ return Array . from ( segmenter . segment ( value ) ) . map ( ( segment : any ) => segment . segment ) ;
100+ }
101+
102+ return splitGraphemes ( value ) ;
103+ } ;
104+
105+ const segmentWords = ( value : string , styles : CSSParsedDeclaration ) : string [ ] => {
106+ if ( FEATURES . SUPPORT_NATIVE_TEXT_SEGMENTATION ) {
107+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
108+ const segmenter = new ( Intl as any ) . Segmenter ( void 0 , {
109+ granularity : 'word'
110+ } ) ;
111+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112+ return Array . from ( segmenter . segment ( value ) ) . map ( ( segment : any ) => segment . segment ) ;
113+ }
114+
115+ return breakWords ( value , styles ) ;
87116} ;
88117
89118const breakText = ( value : string , styles : CSSParsedDeclaration ) : string [ ] => {
90- return styles . letterSpacing !== 0 ? splitGraphemes ( value ) : breakWords ( value , styles ) ;
119+ return styles . letterSpacing !== 0 ? segmentGraphemes ( value ) : segmentWords ( value , styles ) ;
91120} ;
92121
93122// https://drafts.csswg.org/css-text/#word-separator
0 commit comments