@@ -6,7 +6,6 @@ function toArray(e, parent) {
66
77const NBSP = String . fromCharCode ( 160 ) ;
88const NNBSP = String . fromCharCode ( 8239 ) ;
9- const NBSPACES = [ NBSP , NNBSP ] ;
109const SPACES = [ ' ' , NBSP , NNBSP ] ;
1110const BLOCK_TAGS = [ 'DIV' , 'H1' , 'H2' , 'H3' , 'H4' , 'H5' , 'H6' , 'P' , 'UL' , 'OL' , 'LI' ] ;
1211
@@ -60,6 +59,8 @@ export default class SplitText {
6059 const byChars = ~ by . indexOf ( 'chars' ) ;
6160
6261 this . elements . forEach ( ( element , i ) => {
62+ element . __isParent = true ;
63+
6364 this . originals [ i ] = element . innerHTML . trim ( ) ;
6465
6566 // replace all zero width space with <wbr>
@@ -98,20 +99,32 @@ export default class SplitText {
9899 }
99100
100101 if ( ! this . options . noAriaLabel ) {
101- const blockTags = toArray ( element . childNodes ) . filter ( ( child ) => BLOCK_TAGS . includes ( child . tagName ) ) ;
102- if ( blockTags . length ) {
103- blockTags . forEach ( ( child ) => {
104- this . createAriaLabel ( child ) ;
105- } ) ;
106- } else {
107- element . appendChild ( this . createAriaLabel ( element ) ) ;
108- }
102+ this . recursiveAriaLabel ( element ) ;
103+
104+ // Handle A tags
105+ const aTags = toArray ( element . getElementsByTagName ( 'A' ) ) ;
106+ aTags . forEach ( ( aTag ) => {
107+ if ( ! aTag . getAttribute ( 'aria-label' ) ) {
108+ aTag . setAttribute ( 'aria-label' , aTag . textContent ) ;
109+ }
110+ } ) ;
109111 }
110112 } ) ;
111113
112114 this . isSplit = true ;
113115 }
114116
117+ recursiveAriaLabel ( element ) {
118+ const blockTags = toArray ( element . childNodes ) . filter ( ( child ) => BLOCK_TAGS . includes ( child . tagName ) ) ;
119+ if ( blockTags . length ) {
120+ blockTags . forEach ( ( child ) => {
121+ this . recursiveAriaLabel ( child ) ;
122+ } ) ;
123+ } else {
124+ this . createAriaLabel ( element ) ;
125+ }
126+ }
127+
115128 createAriaLabel ( element ) {
116129 const span = document . createElement ( 'span' ) ;
117130 span . classList . add ( 'sr-only' ) ;
@@ -160,11 +173,20 @@ export default class SplitText {
160173 this . isSplit = false ;
161174 }
162175
163- recursiveBalance ( e , lineParents ) {
176+ recursiveBalance ( e ) {
164177 e . normalize ( ) ;
165178 toArray ( e . childNodes ) . forEach ( ( next ) => {
166179 next . normalize ( ) ;
167- next . __lineParent = next . tagName && next . hasChildNodes ( ) && BLOCK_TAGS . includes ( next . tagName ) ;
180+ next . __lineParent = Boolean ( next . tagName && next . hasChildNodes ( ) && BLOCK_TAGS . includes ( next . tagName ) ) ;
181+ if ( next . __lineParent && e ?. __lineParent && ! e . __isParent ) {
182+ e . __lineParent = false ;
183+ }
184+ this . recursiveBalance ( next ) ;
185+ } ) ;
186+ }
187+
188+ recursiveCheckLineParent ( e , lineParents ) {
189+ toArray ( e . childNodes ) . forEach ( ( next ) => {
168190 if ( next . __lineParent ) {
169191 next . __idx = null ;
170192 // check if the __lineParent element has a valid text node to split
@@ -173,15 +195,17 @@ export default class SplitText {
173195 lineParents . push ( next ) ;
174196 }
175197 }
176- this . recursiveBalance ( next , lineParents ) ;
198+ this . recursiveCheckLineParent ( next , lineParents ) ;
177199 } ) ;
178200 }
179201
180202 balance ( el ) {
181203 // save all line parents
182204 this . lineParents = [ ] ;
183205
184- this . recursiveBalance ( el , this . lineParents ) ;
206+ this . recursiveBalance ( el ) ;
207+
208+ this . recursiveCheckLineParent ( el , this . lineParents ) ;
185209
186210 let useParent = true ;
187211 if ( ! this . lineParents . length ) {
@@ -300,13 +324,20 @@ export default class SplitText {
300324 }
301325
302326 handleRawElement ( parentEl , el , key , splitOn , preserveWhitespace , elements , allElements ) {
303- // Get the text to split, trimming out the whitespace
327+ // Get the text to split
304328 const wholeText = el . wholeText || '' ;
305- let contents = wholeText . trim ( ) ;
329+ let contents = wholeText ;
306330
307- // If there's no text left after trimming whitespace, continue the loop
308- if ( contents . length ) {
309- // insert leading space if there was one and preserve
331+ // If there's no text after removing all whitespace, preserve the original whitespace
332+ if ( ! contents . trim ( ) . length ) {
333+ allElements . push ( document . createTextNode ( wholeText ) ) ;
334+ return ;
335+ }
336+
337+ // If we're splitting into words/chars, trim the content but preserve spaces
338+ if ( key === 'word' || key === 'char' ) {
339+ contents = wholeText . trim ( ) ;
340+ // Preserve leading whitespace
310341 if ( SPACES . includes ( wholeText [ 0 ] ) ) {
311342 allElements . push ( document . createTextNode ( wholeText [ 0 ] ) ) ;
312343 }
@@ -371,31 +402,19 @@ export default class SplitText {
371402 allElements . push ( splitEl ) ;
372403 } ) ;
373404 } else {
374- const words = contents . split ( splitOn ) ;
375- let i = 0 ,
376- splitText ;
377-
378- const recursiveSupportNBSpaces = ( ) => {
379- if ( key === 'char' ) return ;
380- let matched = false ;
381- const charAt = contents . charAt ( contents . indexOf ( splitText ) + splitText . length ) ;
382- const space = NBSPACES . find ( ( s ) => s === charAt ) ;
383- if ( space ) {
384- splitText = splitText . concat ( space ) . concat ( words [ ++ i ] ) ;
385- matched = true ;
405+ // Split content preserving all whitespace
406+ const parts = contents . split ( / ( [ \s \u00A0 \u202F ] + ) / ) ;
407+ parts . forEach ( ( part , i ) => {
408+ if ( i % 2 === 1 ) {
409+ // Odd indices are whitespace - preserve them exactly
410+ allElements . push ( document . createTextNode ( part ) ) ;
411+ } else if ( part ) {
412+ // Even indices are words - process them
413+ const splitEl = this . createElement ( parentEl , key , part ) ;
414+ elements . push ( splitEl ) ;
415+ allElements . push ( splitEl ) ;
386416 }
387- contents = contents . substring ( contents . indexOf ( splitText ) ) ;
388- if ( matched ) return recursiveSupportNBSpaces ( ) ;
389- } ;
390-
391- for ( ; i < words . length ; i ++ ) {
392- splitText = words [ i ] ;
393- if ( i && preserveWhitespace ) allElements . push ( document . createTextNode ( ' ' ) ) ;
394- recursiveSupportNBSpaces ( ) ;
395- const splitEl = this . createElement ( parentEl , key , splitText ) ;
396- elements . push ( splitEl ) ;
397- allElements . push ( splitEl ) ;
398- }
417+ } ) ;
399418 }
400419 }
401420
@@ -482,8 +501,9 @@ export default class SplitText {
482501 } ) ;
483502
484503 let globalLineIndex = 0 ;
485- this . lineParents . forEach ( ( lp ) => {
504+ this . lineParents . forEach ( ( lp , i ) => {
486505 let lineIndex = 0 ;
506+ if ( i > 0 ) globalLineIndex ++ ;
487507 toArray ( lp . childNodes ) . forEach ( ( next ) => {
488508 if ( next . tagName === 'BR' ) {
489509 globalLineIndex ++ ;
@@ -511,7 +531,7 @@ export default class SplitText {
511531 const line = document . createElement ( 'span' ) ;
512532 line . style . setProperty ( 'display' , 'block' ) ;
513533 line . className = 'line' ;
514- line . setAttribute ( 'aria-hidden' , true ) ;
534+ // line.setAttribute('aria-hidden', true);
515535 return parent ? parent . appendChild ( line ) : line ;
516536 }
517537
0 commit comments