|
1 | 1 | 'use client'; |
2 | 2 |
|
3 | 3 | import assertNever from 'assert-never'; |
4 | | -import { AnimatePresence, motion } from 'framer-motion'; |
| 4 | +import { motion } from 'framer-motion'; |
5 | 5 | import React from 'react'; |
6 | 6 |
|
7 | 7 | import { useAI } from '@/components/AI'; |
@@ -195,145 +195,141 @@ export const SearchResults = React.forwardRef(function SearchResults( |
195 | 195 | role="listbox" |
196 | 196 | aria-live="polite" |
197 | 197 | > |
198 | | - <AnimatePresence initial={false} mode="popLayout"> |
199 | | - {results.map((item, index) => { |
200 | | - const itemKey = getResultKey(item); |
201 | | - const shouldAnimateItem = |
202 | | - shouldAnimateResults || !seenResultKeys.current.has(itemKey); |
203 | | - const handleResultSelect = () => { |
204 | | - if ( |
205 | | - query && |
206 | | - siteSpaceId && |
207 | | - (item.type === 'local-page' || |
208 | | - item.type === 'page' || |
209 | | - item.type === 'record') |
210 | | - ) { |
211 | | - addRecentSearchQuery(siteSpaceId, query, 'search'); |
212 | | - } |
| 198 | + {results.map((item, index) => { |
| 199 | + const itemKey = getResultKey(item); |
| 200 | + const shouldAnimateItem = |
| 201 | + shouldAnimateResults || !seenResultKeys.current.has(itemKey); |
| 202 | + const handleResultSelect = () => { |
| 203 | + if ( |
| 204 | + query && |
| 205 | + siteSpaceId && |
| 206 | + (item.type === 'local-page' || |
| 207 | + item.type === 'page' || |
| 208 | + item.type === 'record') |
| 209 | + ) { |
| 210 | + addRecentSearchQuery(siteSpaceId, query, 'search'); |
| 211 | + } |
213 | 212 |
|
214 | | - onResultSelect?.(); |
215 | | - }; |
216 | | - const resultItemProps = { |
217 | | - 'aria-posinset': index + 1, |
218 | | - 'aria-setsize': results.length, |
219 | | - id: `${id}-${index}`, |
220 | | - onClickCapture: handleResultSelect, |
221 | | - }; |
222 | | - switch (item.type) { |
223 | | - case 'local-page': |
224 | | - case 'page': { |
225 | | - return ( |
226 | | - <motion.div |
227 | | - layout="position" |
228 | | - transition={ |
229 | | - shouldDisableLayoutAnimation |
230 | | - ? { layout: { duration: 0 } } |
231 | | - : { duration: 0.3, ease: 'circInOut' } |
| 213 | + onResultSelect?.(); |
| 214 | + }; |
| 215 | + const resultItemProps = { |
| 216 | + 'aria-posinset': index + 1, |
| 217 | + 'aria-setsize': results.length, |
| 218 | + id: `${id}-${index}`, |
| 219 | + onClickCapture: handleResultSelect, |
| 220 | + }; |
| 221 | + switch (item.type) { |
| 222 | + case 'local-page': |
| 223 | + case 'page': { |
| 224 | + return ( |
| 225 | + <motion.div |
| 226 | + layout="position" |
| 227 | + transition={ |
| 228 | + shouldDisableLayoutAnimation |
| 229 | + ? { layout: { duration: 0 } } |
| 230 | + : { duration: 0.3, ease: 'circInOut' } |
| 231 | + } |
| 232 | + key={itemKey} |
| 233 | + > |
| 234 | + <div |
| 235 | + className={ |
| 236 | + shouldAnimateItem |
| 237 | + ? 'animate-blur-in-height' |
| 238 | + : undefined |
232 | 239 | } |
233 | | - key={itemKey} |
| 240 | + style={{ |
| 241 | + animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
| 242 | + }} |
234 | 243 | > |
235 | | - <div |
236 | | - className={ |
237 | | - shouldAnimateItem |
238 | | - ? 'animate-blur-in-height' |
239 | | - : undefined |
240 | | - } |
| 244 | + <SearchPageResultItem |
| 245 | + ref={(ref) => { |
| 246 | + refs.current[index] = ref; |
| 247 | + }} |
| 248 | + query={query} |
| 249 | + item={item} |
| 250 | + active={index === cursor} |
241 | 251 | style={{ |
242 | 252 | animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
243 | 253 | }} |
244 | | - > |
245 | | - <SearchPageResultItem |
246 | | - ref={(ref) => { |
247 | | - refs.current[index] = ref; |
248 | | - }} |
249 | | - query={query} |
250 | | - item={item} |
251 | | - active={index === cursor} |
252 | | - style={{ |
253 | | - animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
254 | | - }} |
255 | | - {...resultItemProps} |
256 | | - /> |
257 | | - </div> |
258 | | - </motion.div> |
259 | | - ); |
| 254 | + {...resultItemProps} |
| 255 | + /> |
| 256 | + </div> |
| 257 | + </motion.div> |
| 258 | + ); |
| 259 | + } |
| 260 | + case 'recommended-question': { |
| 261 | + if (!primaryAssistant) { |
| 262 | + return null; |
260 | 263 | } |
261 | | - case 'recommended-question': { |
262 | | - if (!primaryAssistant) { |
263 | | - return null; |
264 | | - } |
265 | | - return ( |
266 | | - <motion.div |
| 264 | + return ( |
| 265 | + <motion.div |
| 266 | + className={ |
| 267 | + shouldAnimateItem ? 'animate-blur-in' : undefined |
| 268 | + } |
| 269 | + style={ |
| 270 | + shouldAnimateItem |
| 271 | + ? { |
| 272 | + animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
| 273 | + } |
| 274 | + : undefined |
| 275 | + } |
| 276 | + key={itemKey} |
| 277 | + > |
| 278 | + <SearchQuestionResultItem |
| 279 | + ref={(ref) => { |
| 280 | + refs.current[index] = ref; |
| 281 | + }} |
| 282 | + question={item.question} |
| 283 | + action={item.action} |
| 284 | + active={index === cursor} |
| 285 | + assistant={primaryAssistant} |
| 286 | + {...resultItemProps} |
| 287 | + /> |
| 288 | + </motion.div> |
| 289 | + ); |
| 290 | + } |
| 291 | + case 'record': { |
| 292 | + return ( |
| 293 | + <motion.div |
| 294 | + layout="position" |
| 295 | + transition={ |
| 296 | + shouldDisableLayoutAnimation |
| 297 | + ? { layout: { duration: 0 } } |
| 298 | + : { duration: 0.3, ease: 'circInOut' } |
| 299 | + } |
| 300 | + key={itemKey} |
| 301 | + > |
| 302 | + <div |
267 | 303 | className={ |
268 | 304 | shouldAnimateItem |
269 | | - ? 'animate-blur-in' |
270 | | - : undefined |
271 | | - } |
272 | | - style={ |
273 | | - shouldAnimateItem |
274 | | - ? { |
275 | | - animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
276 | | - } |
| 305 | + ? 'animate-blur-in-height' |
277 | 306 | : undefined |
278 | 307 | } |
279 | | - key={itemKey} |
| 308 | + style={{ |
| 309 | + animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
| 310 | + }} |
280 | 311 | > |
281 | | - <SearchQuestionResultItem |
| 312 | + <SearchRecordResultItem |
282 | 313 | ref={(ref) => { |
283 | 314 | refs.current[index] = ref; |
284 | 315 | }} |
285 | | - question={item.question} |
286 | | - action={item.action} |
| 316 | + key={itemKey} |
| 317 | + query={query} |
| 318 | + item={item} |
287 | 319 | active={index === cursor} |
288 | | - assistant={primaryAssistant} |
289 | | - {...resultItemProps} |
290 | | - /> |
291 | | - </motion.div> |
292 | | - ); |
293 | | - } |
294 | | - case 'record': { |
295 | | - return ( |
296 | | - <motion.div |
297 | | - layout="position" |
298 | | - transition={ |
299 | | - shouldDisableLayoutAnimation |
300 | | - ? { layout: { duration: 0 } } |
301 | | - : { duration: 0.3, ease: 'circInOut' } |
302 | | - } |
303 | | - key={itemKey} |
304 | | - > |
305 | | - <div |
306 | | - className={ |
307 | | - shouldAnimateItem |
308 | | - ? 'animate-blur-in-height' |
309 | | - : undefined |
310 | | - } |
311 | 320 | style={{ |
312 | 321 | animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
313 | 322 | }} |
314 | | - > |
315 | | - <SearchRecordResultItem |
316 | | - ref={(ref) => { |
317 | | - refs.current[index] = ref; |
318 | | - }} |
319 | | - key={itemKey} |
320 | | - query={query} |
321 | | - item={item} |
322 | | - active={index === cursor} |
323 | | - style={{ |
324 | | - animationDelay: `${index * 25}ms,${100 + index * 25}ms`, |
325 | | - }} |
326 | | - {...resultItemProps} |
327 | | - /> |
328 | | - </div> |
329 | | - </motion.div> |
330 | | - ); |
331 | | - } |
332 | | - default: |
333 | | - assertNever(item); |
| 323 | + {...resultItemProps} |
| 324 | + /> |
| 325 | + </div> |
| 326 | + </motion.div> |
| 327 | + ); |
334 | 328 | } |
335 | | - })} |
336 | | - </AnimatePresence> |
| 329 | + default: |
| 330 | + assertNever(item); |
| 331 | + } |
| 332 | + })} |
337 | 333 | </div> |
338 | 334 | {!fetching && results.length === 0 ? noResults : null} |
339 | 335 | </> |
|
0 commit comments