mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-08 01:09:51 +00:00
♻️ create custom autocomplete tag input
This commit is contained in:
@@ -5,8 +5,10 @@ import { useMemo, useState } from "react";
|
||||
import { useDebounce } from "use-debounce";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { MultiSelectTags } from "./multi-select/multi-select-tags";
|
||||
import { TagInput, type TagInputProps } from "./tags/tag-input";
|
||||
import {
|
||||
SuggestionsTagInput,
|
||||
type SuggestionsTagInputProps
|
||||
} from "./tags/suggestions-tag-input";
|
||||
|
||||
export type SelectedMachine = Pick<
|
||||
ListClientsResponse["clients"][number],
|
||||
@@ -18,19 +20,14 @@ export type MachineSelectorProps = {
|
||||
selectedMachines?: SelectedMachine[];
|
||||
onSelectMachines: (machine: SelectedMachine[]) => void;
|
||||
} & Omit<
|
||||
TagInputProps,
|
||||
| "activeTagIndex"
|
||||
| "setActiveTagIndex"
|
||||
| "placeholder"
|
||||
| "size"
|
||||
SuggestionsTagInputProps,
|
||||
| "tags"
|
||||
| "setTags"
|
||||
| "value"
|
||||
| "suggestedOptions"
|
||||
| "searchQuery"
|
||||
| "onSearchQueryChange"
|
||||
| "suggestedOptions"
|
||||
| "enableAutocomplete"
|
||||
| "autocompleteOptions"
|
||||
| "activeTagIndex"
|
||||
| "setActiveTagIndex"
|
||||
>;
|
||||
|
||||
export function MachinesSelector({
|
||||
@@ -48,7 +45,7 @@ export function MachinesSelector({
|
||||
orgQueries.machineClients({ orgId, perPage: 3, query: debouncedValue })
|
||||
);
|
||||
|
||||
// always include the selected machines in the list of machines shown (if the user isn't searching)
|
||||
// always include the selected machines in the list (if the user isn't searching)
|
||||
const machinesShown = useMemo(() => {
|
||||
const allMachines: Array<SelectedMachine> = [...machines];
|
||||
if (debouncedValue.trim().length === 0) {
|
||||
@@ -60,117 +57,45 @@ export function MachinesSelector({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allMachines;
|
||||
}, [machines, selectedMachines, debouncedValue]);
|
||||
|
||||
// const selectedMachinesIds = new Set(
|
||||
// selectedMachines.map((m) => m.clientId)
|
||||
// );
|
||||
|
||||
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TagInput
|
||||
{...props}
|
||||
activeTagIndex={activeTagIndex}
|
||||
setActiveTagIndex={setActiveTagIndex}
|
||||
placeholder={t("accessClientSelect")}
|
||||
size="sm"
|
||||
tags={selectedMachines.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))}
|
||||
setTags={(newTags) => {
|
||||
const tags =
|
||||
typeof newTags === "function"
|
||||
? newTags(
|
||||
selectedMachines.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))
|
||||
)
|
||||
: newTags;
|
||||
onSelectMachines(
|
||||
tags.map((tag) => ({
|
||||
clientId: Number(tag.id),
|
||||
name: tag.text
|
||||
}))
|
||||
);
|
||||
}}
|
||||
searchQuery={machineSearchQuery}
|
||||
onSearchQueryChange={setMachineSearchQuery}
|
||||
suggestedOptions={machinesShown.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))}
|
||||
allowDuplicates={false}
|
||||
restrictTagsToAutocompleteOptions
|
||||
sortTags
|
||||
/>
|
||||
</>
|
||||
// <MultiSelectTags
|
||||
// emptyPlaceholder={t("machineNotFound")}
|
||||
// searchPlaceholder={t("machineSearch")}
|
||||
// value={selectedMachines.map((m) => ({
|
||||
// ...m,
|
||||
// text: m.name,
|
||||
// id: m.clientId.toString()
|
||||
// }))}
|
||||
// onChange={(values) => {
|
||||
// onSelectMachines(values);
|
||||
// }}
|
||||
// options={machinesShown.map((m) => ({
|
||||
// ...m,
|
||||
// id: m.clientId.toString(),
|
||||
// text: m.name
|
||||
// }))}
|
||||
// onSearch={setMachineSearchQuery}
|
||||
// searchQuery={machineSearchQuery}
|
||||
// />
|
||||
|
||||
// <Command shouldFilter={false}>
|
||||
// <CommandInput
|
||||
// placeholder={t("machineSearch")}
|
||||
// value={machineSearchQuery}
|
||||
// onValueChange={setMachineSearchQuery}
|
||||
// />
|
||||
// <CommandList>
|
||||
// <CommandEmpty>{t("machineNotFound")}</CommandEmpty>
|
||||
// <CommandGroup>
|
||||
// {machinesShown.map((m) => (
|
||||
// <CommandItem
|
||||
// value={`${m.name}:${m.clientId}`}
|
||||
// key={m.clientId}
|
||||
// onSelect={() => {
|
||||
// let newMachineClients = [];
|
||||
// if (selectedMachinesIds.has(m.clientId)) {
|
||||
// newMachineClients = selectedMachines.filter(
|
||||
// (mc) => mc.clientId !== m.clientId
|
||||
// );
|
||||
// } else {
|
||||
// newMachineClients = [
|
||||
// ...selectedMachines,
|
||||
// m
|
||||
// ];
|
||||
// }
|
||||
// onSelectMachines(newMachineClients);
|
||||
// }}
|
||||
// >
|
||||
// <CheckIcon
|
||||
// className={cn(
|
||||
// "mr-2 h-4 w-4",
|
||||
// selectedMachinesIds.has(m.clientId)
|
||||
// ? "opacity-100"
|
||||
// : "opacity-0"
|
||||
// )}
|
||||
// />
|
||||
// {`${m.name}`}
|
||||
// </CommandItem>
|
||||
// ))}
|
||||
// </CommandGroup>
|
||||
// </CommandList>
|
||||
// </Command>
|
||||
<SuggestionsTagInput
|
||||
{...props}
|
||||
activeTagIndex={activeTagIndex}
|
||||
setActiveTagIndex={setActiveTagIndex}
|
||||
placeholder={t("accessClientSelect")}
|
||||
tags={selectedMachines.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))}
|
||||
setTags={(newTags) => {
|
||||
const tags =
|
||||
typeof newTags === "function"
|
||||
? newTags(
|
||||
selectedMachines.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))
|
||||
)
|
||||
: newTags;
|
||||
onSelectMachines(
|
||||
tags.map((tag) => ({
|
||||
clientId: Number(tag.id),
|
||||
name: tag.text
|
||||
}))
|
||||
);
|
||||
}}
|
||||
searchQuery={machineSearchQuery}
|
||||
onSearchQueryChange={setMachineSearchQuery}
|
||||
suggestedOptions={machinesShown.map((mc) => ({
|
||||
id: mc.clientId.toString(),
|
||||
text: mc.name
|
||||
}))}
|
||||
allowDuplicates={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -41,9 +41,6 @@ type AutocompleteProps = {
|
||||
usePortal?: boolean;
|
||||
/** Narrows the dropdown list from the main field (cmdk search filters further). */
|
||||
filterQuery?: string;
|
||||
/** When true, skip internal filtering and make the CommandInput controlled — parent owns filtering. */
|
||||
disableSearch?: boolean;
|
||||
onFilterQueryChange?: (value: string) => void;
|
||||
};
|
||||
|
||||
export const Autocomplete: React.FC<AutocompleteProps> = ({
|
||||
@@ -60,9 +57,7 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
||||
children,
|
||||
classStyleProps,
|
||||
usePortal,
|
||||
filterQuery = "",
|
||||
disableSearch = false,
|
||||
onFilterQueryChange
|
||||
filterQuery = ""
|
||||
}) => {
|
||||
const triggerContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
@@ -75,13 +70,12 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
||||
const [commandResetKey, setCommandResetKey] = useState(0);
|
||||
|
||||
const visibleOptions = useMemo(() => {
|
||||
if (disableSearch) return autocompleteOptions;
|
||||
const q = filterQuery.trim().toLowerCase();
|
||||
if (!q) return autocompleteOptions;
|
||||
return autocompleteOptions.filter((option) =>
|
||||
option.text.toLowerCase().includes(q)
|
||||
);
|
||||
}, [autocompleteOptions, filterQuery, disableSearch]);
|
||||
}, [autocompleteOptions, filterQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPopoverOpen) {
|
||||
@@ -281,25 +275,15 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
||||
>
|
||||
<Command
|
||||
key={commandResetKey}
|
||||
shouldFilter={!disableSearch}
|
||||
className={cn(
|
||||
"rounded-lg border-0 shadow-none",
|
||||
classStyleProps?.command
|
||||
)}
|
||||
>
|
||||
{disableSearch ? (
|
||||
<CommandInput
|
||||
placeholder={t("searchPlaceholder")}
|
||||
className="h-9"
|
||||
value={filterQuery}
|
||||
onValueChange={onFilterQueryChange}
|
||||
/>
|
||||
) : (
|
||||
<CommandInput
|
||||
placeholder={t("searchPlaceholder")}
|
||||
className="h-9"
|
||||
/>
|
||||
)}
|
||||
<CommandInput
|
||||
placeholder={t("searchPlaceholder")}
|
||||
className="h-9"
|
||||
/>
|
||||
<CommandList
|
||||
className={cn(
|
||||
"max-h-[300px]",
|
||||
|
||||
266
src/components/tags/suggestions-tag-input.tsx
Normal file
266
src/components/tags/suggestions-tag-input.tsx
Normal file
@@ -0,0 +1,266 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { type VariantProps } from "class-variance-authority";
|
||||
import { Check } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from "@app/components/ui/command";
|
||||
import {
|
||||
Popover,
|
||||
PopoverAnchor,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@app/components/ui/popover";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import { cn } from "@app/lib/cn";
|
||||
import { tagVariants } from "./tag";
|
||||
import { TagList } from "./tag-list";
|
||||
import type { Tag, TagInputStyleClassesProps } from "./tag-input";
|
||||
|
||||
export type SuggestionsTagInputProps = {
|
||||
tags: Tag[];
|
||||
setTags: React.Dispatch<React.SetStateAction<Tag[]>>;
|
||||
suggestedOptions: Tag[];
|
||||
searchQuery: string;
|
||||
onSearchQueryChange: (value: string) => void;
|
||||
activeTagIndex: number | null;
|
||||
setActiveTagIndex: React.Dispatch<React.SetStateAction<number | null>>;
|
||||
placeholder?: string;
|
||||
maxTags?: number;
|
||||
onTagAdd?: (tag: string) => void;
|
||||
onTagRemove?: (tag: string) => void;
|
||||
allowDuplicates?: boolean;
|
||||
disabled?: boolean;
|
||||
usePortal?: boolean;
|
||||
styleClasses?: TagInputStyleClassesProps;
|
||||
} & VariantProps<typeof tagVariants>;
|
||||
|
||||
export function SuggestionsTagInput({
|
||||
tags,
|
||||
setTags,
|
||||
suggestedOptions,
|
||||
searchQuery,
|
||||
onSearchQueryChange,
|
||||
activeTagIndex,
|
||||
setActiveTagIndex,
|
||||
placeholder,
|
||||
maxTags,
|
||||
onTagAdd,
|
||||
onTagRemove,
|
||||
allowDuplicates = false,
|
||||
disabled = false,
|
||||
usePortal = false,
|
||||
styleClasses = {},
|
||||
variant,
|
||||
size,
|
||||
shape,
|
||||
borderStyle,
|
||||
textCase,
|
||||
interaction,
|
||||
animation,
|
||||
textStyle
|
||||
}: SuggestionsTagInputProps) {
|
||||
const t = useTranslations();
|
||||
const triggerRef = useRef<HTMLDivElement | null>(null);
|
||||
const popoverContentRef = useRef<HTMLDivElement | null>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [popoverWidth, setPopoverWidth] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const handleOutsideClick = (event: MouseEvent | TouchEvent) => {
|
||||
if (
|
||||
isOpen &&
|
||||
triggerRef.current &&
|
||||
popoverContentRef.current &&
|
||||
!triggerRef.current.contains(event.target as Node) &&
|
||||
!popoverContentRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
document.addEventListener("mousedown", handleOutsideClick);
|
||||
return () =>
|
||||
document.removeEventListener("mousedown", handleOutsideClick);
|
||||
}, [isOpen]);
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
if (open && triggerRef.current) {
|
||||
setPopoverWidth(triggerRef.current.getBoundingClientRect().width);
|
||||
}
|
||||
if (open) setIsOpen(true);
|
||||
};
|
||||
|
||||
const toggleTag = (option: Tag) => {
|
||||
const index = tags.findIndex((tag) => tag.text === option.text);
|
||||
if (index >= 0) {
|
||||
setTags(tags.filter((_, i) => i !== index));
|
||||
onTagRemove?.(option.text);
|
||||
} else {
|
||||
if (
|
||||
!allowDuplicates &&
|
||||
tags.some((tag) => tag.text === option.text)
|
||||
)
|
||||
return;
|
||||
if (!maxTags || tags.length < maxTags) {
|
||||
setTags([...tags, option]);
|
||||
onTagAdd?.(option.text);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const removeTag = (idToRemove: string) => {
|
||||
const removed = tags.find((tag) => tag.id === idToRemove);
|
||||
setTags(tags.filter((tag) => tag.id !== idToRemove));
|
||||
if (removed) onTagRemove?.(removed.text);
|
||||
};
|
||||
|
||||
const onSortEnd = (oldIndex: number, newIndex: number) => {
|
||||
setTags((current) => {
|
||||
const next = [...current];
|
||||
const [moved] = next.splice(oldIndex, 1);
|
||||
next.splice(newIndex, 0, moved);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover open={isOpen} onOpenChange={handleOpenChange} modal={usePortal}>
|
||||
<PopoverAnchor asChild>
|
||||
<div
|
||||
ref={triggerRef}
|
||||
className={cn(
|
||||
"flex flex-row flex-wrap items-center gap-1.5 p-1.5 w-full rounded-md border border-input text-sm bg-transparent pr-1",
|
||||
styleClasses?.inlineTagsContainer
|
||||
)}
|
||||
>
|
||||
<TagList
|
||||
tags={tags}
|
||||
variant={variant}
|
||||
size={size}
|
||||
shape={shape}
|
||||
borderStyle={borderStyle}
|
||||
textCase={textCase}
|
||||
interaction={interaction}
|
||||
animation={animation}
|
||||
textStyle={textStyle}
|
||||
onRemoveTag={removeTag}
|
||||
onSortEnd={onSortEnd}
|
||||
inlineTags
|
||||
activeTagIndex={activeTagIndex}
|
||||
setActiveTagIndex={setActiveTagIndex}
|
||||
classStyleProps={{
|
||||
tagListClasses: styleClasses?.tagList,
|
||||
tagClasses: styleClasses?.tag
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
role="combobox"
|
||||
type="button"
|
||||
disabled={
|
||||
disabled ||
|
||||
(maxTags !== undefined &&
|
||||
tags.length >= maxTags)
|
||||
}
|
||||
className={cn(
|
||||
"hover:bg-transparent ml-auto",
|
||||
styleClasses?.autoComplete?.popoverTrigger
|
||||
)}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={`lucide lucide-chevron-down h-4 w-4 shrink-0 opacity-50 transition-transform ${isOpen ? "rotate-180" : "rotate-0"}`}
|
||||
>
|
||||
<path d="m6 9 6 6 6-6" />
|
||||
</svg>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
</div>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent
|
||||
ref={popoverContentRef}
|
||||
side="bottom"
|
||||
align="start"
|
||||
forceMount
|
||||
className={cn("p-0", styleClasses?.autoComplete?.popoverContent)}
|
||||
style={{
|
||||
width: `${popoverWidth}px`,
|
||||
minWidth: `${popoverWidth}px`,
|
||||
zIndex: 9999
|
||||
}}
|
||||
>
|
||||
<Command
|
||||
shouldFilter={false}
|
||||
className={cn(
|
||||
"rounded-lg border-0 shadow-none",
|
||||
styleClasses?.autoComplete?.command
|
||||
)}
|
||||
>
|
||||
<CommandInput
|
||||
placeholder={placeholder ?? t("searchPlaceholder")}
|
||||
className="h-9"
|
||||
value={searchQuery}
|
||||
onValueChange={onSearchQueryChange}
|
||||
/>
|
||||
<CommandList
|
||||
className={cn(
|
||||
"max-h-[300px]",
|
||||
styleClasses?.autoComplete?.commandList
|
||||
)}
|
||||
>
|
||||
<CommandEmpty>{t("noResults")}</CommandEmpty>
|
||||
<CommandGroup
|
||||
className={styleClasses?.autoComplete?.commandGroup}
|
||||
>
|
||||
{suggestedOptions.map((option) => {
|
||||
const isChosen = tags.some(
|
||||
(tag) => tag.text === option.text
|
||||
);
|
||||
return (
|
||||
<CommandItem
|
||||
key={option.id}
|
||||
value={`${option.text} ${option.id}`}
|
||||
onSelect={() => toggleTag(option)}
|
||||
className={
|
||||
styleClasses?.autoComplete
|
||||
?.commandItem
|
||||
}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 shrink-0",
|
||||
isChosen
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{option.text}
|
||||
</CommandItem>
|
||||
);
|
||||
})}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -88,7 +88,6 @@ export interface TagInputProps
|
||||
searchQuery?: string;
|
||||
onSearchQueryChange?: (value: string) => void;
|
||||
autocompleteContent?: React.ReactNode;
|
||||
suggestedOptions?: Tag[];
|
||||
customTagRenderer?: (tag: Tag, isActiveTag: boolean) => React.ReactNode;
|
||||
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
||||
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
||||
@@ -164,8 +163,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
generateTagId = uuid,
|
||||
searchQuery,
|
||||
onSearchQueryChange,
|
||||
autocompleteContent,
|
||||
suggestedOptions
|
||||
autocompleteContent
|
||||
} = props;
|
||||
|
||||
const [inputValue, setInputValue] = React.useState("");
|
||||
@@ -196,7 +194,6 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
}
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (suggestedOptions !== undefined) return;
|
||||
const newValue = e.target.value;
|
||||
if (addOnPaste && newValue.includes(delimiter)) {
|
||||
const splitValues = newValue
|
||||
@@ -440,14 +437,6 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
onClearAll?.();
|
||||
};
|
||||
|
||||
const mainInputValue =
|
||||
suggestedOptions !== undefined ? "" : effectiveQuery;
|
||||
|
||||
const useAutocompleteComponent =
|
||||
enableAutocomplete || suggestedOptions !== undefined;
|
||||
const resolvedAutocompleteOptions = suggestedOptions ?? autocompleteOptions;
|
||||
const disableAutocompleteSearch = suggestedOptions !== undefined;
|
||||
|
||||
const displayedTags = sortTags ? [...tags].sort() : tags;
|
||||
|
||||
const truncatedTags = truncate
|
||||
@@ -500,7 +489,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
disabled={disabled}
|
||||
/>
|
||||
) : (
|
||||
!useAutocompleteComponent && !autocompleteContent && (
|
||||
!enableAutocomplete && !autocompleteContent && (
|
||||
<div className="w-full">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -543,7 +532,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -572,7 +561,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
{!useAutocompleteComponent && autocompleteContent && (
|
||||
{!enableAutocomplete && autocompleteContent && (
|
||||
<div className="w-full">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -614,7 +603,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -634,22 +623,16 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
{autocompleteContent}
|
||||
</div>
|
||||
)}
|
||||
{useAutocompleteComponent ? (
|
||||
{enableAutocomplete ? (
|
||||
<div className="w-full">
|
||||
<Autocomplete
|
||||
tags={tags}
|
||||
setTags={setTags}
|
||||
setInputValue={updateQuery}
|
||||
autocompleteOptions={
|
||||
(resolvedAutocompleteOptions || []) as Tag[]
|
||||
(autocompleteOptions || []) as Tag[]
|
||||
}
|
||||
filterQuery={effectiveQuery}
|
||||
disableSearch={disableAutocompleteSearch}
|
||||
onFilterQueryChange={
|
||||
disableAutocompleteSearch
|
||||
? onSearchQueryChange
|
||||
: undefined
|
||||
}
|
||||
setTagCount={setTagCount}
|
||||
maxTags={maxTags}
|
||||
onTagAdd={onTagAdd}
|
||||
@@ -675,7 +658,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
// <CommandInput
|
||||
// placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||
// ref={inputRef}
|
||||
// value={mainInputValue}
|
||||
// value={effectiveQuery}
|
||||
// disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||
// onChangeCapture={handleInputChange}
|
||||
// onKeyDown={handleKeyDown}
|
||||
@@ -697,7 +680,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -758,7 +741,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
{/* <CommandInput
|
||||
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||
ref={inputRef}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||
onChangeCapture={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
@@ -781,7 +764,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -837,7 +820,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
{/* <CommandInput
|
||||
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||
ref={inputRef}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||
onChangeCapture={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
@@ -859,7 +842,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -902,7 +885,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
@@ -962,7 +945,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
||||
? placeholderWhenFull
|
||||
: placeholder
|
||||
}
|
||||
value={mainInputValue}
|
||||
value={effectiveQuery}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
onFocus={handleInputFocus}
|
||||
|
||||
Reference in New Issue
Block a user