@@ -178,6 +178,7 @@ export interface SelectOptions<Options extends Option<Value>[], Value> {
178178 message : string ;
179179 options : Options ;
180180 initialValue ?: Value ;
181+ maxItems ?: number ;
181182}
182183
183184export const select = < Options extends Option < Value > [ ] , Value > (
@@ -197,6 +198,8 @@ export const select = <Options extends Option<Value>[], Value>(
197198 return `${ color . dim ( S_RADIO_INACTIVE ) } ${ color . dim ( label ) } ` ;
198199 } ;
199200
201+ let slidingWindowLocation = 0 ;
202+
200203 return new SelectPrompt ( {
201204 options : opts . options ,
202205 initialValue : opts . initialValue ,
@@ -212,8 +215,37 @@ export const select = <Options extends Option<Value>[], Value>(
212215 'cancelled'
213216 ) } \n${ color . gray ( S_BAR ) } `;
214217 default : {
218+ // We clamp to minimum 5 because anything less doesn't make sense UX wise
219+ const maxItems = opts . maxItems === undefined ? Infinity : Math . max ( opts . maxItems , 5 ) ;
220+ if ( this . cursor >= slidingWindowLocation + maxItems - 3 ) {
221+ slidingWindowLocation = Math . max (
222+ Math . min ( this . cursor - maxItems + 3 , this . options . length - maxItems ) ,
223+ 0
224+ ) ;
225+ } else if ( this . cursor < slidingWindowLocation + 2 ) {
226+ slidingWindowLocation = Math . max ( this . cursor - 2 , 0 ) ;
227+ }
228+
229+ const shouldRenderTopEllipsis =
230+ maxItems < this . options . length && slidingWindowLocation > 0 ;
231+ const shouldRenderBottomEllipsis =
232+ maxItems < this . options . length &&
233+ slidingWindowLocation + maxItems < this . options . length ;
234+
215235 return `${ title } ${ color . cyan ( S_BAR ) } ${ this . options
216- . map ( ( option , i ) => opt ( option , i === this . cursor ? 'active' : 'inactive' ) )
236+ . slice ( slidingWindowLocation , slidingWindowLocation + maxItems )
237+ . map ( ( option , i , arr ) => {
238+ if ( i === 0 && shouldRenderTopEllipsis ) {
239+ return color . dim ( '...' ) ;
240+ } else if ( i === arr . length - 1 && shouldRenderBottomEllipsis ) {
241+ return color . dim ( '...' ) ;
242+ } else {
243+ return opt (
244+ option ,
245+ i + slidingWindowLocation === this . cursor ? 'active' : 'inactive'
246+ ) ;
247+ }
248+ } )
217249 . join ( `\n${ color . cyan ( S_BAR ) } ` ) } \n${ color . cyan ( S_BAR_END ) } \n`;
218250 }
219251 }
0 commit comments