refactor: dropdowns (#1532)

This commit is contained in:
Aaryan Khandelwal 2023-07-17 17:35:47 +05:30 committed by GitHub
parent 538d67dbd9
commit dddfeb17b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 287 additions and 183 deletions

View File

@ -28,11 +28,11 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
handleClose={() => setmonthModal(false)} handleClose={() => setmonthModal(false)}
handleChange={handleChange} handleChange={handleChange}
/> />
<div className="flex flex-col gap-7 px-6 py-5 rounded-[10px] border border-brand-base bg-brand-base"> <div className="flex flex-col gap-7 px-6 py-5 rounded-[10px] border border-custom-border-100 bg-custom-background-90">
<div className="flex items-center justify-between gap-x-8 gap-y-2 "> <div className="flex items-center justify-between gap-x-8 gap-y-2">
<div className="flex flex-col gap-2.5"> <div className="flex flex-col gap-2.5">
<h4 className="text-lg font-semibold">Auto-archive closed issues</h4> <h4 className="text-lg font-semibold">Auto-archive closed issues</h4>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-custom-text-200">
Plane will automatically archive issues that have been completed or cancelled for the Plane will automatically archive issues that have been completed or cancelled for the
configured time period. configured time period.
</p> </p>
@ -52,17 +52,12 @@ export const AutoArchiveAutomation: React.FC<Props> = ({ projectDetails, handleC
<div className="w-1/2 text-base font-medium"> <div className="w-1/2 text-base font-medium">
Auto-archive issues that are closed for Auto-archive issues that are closed for
</div> </div>
<div className="w-1/2 "> <div className="w-1/2">
<CustomSelect <CustomSelect
value={projectDetails?.archive_in} value={projectDetails?.archive_in}
customButton={ label={`${projectDetails?.archive_in} ${
<button className="flex w-full items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 text-brand-secondary hover:text-brand-base hover:bg-brand-surface-2 focus:outline-none px-3 py-2 text-sm text-left"> projectDetails?.archive_in === 1 ? "Month" : "Months"
{`${projectDetails?.archive_in} ${ }`}
projectDetails?.archive_in === 1 ? "Month" : "Months"
}`}
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</button>
}
onChange={(val: number) => { onChange={(val: number) => {
handleChange({ archive_in: val }); handleChange({ archive_in: val });
}} }}

View File

@ -77,11 +77,11 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
handleChange={handleChange} handleChange={handleChange}
/> />
<div className="flex flex-col gap-7 px-6 py-5 rounded-[10px] border border-brand-base bg-brand-base"> <div className="flex flex-col gap-7 px-6 py-5 rounded-[10px] border border-custom-border-100 bg-custom-background-90">
<div className="flex items-center justify-between gap-x-8 gap-y-2 "> <div className="flex items-center justify-between gap-x-8 gap-y-2 ">
<div className="flex flex-col gap-2.5"> <div className="flex flex-col gap-2.5">
<h4 className="text-lg font-semibold">Auto-close inactive issues</h4> <h4 className="text-lg font-semibold">Auto-close inactive issues</h4>
<p className="text-sm text-brand-secondary"> <p className="text-sm text-custom-text-200">
Plane will automatically close the issues that have not been updated for the Plane will automatically close the issues that have not been updated for the
configured time period. configured time period.
</p> </p>
@ -102,17 +102,12 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
<div className="w-1/2 text-base font-medium"> <div className="w-1/2 text-base font-medium">
Auto-close issues that are inactive for Auto-close issues that are inactive for
</div> </div>
<div className="w-1/2 "> <div className="w-1/2">
<CustomSelect <CustomSelect
value={projectDetails?.close_in} value={projectDetails?.close_in}
customButton={ label={`${projectDetails?.close_in} ${
<button className="flex w-full items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 text-brand-secondary hover:text-brand-base hover:bg-brand-surface-2 focus:outline-none px-3 py-2 text-sm text-left"> projectDetails?.close_in === 1 ? "Month" : "Months"
{`${projectDetails?.close_in} ${ }`}
projectDetails?.close_in === 1 ? "Month" : "Months"
}`}
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</button>
}
onChange={(val: number) => { onChange={(val: number) => {
handleChange({ close_in: val }); handleChange({ close_in: val });
}} }}
@ -143,42 +138,34 @@ export const AutoCloseAutomation: React.FC<Props> = ({ projectDetails, handleCha
value={ value={
projectDetails?.default_state ? projectDetails?.default_state : defaultState projectDetails?.default_state ? projectDetails?.default_state : defaultState
} }
customButton={ label={
<button <div className="flex items-center gap-2">
className={`flex w-full items-center justify-between gap-1 rounded-md border border-brand-base shadow-sm duration-300 text-brand-secondary hover:text-brand-base hover:bg-brand-surface-2 focus:outline-none px-3 py-2 text-sm text-left ${ {selectedOption ? (
!multipleOptions ? "opacity-60" : "" getStateGroupIcon(selectedOption.group, "16", "16", selectedOption.color)
}`} ) : currentDefaultState ? (
> getStateGroupIcon(
<div className="flex items-center gap-2"> currentDefaultState.group,
{selectedOption ? ( "16",
getStateGroupIcon(selectedOption.group, "16", "16", selectedOption.color) "16",
) : currentDefaultState ? ( currentDefaultState.color
getStateGroupIcon( )
currentDefaultState.group, ) : (
"16", <Squares2X2Icon className="h-3.5 w-3.5 text-custom-text-200" />
"16",
currentDefaultState.color
)
) : (
<Squares2X2Icon className="h-3.5 w-3.5 text-custom-text-200" />
)}
{selectedOption?.name
? selectedOption.name
: currentDefaultState?.name ?? (
<span className="text-custom-text-200">State</span>
)}
</div>
{multipleOptions && (
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
)} )}
</button> {selectedOption?.name
? selectedOption.name
: currentDefaultState?.name ?? (
<span className="text-custom-text-200">State</span>
)}
</div>
} }
onChange={(val: string) => { onChange={(val: string) => {
handleChange({ default_state: val }); handleChange({ default_state: val });
}} }}
options={options} options={options}
disabled={!multipleOptions} disabled={!multipleOptions}
dropdownWidth="w-full" width="w-full"
input
/> />
</div> </div>
</div> </div>

View File

@ -56,7 +56,7 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
className="!w-full" className="!w-full"
customButton={ customButton={
<div <div
className={`relative group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-custom-text-200 text-current hover:text-custom-text-100 w-full py-3 px-2 ${ className={`relative group flex items-center justify-start gap-1.5 cursor-pointer text-sm text-custom-text-200 hover:text-custom-text-100 w-full py-3 px-2 ${
activeSortingProperty === col.propertyName ? "bg-custom-background-80" : "" activeSortingProperty === col.propertyName ? "bg-custom-background-80" : ""
}`} }`}
> >
@ -90,16 +90,9 @@ export const SpreadsheetColumns: React.FC<Props> = ({ columnData, gridTemplateCo
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" /> <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</div> </div>
} }
menuItemsWhiteBg
width="xl" width="xl"
> >
<CustomMenu.MenuItem <CustomMenu.MenuItem
className={`${
selectedMenuItem === `${col.ascendingOrder}_${col.propertyName}`
? "bg-custom-background-80"
: ""
}`}
key={col.propertyName}
onClick={() => { onClick={() => {
handleOrderBy(col.ascendingOrder, col.propertyName); handleOrderBy(col.ascendingOrder, col.propertyName);
}} }}

View File

@ -112,7 +112,7 @@ export const SpreadsheetView: React.FC<Props> = ({
</button> </button>
} }
position="left" position="left"
menuItemsClassName="left-5 !w-36" optionsClassName="left-5 !w-36"
noBorder noBorder
> >
<CustomMenu.MenuItem <CustomMenu.MenuItem

View File

@ -130,7 +130,7 @@ export const ViewAssigneeSelect: React.FC<Props> = ({
position={position} position={position}
disabled={isNotAllowed} disabled={isNotAllowed}
selfPositioned={selfPositioned} selfPositioned={selfPositioned}
dropdownWidth="w-full min-w-[12rem]" width="w-full min-w-[12rem]"
/> />
); );
}; };

View File

@ -127,8 +127,6 @@ export const ViewLabelSelect: React.FC<Props> = ({
</button> </button>
); );
const noResultIcon = <TagIcon className="h-3.5 w-3.5 text-custom-text-200" />;
return ( return (
<> <>
{projectId && ( {projectId && (
@ -152,8 +150,7 @@ export const ViewLabelSelect: React.FC<Props> = ({
disabled={isNotAllowed} disabled={isNotAllowed}
selfPositioned={selfPositioned} selfPositioned={selfPositioned}
footerOption={footerOption} footerOption={footerOption}
noResultIcon={noResultIcon} width="w-full min-w-[12rem]"
dropdownWidth="w-full min-w-[12rem]"
/> />
</> </>
); );

View File

@ -66,7 +66,7 @@ export const ModuleMembersSelect: React.FC<Props> = ({ value, onChange }) => {
} }
options={options} options={options}
onChange={onChange} onChange={onChange}
height="md" maxHeight="md"
multiple multiple
noChevron noChevron
/> />

View File

@ -75,7 +75,7 @@ export const SidebarLeadSelect: React.FC<Props> = ({ value, onChange }) => {
</div> </div>
} }
options={options} options={options}
height="md" maxHeight="md"
position="right" position="right"
onChange={onChange} onChange={onChange}
/> />

View File

@ -70,7 +70,7 @@ export const SidebarMembersSelect: React.FC<Props> = ({ value, onChange }) => {
} }
options={options} options={options}
onChange={onChange} onChange={onChange}
height="md" maxHeight="md"
position="right" position="right"
multiple multiple
/> />

View File

@ -223,7 +223,7 @@ const SendProjectInvitationModal: React.FC<Props> = ({ isOpen, setIsOpen, member
}} }}
options={options} options={options}
position="left" position="left"
dropdownWidth="w-full min-w-[12rem]" width="w-full min-w-[12rem]"
/> />
)} )}
/> />

