1- import React , { useState , useEffect } from 'react' ;
1+ import React , { useEffect , useMemo , useState } from 'react' ;
22import clsx from 'clsx' ;
33import styles from './styles.module.css' ;
44
@@ -13,6 +13,7 @@ export default function Typewriter({
1313 prefix = '' ,
1414 values = [ ] ,
1515 highlightClassName = '' ,
16+ reservePairs,
1617} ) {
1718 const [ phase , setPhase ] = useState ( 'typing-prefix' ) ;
1819 // Phases:
@@ -128,25 +129,55 @@ export default function Typewriter({
128129 phase === 'paused-before-type' ||
129130 ( phase === 'typing-value' && displayedValue . length === 0 ) ; // Blink while waiting to start typing value
130131
132+ const reserveVariants = useMemo (
133+ ( ) =>
134+ ( reservePairs ?? [ [ prefix , values ] ] ) . flatMap (
135+ ( [ reservePrefix , reserveValues ] ) =>
136+ ( reserveValues . length ? reserveValues : [ '' ] ) . map ( reserveValue => ( {
137+ prefix : reservePrefix ,
138+ value : reserveValue ,
139+ } ) ) ,
140+ ) ,
141+ [ reservePairs , prefix , values ] ,
142+ ) ;
143+
131144 return (
132- < >
133- { displayedPrefix }
134- { showPrefixCursor && (
135- < span className = { clsx ( styles . cursor , { [ styles . blinking ] : false } ) } >
136- |
137- </ span >
138- ) }
139- < br />
140- < span className = { highlightClassName } >
141- { displayedValue }
142- { showValueCursor && (
145+ < span className = { styles . typewriter } >
146+ < span className = { styles . sizer } aria-hidden = "true" >
147+ { reserveVariants . map ( ( { prefix : variantPrefix , value } , index ) => (
143148 < span
144- className = { clsx ( styles . cursor , { [ styles . blinking ] : isBlinking } ) }
149+ className = { styles . sizerVariant }
150+ key = { `${ variantPrefix } -${ value } -${ index } ` }
145151 >
146- |
152+ { variantPrefix }
153+ < span className = { styles . cursor } > |</ span >
154+ < span className = { styles . breakPoint } />
155+ < span className = { highlightClassName } >
156+ { value }
157+ < span className = { styles . cursor } > |</ span >
158+ </ span >
147159 </ span >
160+ ) ) }
161+ </ span >
162+ < span className = { styles . visibleText } >
163+ { displayedPrefix }
164+ { showPrefixCursor && < span className = { styles . cursor } > |</ span > }
165+ { showValueCursor && (
166+ < >
167+ < span className = { styles . breakPoint } />
168+ < span className = { highlightClassName } >
169+ { displayedValue }
170+ < span
171+ className = { clsx ( styles . cursor , {
172+ [ styles . blinking ] : isBlinking ,
173+ } ) }
174+ >
175+ |
176+ </ span >
177+ </ span >
178+ </ >
148179 ) }
149180 </ span >
150- </ >
181+ </ span >
151182 ) ;
152183}
0 commit comments