⚡️ feat: add hideValues
prop to hide the values when on multiple
This commit is contained in:
parent
410def0750
commit
54c2e8ec0b
@ -34,7 +34,7 @@ export const selectTheme = tv({
|
|||||||
],
|
],
|
||||||
icon: ['text-elements-mid-em'],
|
icon: ['text-elements-mid-em'],
|
||||||
helperIcon: [],
|
helperIcon: [],
|
||||||
helperText: ['flex', 'gap-2', 'items-center', 'text-elements-danger'],
|
helperText: ['flex', 'gap-2', 'items-center', 'text-elements-low-em'],
|
||||||
popover: [
|
popover: [
|
||||||
'z-20',
|
'z-20',
|
||||||
'absolute',
|
'absolute',
|
||||||
@ -70,12 +70,8 @@ export const selectTheme = tv({
|
|||||||
container: [],
|
container: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
state: {
|
|
||||||
default: {
|
|
||||||
inputWrapper: '',
|
|
||||||
helperText: ['text-elements-low-em'],
|
|
||||||
},
|
|
||||||
error: {
|
error: {
|
||||||
|
true: {
|
||||||
inputWrapper: [
|
inputWrapper: [
|
||||||
'outline',
|
'outline',
|
||||||
'outline-offset-0',
|
'outline-offset-0',
|
||||||
@ -121,6 +117,11 @@ export const selectTheme = tv({
|
|||||||
input: ['cursor-pointer'],
|
input: ['cursor-pointer'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
hideValues: {
|
||||||
|
true: {
|
||||||
|
input: ['placeholder:text-elements-mid-em'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
compoundVariants: [
|
compoundVariants: [
|
||||||
{
|
{
|
||||||
@ -143,6 +144,7 @@ export const selectTheme = tv({
|
|||||||
variant: 'default',
|
variant: 'default',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
state: 'default',
|
state: 'default',
|
||||||
|
error: false,
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
hasValue: false,
|
hasValue: false,
|
||||||
},
|
},
|
||||||
|
@ -91,6 +91,10 @@ interface SelectProps
|
|||||||
* The helper text of the select
|
* The helper text of the select
|
||||||
*/
|
*/
|
||||||
helperText?: string;
|
helperText?: string;
|
||||||
|
/**
|
||||||
|
* Show the values of the select if it's multiple
|
||||||
|
*/
|
||||||
|
hideValues?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Select = ({
|
export const Select = ({
|
||||||
@ -99,7 +103,7 @@ export const Select = ({
|
|||||||
searchable = false,
|
searchable = false,
|
||||||
clearable,
|
clearable,
|
||||||
size,
|
size,
|
||||||
state,
|
error,
|
||||||
orientation = 'horizontal',
|
orientation = 'horizontal',
|
||||||
variant,
|
variant,
|
||||||
label,
|
label,
|
||||||
@ -107,9 +111,10 @@ export const Select = ({
|
|||||||
leftIcon,
|
leftIcon,
|
||||||
rightIcon,
|
rightIcon,
|
||||||
helperText,
|
helperText,
|
||||||
|
hideValues = false,
|
||||||
placeholder: placeholderProp = 'Select an option',
|
placeholder: placeholderProp = 'Select an option',
|
||||||
}: SelectProps) => {
|
}: SelectProps) => {
|
||||||
const theme = selectTheme({ size, state, variant, orientation });
|
const theme = selectTheme({ size, error, variant, orientation });
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
const [selectedItem, setSelectedItem] = useState<SelectOption | null>(null);
|
const [selectedItem, setSelectedItem] = useState<SelectOption | null>(null);
|
||||||
@ -273,20 +278,28 @@ export const Select = ({
|
|||||||
const renderHelperText = useMemo(
|
const renderHelperText = useMemo(
|
||||||
() => (
|
() => (
|
||||||
<div className={theme.helperText()}>
|
<div className={theme.helperText()}>
|
||||||
{state === 'error' &&
|
{error &&
|
||||||
cloneIcon(<WarningIcon className={theme.helperIcon()} />, {
|
cloneIcon(<WarningIcon className={theme.helperIcon()} />, {
|
||||||
'aria-hidden': true,
|
'aria-hidden': true,
|
||||||
})}
|
})}
|
||||||
<p>{helperText}</p>
|
<p>{helperText}</p>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
[cloneIcon, state, theme, helperText],
|
[cloneIcon, error, theme, helperText],
|
||||||
);
|
);
|
||||||
|
|
||||||
const isMultipleHasValue = multiple && selectedItems.length > 0;
|
const isMultipleHasValue = multiple && selectedItems.length > 0;
|
||||||
const isMultipleHasValueButNotSearchable =
|
const isMultipleHasValueButNotSearchable =
|
||||||
multiple && !searchable && selectedItems.length > 0;
|
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 (
|
return (
|
||||||
<div className={theme.container()}>
|
<div className={theme.container()}>
|
||||||
@ -297,7 +310,7 @@ export const Select = ({
|
|||||||
<div
|
<div
|
||||||
ref={inputWrapperRef}
|
ref={inputWrapperRef}
|
||||||
className={theme.inputWrapper({
|
className={theme.inputWrapper({
|
||||||
hasValue: isMultipleHasValue,
|
hasValue: isMultipleHasValue && !hideValues,
|
||||||
})}
|
})}
|
||||||
onClick={() => !dropdownOpen && openMenu()}
|
onClick={() => !dropdownOpen && openMenu()}
|
||||||
>
|
>
|
||||||
@ -306,6 +319,7 @@ export const Select = ({
|
|||||||
|
|
||||||
{/* Multiple input values */}
|
{/* Multiple input values */}
|
||||||
{isMultipleHasValue &&
|
{isMultipleHasValue &&
|
||||||
|
!hideValues &&
|
||||||
selectedItems.map((item, index) => (
|
selectedItems.map((item, index) => (
|
||||||
<SelectValue
|
<SelectValue
|
||||||
key={`selected-item-${index}`}
|
key={`selected-item-${index}`}
|
||||||
@ -319,15 +333,21 @@ export const Select = ({
|
|||||||
{/* Single input value or searchable area */}
|
{/* Single input value or searchable area */}
|
||||||
<input
|
<input
|
||||||
{...getInputProps(getDropdownProps())}
|
{...getInputProps(getDropdownProps())}
|
||||||
placeholder={placeholder}
|
placeholder={displayPlaceholder}
|
||||||
// Control readOnly based on searchable
|
// Control readOnly based on searchable
|
||||||
readOnly={!searchable}
|
readOnly={!searchable || hideValues}
|
||||||
className={cn(theme.input({ searchable }), {
|
className={cn(
|
||||||
|
theme.input({
|
||||||
|
searchable,
|
||||||
|
hideValues: hideValues && selectedItems.length > 0,
|
||||||
|
}),
|
||||||
|
{
|
||||||
// Make the input width smaller because we don't need it (not searchable)
|
// Make the input width smaller because we don't need it (not searchable)
|
||||||
'w-6': isMultipleHasValueButNotSearchable,
|
'w-6': isMultipleHasValueButNotSearchable && !hideValues,
|
||||||
// Add margin to the X icon
|
// Add margin to the X icon
|
||||||
'ml-6': isMultipleHasValueButNotSearchable && clearable,
|
'ml-6': isMultipleHasValueButNotSearchable && clearable,
|
||||||
})}
|
},
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Right icon */}
|
{/* Right icon */}
|
||||||
@ -339,12 +359,12 @@ export const Select = ({
|
|||||||
|
|
||||||
{/* Popover */}
|
{/* Popover */}
|
||||||
<ul
|
<ul
|
||||||
{...getMenuProps()}
|
{...getMenuProps({ ref: popoverRef }, { suppressRefError: true })}
|
||||||
id="popover"
|
id="popover"
|
||||||
ref={popoverRef}
|
ref={popoverRef}
|
||||||
className={cn(theme.popover({ isOpen }), {
|
className={cn(theme.popover({ isOpen }), {
|
||||||
// Position the popover based on the dropdown position
|
// 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-[35%]': dropdownPosition === 'bottom' && label,
|
||||||
'top-[42.5%]': dropdownPosition === 'bottom' && label && description,
|
'top-[42.5%]': dropdownPosition === 'bottom' && label && description,
|
||||||
'bottom-[92.5%]': dropdownPosition === 'top' && !label,
|
'bottom-[92.5%]': dropdownPosition === 'top' && !label,
|
||||||
|
@ -31,6 +31,7 @@ import {
|
|||||||
import { renderDefaultTag, renderMinimalTag } from './renders/tag';
|
import { renderDefaultTag, renderMinimalTag } from './renders/tag';
|
||||||
import { renderToast, renderToastsWithCta } from './renders/toast';
|
import { renderToast, renderToastsWithCta } from './renders/toast';
|
||||||
import { renderTooltips } from './renders/tooltip';
|
import { renderTooltips } from './renders/tooltip';
|
||||||
|
import { renderDropdowns } from './renders/dropdown';
|
||||||
|
|
||||||
type ValuePiece = Date | null;
|
type ValuePiece = Date | null;
|
||||||
type Value = ValuePiece | [ValuePiece, ValuePiece];
|
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" />
|
<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 */}
|
{/* Inline notification */}
|
||||||
<div className="flex flex-col gap-10 items-center justify-between">
|
<div className="flex flex-col gap-10 items-center justify-between">
|
||||||
<h1 className="text-2xl font-bold">Inline Notification</h1>
|
<h1 className="text-2xl font-bold">Inline Notification</h1>
|
||||||
|
240
packages/frontend/src/pages/components/renders/dropdown.tsx
Normal file
240
packages/frontend/src/pages/components/renders/dropdown.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
);
|
Loading…
Reference in New Issue
Block a user