@@ -144,60 +144,63 @@ export const ShimmerText = ({
144144 const chars = text . split ( '' )
145145 const numChars = chars . length
146146
147+ if ( numChars === 0 ) {
148+ return null
149+ }
150+
147151 useEffect ( ( ) => {
152+ if ( numChars === 0 ) {
153+ return
154+ }
148155 const pulseInterval = setInterval ( ( ) => {
149156 setPulse ( ( prev ) => ( prev + 1 ) % numChars )
150157 } , interval )
151158
152159 return ( ) => clearInterval ( pulseInterval )
153160 } , [ interval , numChars ] )
154161
155- const generateColors = ( length : number , colorPalette : string [ ] ) : string [ ] => {
162+ const generateColors = ( length : number , palette : string [ ] ) : string [ ] => {
156163 if ( length === 0 ) return [ ]
157- if ( colorPalette . length === 0 ) {
164+ if ( palette . length === 0 ) {
158165 return Array . from ( { length } , ( ) => theme . muted )
159166 }
160- if ( colorPalette . length === 1 ) {
161- return Array . from ( { length } , ( ) => colorPalette [ 0 ] )
167+ if ( palette . length === 1 ) {
168+ return Array . from ( { length } , ( ) => palette [ 0 ] )
162169 }
163- const generatedColors : string [ ] = [ ]
170+ const generated : string [ ] = [ ]
164171 for ( let i = 0 ; i < length ; i ++ ) {
165172 const ratio = length === 1 ? 0 : i / ( length - 1 )
166173 const colorIndex = Math . min (
167- colorPalette . length - 1 ,
168- Math . floor ( ratio * ( colorPalette . length - 1 ) ) ,
174+ palette . length - 1 ,
175+ Math . floor ( ratio * ( palette . length - 1 ) ) ,
169176 )
170- generatedColors . push ( colorPalette [ colorIndex ] )
177+ generated . push ( palette [ colorIndex ] )
171178 }
172- return generatedColors
179+ return generated
173180 }
174181
175182 const palette = useMemo ( ( ) => {
176183 if ( colors && colors . length > 0 ) {
177184 return colors
178185 }
179- if ( primaryColor ) {
180- const paletteSize = Math . max ( 8 , Math . min ( 20 , Math . ceil ( numChars * 1.5 ) ) )
181- return generatePaletteFromPrimary ( primaryColor , paletteSize , theme . muted )
182- }
183- // Use theme shimmer color as default
184186 const paletteSize = Math . max ( 8 , Math . min ( 20 , Math . ceil ( numChars * 1.5 ) ) )
185- return generatePaletteFromPrimary ( theme . info , paletteSize , theme . muted )
187+ const seedColor = primaryColor ?? theme . info
188+ return generatePaletteFromPrimary ( seedColor , paletteSize , theme . muted )
186189 } , [ colors , primaryColor , numChars , theme . info , theme . muted ] )
187190
188191 const generateAttributes = ( length : number ) : number [ ] => {
189- const attributes : number [ ] = [ ]
192+ const attrs : number [ ] = [ ]
190193 for ( let i = 0 ; i < length ; i ++ ) {
191194 const ratio = length <= 1 ? 0 : i / ( length - 1 )
192195 if ( ratio < 0.23 ) {
193- attributes . push ( TextAttributes . BOLD )
196+ attrs . push ( TextAttributes . BOLD )
194197 } else if ( ratio < 0.69 ) {
195- attributes . push ( TextAttributes . NONE )
198+ attrs . push ( TextAttributes . NONE )
196199 } else {
197- attributes . push ( TextAttributes . DIM )
200+ attrs . push ( TextAttributes . DIM )
198201 }
199202 }
200- return attributes
203+ return attrs
201204 }
202205
203206 const generatedColors = useMemo (
@@ -207,39 +210,48 @@ export const ShimmerText = ({
207210 const attributes = useMemo ( ( ) => generateAttributes ( numChars ) , [ numChars ] )
208211
209212 const parts : { text : string ; color : string ; attr : number } [ ] = [ ]
210- let currentColor = generatedColors [ 0 ]
211- let currentAttr = attributes [ 0 ]
212- let currentText = ''
213+ let currentColor : string | undefined
214+ let currentAttr : number | undefined
215+ let buffer = ''
213216
214217 chars . forEach ( ( char , index ) => {
215218 const phase = ( pulse - index + numChars ) % numChars
216- const charColor = generatedColors [ phase ]
217- const charAttr = attributes [ phase ]
219+ const charColor = generatedColors [ phase ] ?? theme . muted
220+ const charAttr = attributes [ phase ] ?? TextAttributes . NONE
221+
222+ if ( currentColor === undefined ) {
223+ currentColor = charColor
224+ currentAttr = charAttr
225+ }
218226
219227 if ( charColor === currentColor && charAttr === currentAttr ) {
220- currentText += char
228+ buffer += char
221229 } else {
222- if ( currentText ) {
230+ if ( buffer ) {
223231 parts . push ( {
224- text : currentText ,
225- color : currentColor ,
226- attr : currentAttr ,
232+ text : buffer ,
233+ color : currentColor ?? theme . muted ,
234+ attr : currentAttr ?? TextAttributes . NONE ,
227235 } )
228236 }
229- currentText = char
237+ buffer = char
230238 currentColor = charColor
231239 currentAttr = charAttr
232240 }
233241 } )
234242
235- if ( currentText ) {
236- parts . push ( { text : currentText , color : currentColor , attr : currentAttr } )
243+ if ( buffer ) {
244+ parts . push ( {
245+ text : buffer ,
246+ color : currentColor ?? theme . muted ,
247+ attr : currentAttr ?? TextAttributes . NONE ,
248+ } )
237249 }
238250
239251 return (
240252 < >
241253 { parts . map ( ( part , index ) => (
242- < span key = { index } fg = { part . color } attributes = { part . attr } >
254+ < span key = { ` ${ part . color } - ${ index } ` } fg = { part . color } attributes = { part . attr } >
243255 { part . text }
244256 </ span >
245257 ) ) }
0 commit comments