List components #31
@ -1,66 +1,80 @@
|
|||||||
import ListItem from '../ListItem/ListItem';
|
import type { HTMLAttributes } from "react";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import ListItem from "../ListItem/ListItem";
|
||||||
|
|
||||||
export interface SearchResultOption {
|
export interface SearchResultOption {
|
||||||
value: string;
|
value: string;
|
||||||
|
ansv7779 marked this conversation as resolved
|
|||||||
label: string;
|
label: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchResultListProps {
|
export interface SearchResultListProps
|
||||||
options: SearchResultOption[];
|
extends Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> {
|
||||||
selectedValues?: string[];
|
options: SearchResultOption[];
|
||||||
focusedIndex?: number;
|
selectedValues?: string[];
|
||||||
maxHeight?: number;
|
focusedIndex?: number;
|
||||||
noResultsText?: string;
|
maxHeight?: number;
|
||||||
onSelect?: (option: SearchResultOption) => void;
|
noResultsText?: string;
|
||||||
itemRefs?: React.RefObject<(HTMLDivElement | null)[]>;
|
onSelect?: (option: SearchResultOption) => void;
|
||||||
|
itemRefs?: React.RefObject<(HTMLDivElement | null)[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerClasses = [
|
const baseClasses = clsx(
|
||||||
'w-full bg-base-canvas border border-base-ink-medium rounded-(--border-radius-md)',
|
"w-full bg-base-canvas",
|
||||||
'overflow-y-auto',
|
"border border-base-ink-medium rounded-(--border-radius-md)",
|
||||||
].join(' ');
|
"overflow-y-auto",
|
||||||
|
);
|
||||||
|
|
||||||
const noResultsClasses = 'px-(--padding-md) py-(--padding-md) body-normal-md text-base-ink-placeholder text-center';
|
const noResultsClasses =
|
||||||
|
"px-(--padding-md) py-(--padding-md) body-normal-md text-base-ink-placeholder text-center";
|
||||||
|
|
||||||
|
const dividerClasses =
|
||||||
|
"border-t border-base-ink-soft [border-top-width:var(--border-width-sm)]";
|
||||||
|
|
||||||
export default function SearchResultList({
|
export default function SearchResultList({
|
||||||
options,
|
options,
|
||||||
selectedValues = [],
|
selectedValues = [],
|
||||||
focusedIndex = -1,
|
focusedIndex = -1,
|
||||||
maxHeight = 300,
|
maxHeight = 300,
|
||||||
noResultsText = 'No results found',
|
noResultsText = "No results found",
|
||||||
onSelect,
|
onSelect,
|
||||||
itemRefs,
|
itemRefs,
|
||||||
|
className,
|
||||||
|
style,
|
||||||
|
...props
|
||||||
}: SearchResultListProps) {
|
}: SearchResultListProps) {
|
||||||
const isSelected = (value: string) => selectedValues.includes(value);
|
const isSelected = (value: string) => selectedValues.includes(value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses} style={{ maxHeight }} onMouseDown={(e) => e.preventDefault()}>
|
<div
|
||||||
{options.length > 0 ? (
|
className={clsx(baseClasses, className)}
|
||||||
options.map((option, index) => (
|
style={{ maxHeight, ...style }}
|
||||||
<div
|
onMouseDown={(e) => e.preventDefault()}
|
||||||
key={option.value}
|
{...props}
|
||||||
ref={(el) => {
|
>
|
||||||
if (itemRefs?.current) {
|
{options.length > 0 ? (
|
||||||
itemRefs.current[index] = el;
|
options.map((option, index) => (
|
||||||
}
|
<div
|
||||||
}}
|
key={option.value}
|
||||||
className={
|
ref={(el) => {
|
||||||
index > 0 ? 'border-t border-base-ink-soft [border-top-width:var(--border-width-sm)]' : ''
|
if (itemRefs?.current) {
|
||||||
}
|
itemRefs.current[index] = el;
|
||||||
>
|
}
|
||||||
<ListItem
|
}}
|
||||||
title={option.label}
|
className={index > 0 ? dividerClasses : undefined}
|
||||||
subtitle={option.subtitle}
|
>
|
||||||
selected={isSelected(option.value)}
|
<ListItem
|
||||||
focused={index === focusedIndex}
|
title={option.label}
|
||||||
onClick={() => onSelect?.(option)}
|
subtitle={option.subtitle}
|
||||||
/>
|
selected={isSelected(option.value)}
|
||||||
</div>
|
focused={index === focusedIndex}
|
||||||
))
|
onClick={() => onSelect?.(option)}
|
||||||
) : (
|
/>
|
||||||
<div className={noResultsClasses}>{noResultsText}</div>
|
</div>
|
||||||
)}
|
))
|
||||||
</div>
|
) : (
|
||||||
);
|
<div className={noResultsClasses}>{noResultsText}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user
This is limiting. Often times you want to select some more complex object as you do in your examples in
ComponentLibrary. Forcing all users of the component to do their own lookup when it should be handled by theCombobox/this component.