️ feat: add hideValues prop to hide the values when on multiple

This commit is contained in:
Wahyu Kurniawan 2024-02-24 13:48:57 +07:00
parent 410def0750
commit 54c2e8ec0b
No known key found for this signature in database
GPG Key ID: 040A1549143A8E33
4 changed files with 294 additions and 23 deletions

View File

@ -34,7 +34,7 @@ export const selectTheme = tv({
],
icon: ['text-elements-mid-em'],
helperIcon: [],
helperText: ['flex', 'gap-2', 'items-center', 'text-elements-danger'],
helperText: ['flex', 'gap-2', 'items-center', 'text-elements-low-em'],
popover: [
'z-20',
'absolute',
@ -70,12 +70,8 @@ export const selectTheme = tv({
container: [],
},
},
state: {
default: {
inputWrapper: '',
helperText: ['text-elements-low-em'],
},
error: {
error: {
true: {
inputWrapper: [
'outline',
'outline-offset-0',
@ -121,6 +117,11 @@ export const selectTheme = tv({
input: ['cursor-pointer'],
},
},
hideValues: {
true: {
input: ['placeholder:text-elements-mid-em'],
},
},
},
compoundVariants: [
{
@ -143,6 +144,7 @@ export const selectTheme = tv({
variant: 'default',
size: 'md',
state: 'default',
error: false,
isOpen: false,
hasValue: false,
},

View File

@ -91,6 +91,10 @@ interface SelectProps
* The helper text of the select
*/
helperText?: string;
/**
* Show the values of the select if it's multiple
*/
hideValues?: boolean;
}
export const Select = ({
@ -99,7 +103,7 @@ export const Select = ({
searchable = false,
clearable,
size,
state,
error,
orientation = 'horizontal',
variant,
label,
@ -107,9 +111,10 @@ export const Select = ({
leftIcon,
rightIcon,
helperText,
hideValues = false,
placeholder: placeholderProp = 'Select an option',
}: SelectProps) => {
const theme = selectTheme({ size, state, variant, orientation });
const theme = selectTheme({ size, error, variant, orientation });
const [inputValue, setInputValue] = useState('');
const [selectedItem, setSelectedItem] = useState<SelectOption | null>(null);
@ -273,20 +278,28 @@ export const Select = ({
const renderHelperText = useMemo(
() => (
<div className={theme.helperText()}>
{state === 'error' &&
{error &&
cloneIcon(<WarningIcon className={theme.helperIcon()} />, {
'aria-hidden': true,
})}
<p>{helperText}</p>
</div>
),
[cloneIcon, state, theme, helperText],
[cloneIcon, error, theme, helperText],
);
const isMultipleHasValue = multiple && selectedItems.length > 0;
const isMultipleHasValueButNotSearchable =
multiple && !searchable && selectedItems.length > 0;
const placeholder = isMultipleHasValueButNotSearchable ? '' : placeholderProp;
const displayPlaceholder = useMemo(() => {
if (hideValues && isMultipleHasValue) {
return `${selectedItems.length} selected`;
}
if (isMultipleHasValueButNotSearchable) {
return '';
}
return placeholderProp;
}, [hideValues, multiple, selectedItems.length, placeholderProp]);
return (
<div className={theme.container()}>
@ -297,7 +310,7 @@ export const Select = ({
<div
ref={inputWrapperRef}
className={theme.inputWrapper({
hasValue: isMultipleHasValue,
hasValue: isMultipleHasValue && !hideValues,
})}
onClick={() => !dropdownOpen && openMenu()}
>
@ -306,6 +319,7 @@ export const Select = ({
{/* Multiple input values */}
{isMultipleHasValue &&
!hideValues &&
selectedItems.map((item, index) => (
<SelectValue
key={`selected-item-${index}`}
@ -319,15 +333,21 @@ export const Select = ({
{/* Single input value or searchable area */}
<input
{...getInputProps(getDropdownProps())}
placeholder={placeholder}
placeholder={displayPlaceholder}
// Control readOnly based on searchable
readOnly={!searchable}
className={cn(theme.input({ searchable }), {
// Make the input width smaller because we don't need it (not searchable)
'w-6': isMultipleHasValueButNotSearchable,
// Add margin to the X icon
'ml-6': isMultipleHasValueButNotSearchable && clearable,
})}
readOnly={!searchable || hideValues}
className={cn(
theme.input({
searchable,
hideValues: hideValues && selectedItems.length > 0,
}),
{
// Make the input width smaller because we don't need it (not searchable)
'w-6': isMultipleHasValueButNotSearchable && !hideValues,
// Add margin to the X icon
'ml-6': isMultipleHasValueButNotSearchable && clearable,
},
)}
/>
{/* Right icon */}
@ -339,12 +359,12 @@ export const Select = ({
{/* Popover */}
<ul
{...getMenuProps()}
{...getMenuProps({ ref: popoverRef }, { suppressRefError: true })}
id="popover"
ref={popoverRef}
className={cn(theme.popover({ isOpen }), {
// Position the popover based on the dropdown position
'top-[12.5%]': dropdownPosition === 'bottom' && !label,
'top-[27.5%]': dropdownPosition === 'bottom' && !label,
'top-[35%]': dropdownPosition === 'bottom' && label,
'top-[42.5%]': dropdownPosition === 'bottom' && label && description,
'bottom-[92.5%]': dropdownPosition === 'top' && !label,

View File

@ -31,6 +31,7 @@ import {
import { renderDefaultTag, renderMinimalTag } from './renders/tag';
import { renderToast, renderToastsWithCta } from './renders/toast';
import { renderTooltips } from './renders/tooltip';
import { renderDropdowns } from './renders/dropdown';
type ValuePiece = Date | null;
type Value = ValuePiece | [ValuePiece, ValuePiece];
@ -270,6 +271,14 @@ const Page: React.FC = () => {
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Dropdown */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Dropdown / Select</h1>
{renderDropdowns()}
</div>
<div className="w-full h border border-gray-200 px-20 my-10" />
{/* Inline notification */}
<div className="flex flex-col gap-10 items-center justify-between">
<h1 className="text-2xl font-bold">Inline Notification</h1>

View File

@ -0,0 +1,240 @@
import React from 'react';
import { PencilIcon } from 'components/shared/CustomIcon';
import { SelectOption, Select } from 'components/shared/Select';
export const DROPDOWN_ITEMS: SelectOption[] = [
{
value: 'apple',
label: 'Apple',
description: 'Apple is fruit',
leftIcon: <PencilIcon />,
},
{
value: 'banana',
label: 'Banana',
description: 'Banana is fruit',
leftIcon: <PencilIcon />,
},
{
value: 'orange',
label: 'Orange',
description: 'Orange is fruit',
leftIcon: <PencilIcon />,
},
{
value: 'watermelon',
label: 'Watermelon',
description: 'Watermelon is fruit',
disabled: true,
leftIcon: <PencilIcon />,
},
];
export const renderDropdowns = () => (
<>
<p className="text-sm text-center text-gray-500 -mb-8">Single Small</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select size="sm" placeholder="Default" options={DROPDOWN_ITEMS} />
<Select
size="sm"
placeholder="Clearable"
clearable
options={DROPDOWN_ITEMS}
/>
<Select
size="sm"
searchable
placeholder="Searchable"
options={DROPDOWN_ITEMS}
/>
<Select
size="sm"
placeholder="Vertical"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-8">Single Medium</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select placeholder="Default" options={DROPDOWN_ITEMS} />
<Select placeholder="Clearable" clearable options={DROPDOWN_ITEMS} />
<Select searchable placeholder="Searchable" options={DROPDOWN_ITEMS} />
<Select
placeholder="Vertical"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-8">Multiple Small</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select
multiple
size="sm"
placeholder="Default"
options={DROPDOWN_ITEMS}
/>
<Select
multiple
size="sm"
placeholder="Clearable"
clearable
options={DROPDOWN_ITEMS}
/>
<Select
searchable
multiple
size="sm"
placeholder="Searchable"
options={DROPDOWN_ITEMS}
/>
<Select
multiple
size="sm"
placeholder="Vertical"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
<Select
multiple
hideValues
size="sm"
orientation="vertical"
placeholder="Hide values"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-8">Multiple Medium</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select multiple placeholder="Default" options={DROPDOWN_ITEMS} />
<Select
multiple
placeholder="Clearable"
clearable
options={DROPDOWN_ITEMS}
/>
<Select
searchable
multiple
placeholder="Searchable"
options={DROPDOWN_ITEMS}
/>
<Select
multiple
placeholder="Vertical"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
<Select
multiple
hideValues
orientation="vertical"
placeholder="Hide values"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-4">
Single With label, description, and helper text
</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select
label="Default"
description="Single select component"
helperText="This is a helper text"
options={DROPDOWN_ITEMS}
/>
<Select
label="Clearable"
description="Single select component"
helperText="This is a helper text"
clearable
options={DROPDOWN_ITEMS}
/>
<Select
searchable
label="Searchable"
description="Single select component"
helperText="This is a helper text"
options={DROPDOWN_ITEMS}
/>
<Select
label="Vertical"
description="Single select component"
helperText="This is a helper text"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-4">
Multiple With label, description, and helper text
</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select
label="Default"
description="Multiple select component"
helperText="This is a helper text"
multiple
options={DROPDOWN_ITEMS}
/>
<Select
label="Clearable"
description="Multiple select component"
helperText="This is a helper text"
multiple
clearable
options={DROPDOWN_ITEMS}
/>
<Select
searchable
label="Searchable"
description="Multiple select component"
helperText="This is a helper text"
multiple
options={DROPDOWN_ITEMS}
/>
<Select
label="Vertical"
description="Multiple select component"
helperText="This is a helper text"
multiple
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
</div>
<p className="text-sm text-center text-gray-500 -mb-4">
Error With label, description, and helper text
</p>
<div className="flex gap-4 flex-wrap justify-center">
<Select
error
label="Default"
description="Multiple select component"
helperText="This is a helper text"
options={DROPDOWN_ITEMS}
/>
<Select
error
label="Clearable"
description="Multiple select component"
helperText="This is a helper text"
clearable
options={DROPDOWN_ITEMS}
/>
<Select
error
searchable
label="Searchable"
description="Multiple select component"
helperText="This is a helper text"
options={DROPDOWN_ITEMS}
/>
<Select
error
label="Vertical"
description="Multiple select component"
helperText="This is a helper text"
orientation="vertical"
options={DROPDOWN_ITEMS}
/>
</div>
</>
);