1*89d2c67fSBartosz Kaszubowskiimport { SearchIcon, theme, XIcon } from '@expo/styleguide'; 2*89d2c67fSBartosz Kaszubowskiimport { Command } from 'cmdk'; 3*89d2c67fSBartosz Kaszubowskiimport { useEffect, useState } from 'react'; 4*89d2c67fSBartosz Kaszubowskiimport type { Dispatch, SetStateAction } from 'react'; 5*89d2c67fSBartosz Kaszubowski 6*89d2c67fSBartosz Kaszubowskiimport { BarLoader } from './BarLoader'; 7*89d2c67fSBartosz Kaszubowskiimport { CommandFooter } from './CommandFooter'; 8*89d2c67fSBartosz Kaszubowskiimport { RNDirectoryItem, RNDocsItem, ExpoDocsItem, ExpoItem } from './Items'; 9*89d2c67fSBartosz Kaszubowskiimport { entries } from './expoEntries'; 10*89d2c67fSBartosz Kaszubowskiimport { searchIconStyle, closeIconStyle } from './styles'; 11*89d2c67fSBartosz Kaszubowskiimport type { ExpoItemType, RNDirectoryItemType, AlgoliaItemType } from './types'; 12*89d2c67fSBartosz Kaszubowskiimport { getExpoDocsResults, getRNDocsResults, getDirectoryResults, getItemsAsync } from './utils'; 13*89d2c67fSBartosz Kaszubowski 14*89d2c67fSBartosz Kaszubowskiimport { CALLOUT } from '~/ui/components/Text'; 15*89d2c67fSBartosz Kaszubowski 16*89d2c67fSBartosz Kaszubowskitype Props = { 17*89d2c67fSBartosz Kaszubowski version: string; 18*89d2c67fSBartosz Kaszubowski open: boolean; 19*89d2c67fSBartosz Kaszubowski setOpen: Dispatch<SetStateAction<boolean>>; 20*89d2c67fSBartosz Kaszubowski}; 21*89d2c67fSBartosz Kaszubowski 22*89d2c67fSBartosz Kaszubowskiexport const CommandMenu = ({ version, open, setOpen }: Props) => { 23*89d2c67fSBartosz Kaszubowski const [loading, setLoading] = useState(false); 24*89d2c67fSBartosz Kaszubowski const [query, setQuery] = useState(''); 25*89d2c67fSBartosz Kaszubowski const [expoDocsItems, setExpoDocsItems] = useState<AlgoliaItemType[]>([]); 26*89d2c67fSBartosz Kaszubowski const [expoItems, setExpoItems] = useState<ExpoItemType[]>([]); 27*89d2c67fSBartosz Kaszubowski const [rnDocsItems, setRnDocsItems] = useState<AlgoliaItemType[]>([]); 28*89d2c67fSBartosz Kaszubowski const [directoryItems, setDirectoryItems] = useState<RNDirectoryItemType[]>([]); 29*89d2c67fSBartosz Kaszubowski 30*89d2c67fSBartosz Kaszubowski const getExpoDocsItems = async () => 31*89d2c67fSBartosz Kaszubowski getItemsAsync(query, getExpoDocsResults, setExpoDocsItems, version); 32*89d2c67fSBartosz Kaszubowski const getRNDocsItems = async () => getItemsAsync(query, getRNDocsResults, setRnDocsItems); 33*89d2c67fSBartosz Kaszubowski const getDirectoryItems = async () => 34*89d2c67fSBartosz Kaszubowski getItemsAsync(query, getDirectoryResults, setDirectoryItems); 35*89d2c67fSBartosz Kaszubowski 36*89d2c67fSBartosz Kaszubowski const getExpoItems = async () => { 37*89d2c67fSBartosz Kaszubowski setExpoItems(entries.filter(entry => entry.label.toLowerCase().includes(query.toLowerCase()))); 38*89d2c67fSBartosz Kaszubowski }; 39*89d2c67fSBartosz Kaszubowski 40*89d2c67fSBartosz Kaszubowski const dismiss = () => setOpen(false); 41*89d2c67fSBartosz Kaszubowski 42*89d2c67fSBartosz Kaszubowski const fetchData = () => { 43*89d2c67fSBartosz Kaszubowski Promise.all([getExpoDocsItems(), getRNDocsItems(), getDirectoryItems(), getExpoItems()]).then( 44*89d2c67fSBartosz Kaszubowski () => setLoading(false) 45*89d2c67fSBartosz Kaszubowski ); 46*89d2c67fSBartosz Kaszubowski }; 47*89d2c67fSBartosz Kaszubowski 48*89d2c67fSBartosz Kaszubowski const onQueryChange = () => { 49*89d2c67fSBartosz Kaszubowski setLoading(true); 50*89d2c67fSBartosz Kaszubowski const inputTimeout = setTimeout(fetchData, 150); 51*89d2c67fSBartosz Kaszubowski return () => clearTimeout(inputTimeout); 52*89d2c67fSBartosz Kaszubowski }; 53*89d2c67fSBartosz Kaszubowski 54*89d2c67fSBartosz Kaszubowski useEffect(onQueryChange, [query]); 55*89d2c67fSBartosz Kaszubowski 56*89d2c67fSBartosz Kaszubowski const totalCount = 57*89d2c67fSBartosz Kaszubowski expoDocsItems.length + rnDocsItems.length + directoryItems.length + expoItems.length; 58*89d2c67fSBartosz Kaszubowski 59*89d2c67fSBartosz Kaszubowski return ( 60*89d2c67fSBartosz Kaszubowski <Command.Dialog open={open} onOpenChange={setOpen} label="Search Menu" shouldFilter={false}> 61*89d2c67fSBartosz Kaszubowski <SearchIcon color={theme.icon.secondary} css={searchIconStyle} /> 62*89d2c67fSBartosz Kaszubowski <XIcon color={theme.icon.secondary} css={closeIconStyle} onClick={() => setOpen(false)} /> 63*89d2c67fSBartosz Kaszubowski <Command.Input value={query} onValueChange={setQuery} placeholder="search anything…" /> 64*89d2c67fSBartosz Kaszubowski <BarLoader isLoading={loading} /> 65*89d2c67fSBartosz Kaszubowski <Command.List> 66*89d2c67fSBartosz Kaszubowski {expoDocsItems.length > 0 && ( 67*89d2c67fSBartosz Kaszubowski <Command.Group heading="Expo documentation"> 68*89d2c67fSBartosz Kaszubowski {expoDocsItems.map(item => ( 69*89d2c67fSBartosz Kaszubowski <ExpoDocsItem item={item} onSelect={dismiss} key={`hit-expo-docs-${item.objectID}`} /> 70*89d2c67fSBartosz Kaszubowski ))} 71*89d2c67fSBartosz Kaszubowski </Command.Group> 72*89d2c67fSBartosz Kaszubowski )} 73*89d2c67fSBartosz Kaszubowski {expoItems.length > 0 && ( 74*89d2c67fSBartosz Kaszubowski <Command.Group heading="Expo dashboard"> 75*89d2c67fSBartosz Kaszubowski {expoItems.map((item: ExpoItemType) => ( 76*89d2c67fSBartosz Kaszubowski <ExpoItem item={item} onSelect={dismiss} key={`hit-expo-${item.url}`} query={query} /> 77*89d2c67fSBartosz Kaszubowski ))} 78*89d2c67fSBartosz Kaszubowski </Command.Group> 79*89d2c67fSBartosz Kaszubowski )} 80*89d2c67fSBartosz Kaszubowski {rnDocsItems.length > 0 && ( 81*89d2c67fSBartosz Kaszubowski <Command.Group heading="React Native documentation"> 82*89d2c67fSBartosz Kaszubowski {rnDocsItems.map(item => ( 83*89d2c67fSBartosz Kaszubowski <RNDocsItem item={item} onSelect={dismiss} key={`hit-rn-docs-${item.objectID}`} /> 84*89d2c67fSBartosz Kaszubowski ))} 85*89d2c67fSBartosz Kaszubowski </Command.Group> 86*89d2c67fSBartosz Kaszubowski )} 87*89d2c67fSBartosz Kaszubowski {directoryItems.length > 0 && ( 88*89d2c67fSBartosz Kaszubowski <Command.Group heading="React Native directory"> 89*89d2c67fSBartosz Kaszubowski {directoryItems.map(item => ( 90*89d2c67fSBartosz Kaszubowski <RNDirectoryItem 91*89d2c67fSBartosz Kaszubowski item={item} 92*89d2c67fSBartosz Kaszubowski onSelect={dismiss} 93*89d2c67fSBartosz Kaszubowski key={`hit-rn-dir-${item.npmPkg}`} 94*89d2c67fSBartosz Kaszubowski query={query} 95*89d2c67fSBartosz Kaszubowski /> 96*89d2c67fSBartosz Kaszubowski ))} 97*89d2c67fSBartosz Kaszubowski </Command.Group> 98*89d2c67fSBartosz Kaszubowski )} 99*89d2c67fSBartosz Kaszubowski {totalCount === 0 && ( 100*89d2c67fSBartosz Kaszubowski <Command.Empty> 101*89d2c67fSBartosz Kaszubowski <CALLOUT theme="secondary">No results found.</CALLOUT> 102*89d2c67fSBartosz Kaszubowski </Command.Empty> 103*89d2c67fSBartosz Kaszubowski )} 104*89d2c67fSBartosz Kaszubowski </Command.List> 105*89d2c67fSBartosz Kaszubowski <CommandFooter /> 106*89d2c67fSBartosz Kaszubowski </Command.Dialog> 107*89d2c67fSBartosz Kaszubowski ); 108*89d2c67fSBartosz Kaszubowski}; 109