View File

@ -4,7 +4,7 @@ import Link from "next/link";
// headless ui // headless ui
import { Menu, Transition } from "@headlessui/react"; import { Menu, Transition } from "@headlessui/react";
// icons // icons
import { ChevronDownIcon, EllipsisHorizontalIcon } from "@heroicons/react/24/outline"; import { ChevronDownIcon } from "@heroicons/react/24/outline";
import { Icon } from "./icon"; import { Icon } from "./icon";
type Props = { type Props = {

View File

@ -0,0 +1,153 @@
import React from "react";
import Link from "next/link";
// headless ui
import { Menu, Transition } from "@headlessui/react";
// icons
import { DropdownProps, Icon } from "components/ui";
import { ChevronDownIcon } from "@heroicons/react/24/outline";
export type CustomMenuProps = DropdownProps & {
children: React.ReactNode;
ellipsis?: boolean;
noBorder?: boolean;
verticalEllipsis?: boolean;
};
const CustomMenu = ({
buttonClassName = "",
children,
className = "",
customButton,
disabled = false,
ellipsis = false,
label,
maxHeight = "md",
noBorder = false,
noChevron = false,
optionsClassName = "",
position = "right",
selfPositioned = false,
verticalEllipsis = false,
verticalPosition = "bottom",
width = "auto",
}: CustomMenuProps) => (
<Menu as="div" className={`${selfPositioned ? "" : "relative"} w-min text-left ${className}`}>
{({ open }) => (
<>
{customButton ? (
<Menu.Button as="div">{customButton}</Menu.Button>
) : (
<>
{ellipsis || verticalEllipsis ? (
<Menu.Button
type="button"
disabled={disabled}
className={`relative grid place-items-center rounded p-1 text-custom-text-200 outline-none ${
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
<Icon
iconName="more_horiz"
className={`${verticalEllipsis ? "rotate-90" : ""} text-custom-text-200`}
/>
</Menu.Button>
) : (
<Menu.Button
type="button"
className={`flex items-center justify-between gap-1 rounded-md px-2.5 py-1 text-xs duration-300 ${
open ? "bg-custom-background-90 text-custom-text-100" : "text-custom-text-200"
} ${
noBorder ? "" : "border border-custom-border-100 shadow-sm focus:outline-none"
} ${
disabled
? "cursor-not-allowed text-custom-text-200"
: "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
>
{label}
{!noChevron && <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />}
</Menu.Button>
)}
</>
)}
<Transition
as={React.Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
className={`absolute z-10 overflow-y-scroll whitespace-nowrap rounded-md border border-custom-border-100 p-1 text-xs shadow-lg focus:outline-none bg-custom-background-90 ${
position === "left" ? "left-0 origin-top-left" : "right-0 origin-top-right"
} ${verticalPosition === "top" ? "bottom-full mb-1" : "mt-1"} ${
maxHeight === "lg"
? "max-h-60"
: maxHeight === "md"
? "max-h-48"
: maxHeight === "rg"
? "max-h-36"
: maxHeight === "sm"
? "max-h-28"
: ""
} ${width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width} ${optionsClassName}`}
>
<div className="py-1">{children}</div>
</Menu.Items>
</Transition>
</>
)}
</Menu>
);
type MenuItemProps = {
children: JSX.Element | string;
renderAs?: "button" | "a";
href?: string;
onClick?: (args?: any) => void;
className?: string;
};
const MenuItem: React.FC<MenuItemProps> = ({
children,
renderAs,
href,
onClick,
className = "",
}) => (
<Menu.Item as="div">
{({ active, close }) =>
renderAs === "a" ? (
<Link href={href ?? ""}>
<a
className={`inline-block w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${
active ? "bg-custom-background-80" : ""
} ${className}`}
onClick={close}
>
{children}
</a>
</Link>
) : (
<button
type="button"
className={`w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${
active ? "bg-custom-background-80" : ""
} ${className}`}
onClick={onClick}
>
{children}
</button>
)
}
</Menu.Item>
);
CustomMenu.MenuItem = MenuItem;
export { CustomMenu };

View File

@ -5,8 +5,12 @@ import { Combobox, Transition } from "@headlessui/react";
// icons // icons
import { ChevronDownIcon } from "@heroicons/react/20/solid"; import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
// types
import { DropdownProps } from "./types";
type CustomSearchSelectProps = { export type CustomSearchSelectProps = DropdownProps & {
footerOption?: JSX.Element;
multiple?: boolean;
value: any; value: any;
onChange: any; onChange: any;
options: options:
@ -16,43 +20,27 @@ type CustomSearchSelectProps = {
content: JSX.Element; content: JSX.Element;
}[] }[]
| undefined; | undefined;
label?: string | JSX.Element;
textAlignment?: "left" | "center" | "right";
height?: "sm" | "md" | "rg" | "lg";
position?: "right" | "left";
verticalPosition?: "top" | "bottom";
noChevron?: boolean;
customButton?: JSX.Element;
className?: string;
optionsClassName?: string;
input?: boolean;
disabled?: boolean;
selfPositioned?: boolean;
multiple?: boolean;
footerOption?: JSX.Element;
noResultIcon?: JSX.Element;
dropdownWidth?: string;
}; };
export const CustomSearchSelect = ({ export const CustomSearchSelect = ({
buttonClassName = "",
className = "",
customButton,
disabled = false,
footerOption,
input = false,
label, label,
textAlignment, maxHeight = "md",
height = "md", multiple = false,
value, noChevron = false,
onChange, onChange,
options, options,
position = "left",
verticalPosition = "bottom",
noChevron = false,
customButton,
className = "",
optionsClassName = "", optionsClassName = "",
input = false, position = "left",
disabled = false,
selfPositioned = false, selfPositioned = false,
multiple = false, value,
noResultIcon, verticalPosition = "bottom",
footerOption, width = "auto",
dropdownWidth,
}: CustomSearchSelectProps) => { }: CustomSearchSelectProps) => {
const [query, setQuery] = useState(""); const [query, setQuery] = useState("");
@ -72,7 +60,7 @@ export const CustomSearchSelect = ({
return ( return (
<Combobox <Combobox
as="div" as="div"
className={`${!selfPositioned ? "relative" : ""} flex-shrink-0 text-left ${className}`} className={`${selfPositioned ? "" : "relative"} flex-shrink-0 text-left ${className}`}
{...props} {...props}
> >
{({ open }: any) => ( {({ open }: any) => (
@ -81,17 +69,13 @@ export const CustomSearchSelect = ({
<Combobox.Button as="div">{customButton}</Combobox.Button> <Combobox.Button as="div">{customButton}</Combobox.Button>
) : ( ) : (
<Combobox.Button <Combobox.Button
className={`flex w-full border border-custom-border-200 ${ className={`flex items-center justify-between gap-1 w-full rounded-md shadow-sm border border-custom-border-100 duration-300 focus:outline-none ${
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-custom-background-80"
} ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs" input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} items-center justify-between gap-1 rounded-md shadow-sm duration-300 focus:outline-none focus:ring-1 focus:ring-custom-border-100 ${ } ${
textAlignment === "right" disabled
? "text-right" ? "cursor-not-allowed text-custom-text-200"
: textAlignment === "center" : "cursor-pointer hover:bg-custom-background-80"
? "text-center" } ${buttonClassName}`}
: "text-left"
}`}
> >
{label} {label}
{!noChevron && !disabled && ( {!noChevron && !disabled && (
@ -110,13 +94,11 @@ export const CustomSearchSelect = ({
leaveTo="opacity-0 translate-y-1" leaveTo="opacity-0 translate-y-1"
> >
<Combobox.Options <Combobox.Options
className={`${optionsClassName} absolute min-w-[10rem] border border-custom-border-200 p-2 ${ className={`absolute z-10 min-w-[10rem] border border-custom-border-100 p-2 rounded-md bg-custom-background-90 text-xs shadow-lg focus:outline-none ${
position === "right" ? "right-0" : "left-0" position === "left" ? "left-0 origin-top-left" : "right-0 origin-top-right"
} ${ } ${verticalPosition === "top" ? "bottom-full mb-1" : "mt-1"} ${
verticalPosition === "top" ? "bottom-full mb-1" : "mt-1" width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width
} z-10 origin-top-right rounded-md bg-custom-background-90 text-xs shadow-lg focus:outline-none ${ } ${optionsClassName}`}
dropdownWidth ? dropdownWidth : ``
} `}
> >
<div className="flex w-full items-center justify-start rounded-sm border-[0.6px] border-custom-border-200 bg-custom-background-90 px-2"> <div className="flex w-full items-center justify-start rounded-sm border-[0.6px] border-custom-border-200 bg-custom-background-90 px-2">
<MagnifyingGlassIcon className="h-3 w-3 text-custom-text-200" /> <MagnifyingGlassIcon className="h-3 w-3 text-custom-text-200" />
@ -129,14 +111,14 @@ export const CustomSearchSelect = ({
</div> </div>
<div <div
className={`mt-2 space-y-1 ${ className={`mt-2 space-y-1 ${
height === "sm" maxHeight === "lg"
? "max-h-60"
: maxHeight === "md"
? "max-h-48"
: maxHeight === "rg"
? "max-h-36"
: maxHeight === "sm"
? "max-h-28" ? "max-h-28"
: height === "md"
? "max-h-44"
: height === "rg"
? "max-h-56"
: height === "lg"
? "max-h-80"
: "" : ""
} overflow-y-scroll`} } overflow-y-scroll`}
> >
@ -147,9 +129,9 @@ export const CustomSearchSelect = ({
key={option.value} key={option.value}
value={option.value} value={option.value}
className={({ active, selected }) => className={({ active, selected }) =>
`${active || selected ? "bg-custom-background-80" : ""} ${ `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${
selected ? "text-custom-text-100" : "text-custom-text-200" active || selected ? "bg-custom-background-80" : ""
} flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5` } ${selected ? "text-custom-text-100" : "text-custom-text-200"}`
} }
> >
{({ active, selected }) => ( {({ active, selected }) => (
@ -176,7 +158,6 @@ export const CustomSearchSelect = ({
)) ))
) : ( ) : (
<span className="flex items-center gap-2 p-1"> <span className="flex items-center gap-2 p-1">
{noResultIcon && noResultIcon}
<p className="text-left text-custom-text-200 ">No matching results</p> <p className="text-left text-custom-text-200 ">No matching results</p>
</span> </span>
) )

View File

@ -5,73 +5,58 @@ import { Listbox, Transition } from "@headlessui/react";
// icons // icons
import { ChevronDownIcon } from "@heroicons/react/20/solid"; import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { CheckIcon } from "@heroicons/react/24/outline"; import { CheckIcon } from "@heroicons/react/24/outline";
// types
import { DropdownProps } from "./types";
type CustomSelectProps = { export type CustomSelectProps = DropdownProps & {
children: React.ReactNode;
value: any; value: any;
onChange: any; onChange: any;
children: React.ReactNode;
label?: string | JSX.Element;
textAlignment?: "left" | "center" | "right";
maxHeight?: "sm" | "rg" | "md" | "lg" | "none";
position?: "right" | "left";
verticalPosition?: "top" | "bottom";
width?: "auto" | string;
input?: boolean;
noChevron?: boolean;
customButton?: JSX.Element;
optionsClassName?: string;
disabled?: boolean;
selfPositioned?: boolean;
}; };
const CustomSelect = ({ const CustomSelect = ({
buttonClassName = "",
children, children,
className = "",
customButton,
disabled = false,
input = false,
label, label,
textAlignment, maxHeight = "md",
value, noChevron = false,
onChange, onChange,
maxHeight = "none", optionsClassName = "",
position = "left", position = "left",
selfPositioned = false,
value,
verticalPosition = "bottom", verticalPosition = "bottom",
width = "auto", width = "auto",
input = false,
noChevron = false,
customButton,
optionsClassName = "",
disabled = false,
selfPositioned = false,
}: CustomSelectProps) => ( }: CustomSelectProps) => (
<Listbox <Listbox
as="div" as="div"
value={value} value={value}
onChange={onChange} onChange={onChange}
className={`${!selfPositioned ? "relative" : ""} flex-shrink-0 text-left`} className={`${selfPositioned ? "" : "relative"} flex-shrink-0 text-left ${className}`}
disabled={disabled} disabled={disabled}
> >
<div> <>
{customButton ? ( {customButton ? (
<Listbox.Button as="div">{customButton}</Listbox.Button> <Listbox.Button as="div">{customButton}</Listbox.Button>
) : ( ) : (
<Listbox.Button <Listbox.Button
className={`flex w-full ${ className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-100 shadow-sm duration-300 focus:outline-none ${
input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
disabled disabled
? "cursor-not-allowed text-custom-text-200" ? "cursor-not-allowed text-custom-text-200"
: "cursor-pointer hover:bg-custom-background-80" : "cursor-pointer hover:bg-custom-background-80"
} items-center justify-between gap-1 rounded-md border border-custom-border-200 shadow-sm duration-300 focus:outline-none ${ } ${buttonClassName}`}
input ? "border-custom-border-200 px-3 py-2 text-sm" : "px-2.5 py-1 text-xs"
} ${
textAlignment === "right"
? "text-right"
: textAlignment === "center"
? "text-center"
: "text-left"
}`}
> >
{label} {label}
{!noChevron && !disabled && <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />} {!noChevron && !disabled && <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />}
</Listbox.Button> </Listbox.Button>
)} )}
</div> </>
<Transition <Transition
as={React.Fragment} as={React.Fragment}
@ -83,13 +68,9 @@ const CustomSelect = ({
leaveTo="transform opacity-0 scale-95" leaveTo="transform opacity-0 scale-95"
> >
<Listbox.Options <Listbox.Options
className={`${optionsClassName} absolute border border-custom-border-200 ${ className={`absolute z-10 border border-custom-border-100 mt-1 origin-top-right overflow-y-auto rounded-md bg-custom-background-90 text-xs shadow-lg focus:outline-none ${
position === "right" ? "right-0" : "left-0" position === "left" ? "left-0 origin-top-left" : "right-0 origin-top-right"
} ${ } ${verticalPosition === "top" ? "bottom-full mb-1" : "mt-1"} ${
verticalPosition === "top" ? "bottom-full mb-1" : "mt-1"
} z-10 mt-1 origin-top-right overflow-y-auto rounded-md bg-custom-background-90 text-xs shadow-lg focus:outline-none ${
width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width
} ${input ? "max-h-48" : ""} ${
maxHeight === "lg" maxHeight === "lg"
? "max-h-60" ? "max-h-60"
: maxHeight === "md" : maxHeight === "md"
@ -99,7 +80,7 @@ const CustomSelect = ({
: maxHeight === "sm" : maxHeight === "sm"
? "max-h-28" ? "max-h-28"
: "" : ""
}`} } ${width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width} ${optionsClassName}`}
> >
<div className="space-y-1 p-2">{children}</div> <div className="space-y-1 p-2">{children}</div>
</Listbox.Options> </Listbox.Options>
@ -117,9 +98,9 @@ const Option: React.FC<OptionProps> = ({ children, value, className }) => (
<Listbox.Option <Listbox.Option
value={value} value={value}
className={({ active, selected }) => className={({ active, selected }) =>
`${className} ${active || selected ? "bg-custom-background-80" : ""} ${ `cursor-pointer select-none truncate rounded px-1 py-1.5 ${
selected ? "text-custom-text-100" : "text-custom-text-200" active || selected ? "bg-custom-background-80" : ""
} cursor-pointer select-none truncate rounded px-1 py-1.5` } ${selected ? "text-custom-text-100" : "text-custom-text-200"} ${className}`
} }
> >
{({ selected }) => ( {({ selected }) => (

View File

@ -0,0 +1,5 @@
export * from "./context-menu";
export * from "./custom-menu";
export * from "./custom-search-select";
export * from "./custom-select";
export * from "./types.d";

View File

@ -0,0 +1,15 @@
export type DropdownProps = {
buttonClassName?: string;
className?: string;
customButton?: JSX.Element;
disabled?: boolean;
input?: boolean;
label?: string | JSX.Element;
maxHeight?: "sm" | "rg" | "md" | "lg";
noChevron?: boolean;
optionsClassName?: string;
position?: "right" | "left";
selfPositioned?: boolean;
verticalPosition?: "top" | "bottom";
width?: "auto" | string;
};

View File

@ -1,16 +1,14 @@
export * from "./buttons"; export * from "./buttons";
export * from "./dropdowns";
export * from "./graphs"; export * from "./graphs";
export * from "./input"; export * from "./input";
export * from "./text-area"; export * from "./text-area";
export * from "./avatar"; export * from "./avatar";
export * from "./context-menu";
export * from "./custom-menu";
export * from "./custom-search-select";
export * from "./custom-select";
export * from "./date"; export * from "./date";
export * from "./datepicker"; export * from "./datepicker";
export * from "./empty-space"; export * from "./empty-space";
export * from "./empty-state"; export * from "./empty-state";
export * from "./icon";
export * from "./labels-list"; export * from "./labels-list";
export * from "./linear-progress-indicator"; export * from "./linear-progress-indicator";
export * from "./loader"; export * from "./loader";
@ -24,5 +22,4 @@ export * from "./markdown-to-component";
export * from "./product-updates-modal"; export * from "./product-updates-modal";
export * from "./integration-and-import-export-banner"; export * from "./integration-and-import-export-banner";
export * from "./range-datepicker"; export * from "./range-datepicker";
export * from "./icon";
export * from "./circular-progress"; export * from "./circular-progress";