import React , { useState , useEffect } from 'react' ; import { Box , useInput , Key } from 'ink' ; import { Entry } from '../../search-api' ; import { useStore , Item , returnedValue } from '../../store-provider' ; import { ui_page_size } from '../app-config.json' ; import { SelectInputItem } from './SelectInput' ; import ListItem from './ListItem' ; import ExpandableListItem from './ExpandableListItem' ; export type ListEntry = { idx : number ; data : Entry ; } ; type Props = { entries : ListEntry [ ] ; options : SelectInputItem [ ] ; pageSize : number ; generateSelectInputItems : ( inBulkQueue : boolean , inDownloadQueue : boolean ) => SelectInputItem [ ] ; handleOnSelect : ( expanded : boolean , setExpanded : Function , entryData : Entry | null , returnedValue : returnedValue ) => void ; } ; const List = ( props ) => { const { entries , options , pageSize , generateSelectInputItems , handleOnSelect } = props ; const [ expanded , setExpanded ] = useState < boolean > ( false ) ; const [ input , setInput ] = useState ( false ) ; const currentPage = useStore ( state => state . globals . currentPage ) ; const bulkQueue = useStore ( state => state . globals . bulkQueue ) ; const downloadQueue = useStore ( state => state . globals . downloadQueue ) ; const listBuffer = useStore ( state => state . globals . listBuffer ) ; const setListBuffer = useStore ( state => state . set . listBuffer ) ; useEffect ( ( ) => { setInput ( true ) ; ( ) => setInput ( false ) ; } , [ ] ) ; useEffect ( ( ) => { if ( listBuffer . length == 0 ) { const entryItems = entries . map ( ( entry ) => { const idx = entry . idx + 1 + ( currentPage - 1 ) * pageSize ; const extension = entry . data . extension ; const title = entry . data . title ; let text = `[${ idx }] [${ extension }] ${ title }` ; return { key : entry . data . id , data : entry . data , text , expandable : true , value : null } ; } ) ; const optionItems = options . filter ( ( option ) => ! option . disabled ) . map ( ( option , i ) => ( { key : `option${ i }` , text : option . label , value : option . value , expandable : false , data : null } ) ) ; const pool = [ ... optionItems , ... entryItems ] ; const renderListLength = pool . length > ui_page_size ? ui_page_size : pool . length ; setListBuffer ( [ ... pool . slice ( pool . length - Math . floor ( renderListLength / 3 ) , pool . length ) , ... pool . slice ( 0 , pool . length - Math . floor ( renderListLength / 3 ) ) ] ) ; } } , [ entries ] ) ; const renderList = listBuffer . slice ( 0 , ui_page_size ) ; useInput ( ( _ , key ) => { if ( ! expanded ) { if ( key . upArrow ) { const lastEntry = listBuffer . pop ( ) ; if ( lastEntry ) { listBuffer . unshift ( lastEntry ) ; setListBuffer ( [ ... listBuffer ] ) ; } } if ( key . downArrow ) { const firstEntry = listBuffer . shift ( ) ; if ( firstEntry ) { listBuffer . push ( firstEntry ) ; setListBuffer ( [ ... listBuffer ] ) ; } } if ( renderList [ Math . floor ( renderList . length / 3 ) ] . expandable && key . return ) { setExpanded ( ! expanded ) ; } } } , { isActive : input } ) ; return ( < Box flexDirection = 'column' borderStyle = 'round' borderColor = 'grey' width = '100%' paddingLeft = { 1 } paddingRight = { 1 } > < Box width = '100%' flexDirection = 'column' > { renderList . map ( ( item , i ) => { const itemHovered = i == Math . floor ( renderList . length / 3 ) ; const itemExpanded = expanded && itemHovered ; const itemFadedOut = expanded && ! itemHovered ; const itemChecked = item . data ?. id ? bulkQueue . indexOf ( item . data ?. id ) > - 1 : false ; const itemInDownloadQueue = item . data ? downloadQueue . indexOf ( item . data ) > - 1 : false ; const selectInputItems = generateSelectInputItems ( itemChecked , itemInDownloadQueue ) ; if ( ! expanded || i + selectInputItems . length < ui_page_size ) { if ( item . expandable && item . data ) { return < ExpandableListItem key = { item . key } selectInputItems = { selectInputItems } hovered = { itemHovered } expanded = { itemExpanded } fadedOut = { itemFadedOut } checked = { itemChecked } downloading = { itemInDownloadQueue } onSelect = { ( returned ) => handleOnSelect ( expanded , setExpanded , item . data , returned ) } > { item . text } < /ExpandableListItem>; } if ( ! item . expandable && item . value ) { return < ListItem key = { item . key } value = { item . value } hovered = { itemHovered } fadedOut = { itemFadedOut } onSelect = { ( returned ) => handleOnSelect ( expanded , setExpanded , null , returned ) } > { item . text } < /ListItem>; } } return null ; } ) } < /Box> < /Box>); } ; export default List ;