1import type { Dispatch, SetStateAction } from 'react'; 2 3import type { AlgoliaItemHierarchy, AlgoliaItemType } from './types'; 4 5export const getItemsAsync = async <T>( 6 query: string, 7 fetcher: (query: string, version?: string) => Promise<Response>, 8 setter: Dispatch<SetStateAction<T[]>>, 9 version?: string 10) => { 11 const { hits, libraries } = await fetcher(query, version).then(response => response.json()); 12 setter(hits || libraries || []); 13}; 14 15const getAlgoliaFetchParams = ( 16 query: string, 17 appId: string, 18 apiKey: string, 19 indexName: string, 20 hits: number, 21 additionalParams: object = {} 22): [string, RequestInit] => [ 23 `https://${appId}-dsn.algolia.net/1/indexes/${indexName}/query`, 24 { 25 method: 'POST', 26 headers: { 27 'X-Algolia-Application-Id': appId, 28 'X-Algolia-API-Key': apiKey, 29 }, 30 body: JSON.stringify({ 31 params: `query=${query}&hitsPerPage=${hits}`, 32 highlightPreTag: '<mark>', 33 highlightPostTag: '</mark>', 34 ...additionalParams, 35 }), 36 }, 37]; 38 39export const getExpoDocsResults = (query: string, version?: string) => { 40 return fetch( 41 ...getAlgoliaFetchParams(query, 'QEX7PB7D46', '6652d26570e8628af4601e1d78ad456b', 'expo', 10, { 42 facetFilters: [['version:none', `version:${version}`]], 43 }) 44 ); 45}; 46 47export const getRNDocsResults = (query: string) => { 48 return fetch( 49 ...getAlgoliaFetchParams( 50 query, 51 '8TDSE0OHGQ', 52 'c9c791d9d5fd7f315d7f3859b32c1f3b', 53 'react-native-v2', 54 5, 55 { facetFilters: [['version:current']] } 56 ) 57 ); 58}; 59 60export const getDirectoryResults = (query: string) => { 61 return fetch(`https://reactnative.directory/api/libraries?search=${encodeURI(query)}&limit=5`); 62}; 63 64export const getHighlightHTML = ( 65 item: AlgoliaItemType, 66 tag: keyof AlgoliaItemHierarchy<string> 67) => ({ 68 dangerouslySetInnerHTML: { 69 __html: item._highlightResult.hierarchy[`${tag}`]?.value || '', 70 }, 71}); 72 73const trimContent = (content: string) => { 74 if (!content || !content.length) return ''; 75 76 const trimStart = Math.max(content.indexOf('<mark>') - 36, 0); 77 const trimEnd = Math.min(content.indexOf('</mark>') + 36 + 6, content.length); 78 79 return `${trimStart !== 0 ? '…' : ''}${content.substring(trimStart, trimEnd).trim()}${ 80 trimEnd !== content.length ? '…' : '' 81 }`; 82}; 83 84export const getContentHighlightHTML = (item: AlgoliaItemType) => ({ 85 dangerouslySetInnerHTML: { 86 __html: trimContent(item._highlightResult.content?.value || ''), 87 }, 88}); 89 90// note(simek): this code make sure that browser popup blocker 91// do not prevent opening links via key press (when it fires windows.open) 92export const openLink = (url: string, isExternal: boolean = false) => { 93 const link = document.createElement('a'); 94 if (isExternal) { 95 link.target = '_blank'; 96 link.rel = 'noopener noreferrer'; 97 } 98 link.href = url; 99 link.click(); 100}; 101 102const ReferencePathChunks = ['/versions/', '/modules/', '/more/'] as const; 103 104export const isReferencePath = (url: string) => { 105 return ReferencePathChunks.some(pathChunk => url.includes(pathChunk)); 106}; 107 108const EASPathChunks = [ 109 '/app-signing/', 110 '/build/', 111 '/build-reference/', 112 '/development/', 113 '/eas/', 114 '/eas/metadata/', 115 '/eas-update/', 116 '/submit/', 117] as const; 118 119export const isEASPath = (url: string) => { 120 return EASPathChunks.some(pathChunk => url.includes(pathChunk)); 121}; 122 123const HomePathChunks = [ 124 '/get-started/', 125 '/develop/', 126 '/deploy/', 127 '/faq/', 128 '/core-concepts/', 129 '/debugging/', 130 '/config-plugins/', 131] as const; 132 133export const isHomePath = (url: string) => { 134 return HomePathChunks.some(pathChunk => url.includes(pathChunk)); 135}; 136 137const LearnPathChunks = ['/tutorial', '/ui-programming/', '/additional-resources/'] as const; 138 139export const isLearnPath = (url: string) => { 140 return LearnPathChunks.some(pathChunk => url.includes(pathChunk)); 141}; 142 143export const isAppleDevice = () => { 144 return /(Mac|iPhone|iPod|iPad)/i.test( 145 navigator?.platform ?? navigator?.userAgentData?.platform ?? '' 146 ); 147}; 148 149export const addHighlight = (content: string, query: string) => { 150 const highlightStart = content.toLowerCase().indexOf(query.toLowerCase()); 151 152 if (highlightStart === -1) return content; 153 154 const highlightEnd = highlightStart + query.length; 155 return ( 156 content.substring(0, highlightStart) + 157 '<mark>' + 158 content.substring(highlightStart, highlightEnd) + 159 '</mark>' + 160 content.substring(highlightEnd) 161 ); 162}; 163