|
1 | 1 | // @flow |
2 | 2 |
|
3 | | -import React, { type Element } from 'react'; |
| 3 | +import React, { type Element, useMemo } from 'react'; |
4 | 4 | import clsx from 'clsx'; |
5 | 5 | import Icon from './Icon'; |
6 | 6 | import { type Attribute } from '../types/SearchList'; |
@@ -61,46 +61,58 @@ const ItemWrapper = (props: ItemWrapperProps) => { |
61 | 61 | return props.children; |
62 | 62 | }; |
63 | 63 |
|
64 | | -const SearchListItem = (props: SearchListItemProps) => ( |
65 | | - <li |
66 | | - className={clsx( |
67 | | - { 'bg-neutral-200': props.isHighlight }, |
68 | | - { 'hover:bg-neutral-200': !!props.onClick } |
69 | | - )} |
70 | | - > |
71 | | - <ItemWrapper {...props}> |
72 | | - <div |
73 | | - className='py-3 px-6' |
74 | | - onPointerEnter={props.onPointerEnter |
75 | | - ? () => props.onPointerEnter(props.item) |
76 | | - : undefined} |
77 | | - onPointerLeave={props.onPointerLeave |
78 | | - ? () => props.onPointerLeave(props.item) |
79 | | - : undefined} |
80 | | - > |
81 | | - <p className='font-bold text-neutral-800'>{props.title}</p> |
82 | | - {props.attributes && props.attributes.length > 0 && ( |
83 | | - <ul className='list-none'> |
84 | | - {props.attributes.slice(0, 3).map((att) => ( |
85 | | - <li |
86 | | - className='text-sm text-neutral-800 flex gap-2 items-center list-none pl-5 pt-1' |
87 | | - key={att.name} |
88 | | - > |
89 | | - <Icon |
90 | | - className='min-w-[13px]' |
91 | | - name={att.icon || 'bullet'} |
92 | | - size={13} |
93 | | - /> |
94 | | - {att.render |
95 | | - ? att.render(props.item) |
96 | | - : props.item[att.name]} |
97 | | - </li> |
98 | | - ))} |
99 | | - </ul> |
100 | | - )} |
101 | | - </div> |
102 | | - </ItemWrapper> |
103 | | - </li> |
104 | | -); |
| 64 | +const SearchListItem = (props: SearchListItemProps) => { |
| 65 | + const attributeValues = useMemo(() => props.attributes.slice(0, 3).map((attribute) => { |
| 66 | + if (attribute.render) { |
| 67 | + return attribute.render(props.item); |
| 68 | + } |
| 69 | + |
| 70 | + return props.item[attribute.name]; |
| 71 | + }), [props.attributes, props.item]); |
| 72 | + |
| 73 | + return ( |
| 74 | + <li |
| 75 | + className={clsx( |
| 76 | + { 'bg-neutral-200': props.isHighlight }, |
| 77 | + { 'hover:bg-neutral-200': !!props.onClick } |
| 78 | + )} |
| 79 | + > |
| 80 | + <ItemWrapper {...props}> |
| 81 | + <div |
| 82 | + className='py-3 px-6' |
| 83 | + onPointerEnter={props.onPointerEnter |
| 84 | + ? () => props.onPointerEnter(props.item) |
| 85 | + : undefined} |
| 86 | + onPointerLeave={props.onPointerLeave |
| 87 | + ? () => props.onPointerLeave(props.item) |
| 88 | + : undefined} |
| 89 | + > |
| 90 | + <p className='font-bold text-neutral-800'>{props.title}</p> |
| 91 | + {props.attributes && attributeValues.some(Boolean) && ( |
| 92 | + <ul className='list-none'> |
| 93 | + {props.attributes.slice(0, 3).map((att, idx) => ( |
| 94 | + <> |
| 95 | + {!!attributeValues[idx] && ( |
| 96 | + <li |
| 97 | + className='text-sm text-neutral-800 flex gap-2 items-center list-none pl-5 pt-1' |
| 98 | + key={att.name} |
| 99 | + > |
| 100 | + <Icon |
| 101 | + className='min-w-[13px]' |
| 102 | + name={att.icon || 'bullet'} |
| 103 | + size={13} |
| 104 | + /> |
| 105 | + {attributeValues[idx]} |
| 106 | + </li> |
| 107 | + )} |
| 108 | + </> |
| 109 | + ))} |
| 110 | + </ul> |
| 111 | + )} |
| 112 | + </div> |
| 113 | + </ItemWrapper> |
| 114 | + </li> |
| 115 | + ); |
| 116 | +}; |
105 | 117 |
|
106 | 118 | export default SearchListItem; |
0 commit comments