Skip to content

Commit b448894

Browse files
authored
Add tags prop to SearchListItem (#554)
* add tags to SearchListItem * add styles to story * fixes * feedback * feedback
1 parent 6b9101d commit b448894

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
lines changed

packages/core-data/src/components/SearchList.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ type Props = {
5151
/**
5252
* Callback that fires when the pointer stops hovering over an item
5353
*/
54-
onItemPointerLeave?: (item: any) => void
54+
onItemPointerLeave?: (item: any) => void,
55+
56+
/**
57+
* List of attributes that appear as pills on the top of the item
58+
*/
59+
tags?: { attribute: string, primary?: boolean, secondary?: boolean }[]
5560
};
5661

5762
const LIMIT_STEP = 50;
@@ -119,6 +124,7 @@ const SearchList = (props: Props) => {
119124
onClick={props.onItemClick}
120125
onPointerEnter={props.onItemPointerEnter}
121126
onPointerLeave={props.onItemPointerLeave}
127+
tags={props.tags}
122128
/>
123129
))}
124130
</InfiniteScroll>

packages/core-data/src/components/SearchListItem.js

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, { type Element, useMemo } from 'react';
44
import clsx from 'clsx';
55
import Icon from './Icon';
66
import { type Attribute } from '../types/SearchList';
7+
import Pill from './Pill';
78

89
type SearchListItemProps = {
910
/**
@@ -39,7 +40,12 @@ type SearchListItemProps = {
3940
/**
4041
* Title of the record
4142
*/
42-
title: string
43+
title: string,
44+
45+
/**
46+
* List of attributes that appear as pills on the top of the item
47+
*/
48+
tags?: { attribute: string, primary?: boolean, secondary?: boolean }[]
4349
};
4450

4551
type ItemWrapperProps = {
@@ -76,6 +82,28 @@ const SearchListItem = (props: SearchListItemProps) => {
7682
return props.item[attribute.name];
7783
}), [props.attributes, props.item]);
7884

85+
const tags = useMemo(() => {
86+
const result = [];
87+
88+
if (!props.tags) {
89+
return result;
90+
}
91+
92+
props.tags.forEach(tag => {
93+
const value = props.item[tag.attribute];
94+
95+
if (value) {
96+
result.push({
97+
value,
98+
primary: tag.primary,
99+
secondary: tag.secondary,
100+
});
101+
}
102+
});
103+
104+
return result;
105+
}, [props.tags, props.item]);
106+
79107
return (
80108
<li
81109
className={clsx(
@@ -93,15 +121,26 @@ const SearchListItem = (props: SearchListItemProps) => {
93121
? () => props.onPointerLeave(props.item)
94122
: undefined}
95123
>
124+
{tags.length > 0 && (
125+
<div className='flex flex-wrap gap-2'>
126+
{tags.map((tag, idx) => (
127+
<Pill
128+
primary={tag.primary}
129+
secondary={tag.secondary}
130+
label={tag.value}
131+
key={idx}
132+
/>
133+
))}
134+
</div>
135+
)}
96136
<p className='font-bold text-neutral-800'>{props.title}</p>
97137
{props.attributes && attributeValues.some(Boolean) && (
98138
<ul className='list-none'>
99139
{props.attributes.slice(0, 3).map((att, idx) => (
100-
<>
140+
<React.Fragment key={att.name}>
101141
{!!attributeValues[idx] && (
102142
<li
103143
className='text-sm text-neutral-800 flex gap-2 items-center list-none pl-5 pt-1'
104-
key={att.name}
105144
>
106145
<Icon
107146
className='min-w-[13px]'
@@ -111,7 +150,7 @@ const SearchListItem = (props: SearchListItemProps) => {
111150
{attributeValues[idx]}
112151
</li>
113152
)}
114-
</>
153+
</React.Fragment>
115154
))}
116155
</ul>
117156
)}

packages/storybook/src/core-data/SearchList.stories.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,40 @@ export const Default = () => (
4545
</div>
4646
);
4747

48+
export const WithTags = () => (
49+
<div className='h-[600px] w-[360px]'>
50+
<SearchList
51+
attributes={[
52+
{
53+
label: 'UUID',
54+
name: 'uuid'
55+
},
56+
{
57+
label: 'Record ID',
58+
name: 'record_id',
59+
icon: 'person'
60+
},
61+
{
62+
label: 'Location',
63+
name: 'geometry',
64+
icon: 'location',
65+
render: (item) => (item.coordinates
66+
? `${item.coordinates[0]}, ${item.coordinates[1]}`
67+
: '')
68+
}
69+
]}
70+
tags={[
71+
{
72+
attribute: 'type',
73+
primary: true
74+
}
75+
]}
76+
items={LOTS_OF_DATA}
77+
itemTitle='name'
78+
/>
79+
</div>
80+
);
81+
4882
export const TitleCallback = () => (
4983
<div className='h-[600px] w-[360px]'>
5084
<SearchList

0 commit comments

Comments
 (0)