-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: lodash package added * chore: dropdown key down hook added * dev: dropdown component * chore: build error and code refactor * chore: readme file updated
- Loading branch information
1 parent
96cee7b
commit 4643ad3
Showing
12 changed files
with
708 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
Below is a detailed list of the props included: | ||
|
||
### Root Props | ||
- value: string | string[]; - Current selected value. | ||
- onChange: (value: string | string []) => void; - Callback function for handling value changes. | ||
- options: TDropdownOption[] | undefined; - Array of options. | ||
- onOpen?: () => void; - Callback function triggered when the dropdown opens. | ||
- onClose?: () => void; - Callback function triggered when the dropdown closes. | ||
- containerClassName?: (isOpen: boolean) => string; - Function to return the class name for the container based on the open state. | ||
- tabIndex?: number; - Sets the tab index for the dropdown. | ||
- placement?: Placement; - Determines the placement of the dropdown (e.g., top, bottom, left, right). | ||
- disabled?: boolean; - Disables the dropdown if set to true. | ||
|
||
--- | ||
|
||
### Button Props | ||
- buttonContent?: (isOpen: boolean) => React.ReactNode; - Function to render the content of the button based on the open state. | ||
- buttonContainerClassName?: string; - Class name for the button container. | ||
- buttonClassName?: string; - Class name for the button itself. | ||
|
||
--- | ||
|
||
### Input Props | ||
- disableSearch?: boolean; - Disables the search input if set to true. | ||
- inputPlaceholder?: string; - Placeholder text for the search input. | ||
- inputClassName?: string; - Class name for the search input. | ||
- inputIcon?: React.ReactNode; - Icon to be displayed in the search input. | ||
- inputContainerClassName?: string; - Class name for the search input container. | ||
|
||
--- | ||
|
||
### Options Props | ||
- keyExtractor: (option: TDropdownOption) => string; - Function to extract the key from each option. | ||
- optionsContainerClassName?: string; - Class name for the options container. | ||
- queryArray: string[]; - Array of strings to be used for querying the options. | ||
- sortByKey: string; - Key to sort the options by. | ||
- firstItem?: (optionValue: string) => boolean; - Function to determine if an option should be the first item. | ||
- renderItem?: ({ value, selected }: { value: string; selected: boolean }) => React.ReactNode; - Function to render each option. | ||
- loader?: React.ReactNode; - Loader element to be displayed while options are being loaded. | ||
- disableSorting?: boolean; - Disables sorting of the options if set to true. | ||
|
||
--- | ||
|
||
These properties offer extensive control over the dropdown's behavior and presentation, making it a highly versatile component suitable for various scenarios. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import React, { Fragment } from "react"; | ||
// headless ui | ||
import { Combobox } from "@headlessui/react"; | ||
// helper | ||
import { cn } from "../../../helpers"; | ||
import { IMultiSelectDropdownButton, ISingleSelectDropdownButton } from "../dropdown"; | ||
|
||
export const DropdownButton: React.FC<IMultiSelectDropdownButton | ISingleSelectDropdownButton> = (props) => { | ||
const { | ||
isOpen, | ||
buttonContent, | ||
buttonClassName, | ||
buttonContainerClassName, | ||
handleOnClick, | ||
value, | ||
setReferenceElement, | ||
disabled, | ||
} = props; | ||
return ( | ||
<Combobox.Button as={Fragment}> | ||
<button | ||
ref={setReferenceElement} | ||
type="button" | ||
className={cn( | ||
"clickable block h-full max-w-full outline-none", | ||
{ | ||
"cursor-not-allowed text-custom-text-200": disabled, | ||
"cursor-pointer": !disabled, | ||
}, | ||
buttonContainerClassName | ||
)} | ||
onClick={handleOnClick} | ||
> | ||
{buttonContent ? <>{buttonContent(isOpen)}</> : <span className={cn("", buttonClassName)}>{value}</span>} | ||
</button> | ||
</Combobox.Button> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from "./input-search"; | ||
export * from "./button"; | ||
export * from "./options"; | ||
export * from "./loader"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import React, { FC, useEffect, useRef } from "react"; | ||
// headless ui | ||
import { Combobox } from "@headlessui/react"; | ||
// icons | ||
import { Search } from "lucide-react"; | ||
// helpers | ||
import { cn } from "../../../helpers"; | ||
|
||
interface IInputSearch { | ||
isOpen: boolean; | ||
query: string; | ||
updateQuery: (query: string) => void; | ||
inputIcon?: React.ReactNode; | ||
inputContainerClassName?: string; | ||
inputClassName?: string; | ||
inputPlaceholder?: string; | ||
} | ||
|
||
export const InputSearch: FC<IInputSearch> = (props) => { | ||
const { isOpen, query, updateQuery, inputIcon, inputContainerClassName, inputClassName, inputPlaceholder } = props; | ||
|
||
const inputRef = useRef<HTMLInputElement | null>(null); | ||
|
||
const searchInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||
if (query !== "" && e.key === "Escape") { | ||
e.stopPropagation(); | ||
updateQuery(""); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
if (isOpen) { | ||
inputRef.current && inputRef.current.focus(); | ||
} | ||
}, [isOpen]); | ||
return ( | ||
<div | ||
className={cn( | ||
"flex items-center gap-1.5 rounded border border-custom-border-100 bg-custom-background-90 px-2", | ||
inputContainerClassName | ||
)} | ||
> | ||
{inputIcon ? <>{inputIcon}</> : <Search className="h-4 w-4 text-custom-text-300" aria-hidden="true" />} | ||
<Combobox.Input | ||
as="input" | ||
ref={inputRef} | ||
className={cn( | ||
"w-full bg-transparent py-1 text-xs text-custom-text-200 placeholder:text-custom-text-400 focus:outline-none", | ||
inputClassName | ||
)} | ||
value={query} | ||
onChange={(e) => updateQuery(e.target.value)} | ||
placeholder={inputPlaceholder ?? "Search"} | ||
onKeyDown={searchInputKeyDown} | ||
/> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from "react"; | ||
|
||
export const DropdownOptionsLoader = () => ( | ||
<div className="flex flex-col gap-1 animate-pulse"> | ||
{Array.from({ length: 6 }, (_, i) => ( | ||
<div key={i} className="flex h-[1.925rem] w-full rounded px-1 py-1.5 bg-custom-background-90" /> | ||
))} | ||
</div> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import React from "react"; | ||
// headless ui | ||
import { Combobox } from "@headlessui/react"; | ||
// icons | ||
import { Check } from "lucide-react"; | ||
// components | ||
import { DropdownOptionsLoader, InputSearch } from "."; | ||
// helpers | ||
import { cn } from "../../../helpers"; | ||
// types | ||
import { IMultiSelectDropdownOptions, ISingleSelectDropdownOptions } from "../dropdown"; | ||
|
||
export const DropdownOptions: React.FC<IMultiSelectDropdownOptions | ISingleSelectDropdownOptions> = (props) => { | ||
const { | ||
isOpen, | ||
query, | ||
setQuery, | ||
inputIcon, | ||
inputPlaceholder, | ||
inputClassName, | ||
inputContainerClassName, | ||
disableSearch, | ||
keyExtractor, | ||
options, | ||
value, | ||
renderItem, | ||
loader, | ||
} = props; | ||
return ( | ||
<> | ||
{!disableSearch && ( | ||
<InputSearch | ||
isOpen={isOpen} | ||
query={query} | ||
updateQuery={(query) => setQuery(query)} | ||
inputIcon={inputIcon} | ||
inputPlaceholder={inputPlaceholder} | ||
inputClassName={inputClassName} | ||
inputContainerClassName={inputContainerClassName} | ||
/> | ||
)} | ||
<div className="mt-2 max-h-48 space-y-1 overflow-y-scroll"> | ||
<> | ||
{options ? ( | ||
options.length > 0 ? ( | ||
options?.map((option) => ( | ||
<Combobox.Option | ||
key={keyExtractor(option)} | ||
value={option.data[option.value]} | ||
className={({ active, selected }) => | ||
cn( | ||
"flex w-full cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5", | ||
{ | ||
"bg-custom-background-80": active, | ||
"text-custom-text-100": selected, | ||
"text-custom-text-200": !selected, | ||
}, | ||
option.className && option.className({ active, selected }) | ||
) | ||
} | ||
> | ||
{({ selected }) => ( | ||
<> | ||
{renderItem ? ( | ||
<>{renderItem({ value: option.data[option.value], selected })}</> | ||
) : ( | ||
<> | ||
<span className="flex-grow truncate">{value}</span> | ||
{selected && <Check className="h-3.5 w-3.5 flex-shrink-0" />} | ||
</> | ||
)} | ||
</> | ||
)} | ||
</Combobox.Option> | ||
)) | ||
) : ( | ||
<p className="px-1.5 py-1 italic text-custom-text-400">No matching results</p> | ||
) | ||
) : loader ? ( | ||
<> {loader} </> | ||
) : ( | ||
<DropdownOptionsLoader /> | ||
)} | ||
</> | ||
</div> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { Placement } from "@popperjs/core"; | ||
|
||
export interface IDropdown { | ||
// root props | ||
onOpen?: () => void; | ||
onClose?: () => void; | ||
containerClassName?: (isOpen: boolean) => string; | ||
tabIndex?: number; | ||
placement?: Placement; | ||
disabled?: boolean; | ||
|
||
// button props | ||
buttonContent?: (isOpen: boolean) => React.ReactNode; | ||
buttonContainerClassName?: string; | ||
buttonClassName?: string; | ||
|
||
// input props | ||
disableSearch?: boolean; | ||
inputPlaceholder?: string; | ||
inputClassName?: string; | ||
inputIcon?: React.ReactNode; | ||
inputContainerClassName?: string; | ||
|
||
// options props | ||
keyExtractor: (option: TDropdownOption) => string; | ||
optionsContainerClassName?: string; | ||
queryArray: string[]; | ||
sortByKey: string; | ||
firstItem?: (optionValue: string) => boolean; | ||
renderItem?: ({ value, selected }: { value: string; selected: boolean }) => React.ReactNode; | ||
loader?: React.ReactNode; | ||
disableSorting?: boolean; | ||
} | ||
|
||
export interface TDropdownOption { | ||
data: any; | ||
value: string; | ||
className?: ({ active, selected }: { active: boolean; selected: boolean }) => string; | ||
} | ||
|
||
export interface IMultiSelectDropdown extends IDropdown { | ||
value: string[]; | ||
onChange: (value: string[]) => void; | ||
options: TDropdownOption[] | undefined; | ||
} | ||
|
||
export interface ISingleSelectDropdown extends IDropdown { | ||
value: string; | ||
onChange: (value: string) => void; | ||
options: TDropdownOption[] | undefined; | ||
} | ||
|
||
export interface IDropdownButton { | ||
isOpen: boolean; | ||
buttonContent?: (isOpen: boolean) => React.ReactNode; | ||
buttonClassName?: string; | ||
buttonContainerClassName?: string; | ||
handleOnClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void; | ||
setReferenceElement: (element: HTMLButtonElement | null) => void; | ||
disabled?: boolean; | ||
} | ||
|
||
export interface IMultiSelectDropdownButton extends IDropdownButton { | ||
value: string[]; | ||
} | ||
|
||
export interface ISingleSelectDropdownButton extends IDropdownButton { | ||
value: string; | ||
} | ||
|
||
export interface IDropdownOptions { | ||
isOpen: boolean; | ||
query: string; | ||
setQuery: (query: string) => void; | ||
|
||
inputPlaceholder?: string; | ||
inputClassName?: string; | ||
inputIcon?: React.ReactNode; | ||
inputContainerClassName?: string; | ||
disableSearch?: boolean; | ||
|
||
keyExtractor: (option: TDropdownOption) => string; | ||
renderItem: (({ value, selected }: { value: string; selected: boolean }) => React.ReactNode) | undefined; | ||
options: TDropdownOption[] | undefined; | ||
loader?: React.ReactNode; | ||
} | ||
|
||
export interface IMultiSelectDropdownOptions extends IDropdownOptions { | ||
value: string[]; | ||
} | ||
|
||
export interface ISingleSelectDropdownOptions extends IDropdownOptions { | ||
value: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from "./common"; | ||
export * from "./multi-select"; | ||
export * from "./single-select"; |
Oops, something went wrong.