mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-11 23:04:59 +00:00
🚧 wip
This commit is contained in:
@@ -1572,7 +1572,22 @@ export function InternalResourceForm({
|
|||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("machineClients")}
|
{t("machineClients")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<Popover>
|
<MachinesSelector
|
||||||
|
{...field}
|
||||||
|
selectedMachines={
|
||||||
|
field.value ?? []
|
||||||
|
}
|
||||||
|
orgId={orgId}
|
||||||
|
onSelectMachines={(
|
||||||
|
machines
|
||||||
|
) => {
|
||||||
|
form.setValue(
|
||||||
|
"clients",
|
||||||
|
machines
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* <Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
@@ -1638,7 +1653,7 @@ export function InternalResourceForm({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover> */}
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useDebounce } from "use-debounce";
|
|||||||
|
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { MultiSelectTags } from "./multi-select/multi-select-tags";
|
import { MultiSelectTags } from "./multi-select/multi-select-tags";
|
||||||
|
import { TagInput, type TagInputProps } from "./tags/tag-input";
|
||||||
|
|
||||||
export type SelectedMachine = Pick<
|
export type SelectedMachine = Pick<
|
||||||
ListClientsResponse["clients"][number],
|
ListClientsResponse["clients"][number],
|
||||||
@@ -16,12 +17,27 @@ export type MachineSelectorProps = {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
selectedMachines?: SelectedMachine[];
|
selectedMachines?: SelectedMachine[];
|
||||||
onSelectMachines: (machine: SelectedMachine[]) => void;
|
onSelectMachines: (machine: SelectedMachine[]) => void;
|
||||||
};
|
} & Omit<
|
||||||
|
TagInputProps,
|
||||||
|
| "activeTagIndex"
|
||||||
|
| "setActiveTagIndex"
|
||||||
|
| "placeholder"
|
||||||
|
| "size"
|
||||||
|
| "tags"
|
||||||
|
| "setTags"
|
||||||
|
| "value"
|
||||||
|
| "searchQuery"
|
||||||
|
| "onSearchQueryChange"
|
||||||
|
| "suggestedOptions"
|
||||||
|
| "enableAutocomplete"
|
||||||
|
| "autocompleteOptions"
|
||||||
|
>;
|
||||||
|
|
||||||
export function MachinesSelector({
|
export function MachinesSelector({
|
||||||
orgId,
|
orgId,
|
||||||
selectedMachines = [],
|
selectedMachines = [],
|
||||||
onSelectMachines
|
onSelectMachines,
|
||||||
|
...props
|
||||||
}: MachineSelectorProps) {
|
}: MachineSelectorProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
const [machineSearchQuery, setMachineSearchQuery] = useState("");
|
const [machineSearchQuery, setMachineSearchQuery] = useState("");
|
||||||
@@ -29,7 +45,7 @@ export function MachinesSelector({
|
|||||||
const [debouncedValue] = useDebounce(machineSearchQuery, 150);
|
const [debouncedValue] = useDebounce(machineSearchQuery, 150);
|
||||||
|
|
||||||
const { data: machines = [] } = useQuery(
|
const { data: machines = [] } = useQuery(
|
||||||
orgQueries.machineClients({ orgId, perPage: 10, query: debouncedValue })
|
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 of machines shown (if the user isn't searching)
|
||||||
@@ -52,26 +68,68 @@ export function MachinesSelector({
|
|||||||
// selectedMachines.map((m) => m.clientId)
|
// selectedMachines.map((m) => m.clientId)
|
||||||
// );
|
// );
|
||||||
|
|
||||||
|
const [activeTagIndex, setActiveTagIndex] = useState<number | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MultiSelectTags
|
<>
|
||||||
emptyPlaceholder={t("machineNotFound")}
|
<TagInput
|
||||||
searchPlaceholder={t("machineSearch")}
|
{...props}
|
||||||
value={selectedMachines.map((m) => ({
|
activeTagIndex={activeTagIndex}
|
||||||
...m,
|
setActiveTagIndex={setActiveTagIndex}
|
||||||
text: m.name,
|
placeholder={t("accessClientSelect")}
|
||||||
id: m.clientId.toString()
|
size="sm"
|
||||||
}))}
|
tags={selectedMachines.map((mc) => ({
|
||||||
onChange={(values) => {
|
id: mc.clientId.toString(),
|
||||||
onSelectMachines(values);
|
text: mc.name
|
||||||
}}
|
}))}
|
||||||
options={machinesShown.map((m) => ({
|
setTags={(newTags) => {
|
||||||
...m,
|
const tags =
|
||||||
id: m.clientId.toString(),
|
typeof newTags === "function"
|
||||||
text: m.name
|
? newTags(
|
||||||
}))}
|
selectedMachines.map((mc) => ({
|
||||||
onSearch={setMachineSearchQuery}
|
id: mc.clientId.toString(),
|
||||||
searchQuery={machineSearchQuery}
|
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}>
|
// <Command shouldFilter={false}>
|
||||||
// <CommandInput
|
// <CommandInput
|
||||||
// placeholder={t("machineSearch")}
|
// placeholder={t("machineSearch")}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from "react";
|
||||||
import { TagInputStyleClassesProps, type Tag as TagType } from "./tag-input";
|
import { TagInputStyleClassesProps, type Tag as TagType } from "./tag-input";
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
@@ -35,6 +41,9 @@ type AutocompleteProps = {
|
|||||||
usePortal?: boolean;
|
usePortal?: boolean;
|
||||||
/** Narrows the dropdown list from the main field (cmdk search filters further). */
|
/** Narrows the dropdown list from the main field (cmdk search filters further). */
|
||||||
filterQuery?: string;
|
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> = ({
|
export const Autocomplete: React.FC<AutocompleteProps> = ({
|
||||||
@@ -51,7 +60,9 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
children,
|
children,
|
||||||
classStyleProps,
|
classStyleProps,
|
||||||
usePortal,
|
usePortal,
|
||||||
filterQuery = ""
|
filterQuery = "",
|
||||||
|
disableSearch = false,
|
||||||
|
onFilterQueryChange
|
||||||
}) => {
|
}) => {
|
||||||
const triggerContainerRef = useRef<HTMLDivElement | null>(null);
|
const triggerContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
@@ -64,12 +75,13 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
const [commandResetKey, setCommandResetKey] = useState(0);
|
const [commandResetKey, setCommandResetKey] = useState(0);
|
||||||
|
|
||||||
const visibleOptions = useMemo(() => {
|
const visibleOptions = useMemo(() => {
|
||||||
|
if (disableSearch) return autocompleteOptions;
|
||||||
const q = filterQuery.trim().toLowerCase();
|
const q = filterQuery.trim().toLowerCase();
|
||||||
if (!q) return autocompleteOptions;
|
if (!q) return autocompleteOptions;
|
||||||
return autocompleteOptions.filter((option) =>
|
return autocompleteOptions.filter((option) =>
|
||||||
option.text.toLowerCase().includes(q)
|
option.text.toLowerCase().includes(q)
|
||||||
);
|
);
|
||||||
}, [autocompleteOptions, filterQuery]);
|
}, [autocompleteOptions, filterQuery, disableSearch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isPopoverOpen) {
|
if (isPopoverOpen) {
|
||||||
@@ -220,7 +232,7 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
>
|
>
|
||||||
<PopoverAnchor asChild>
|
<PopoverAnchor asChild>
|
||||||
<div
|
<div
|
||||||
className="relative h-full flex items-center rounded-md border border-input bg-transparent pr-3"
|
className="relative h-full flex items-center rounded-md border border-input bg-transparent pr-1"
|
||||||
ref={triggerContainerRef}
|
ref={triggerContainerRef}
|
||||||
>
|
>
|
||||||
{childrenWithProps}
|
{childrenWithProps}
|
||||||
@@ -260,10 +272,7 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
side="bottom"
|
side="bottom"
|
||||||
align="start"
|
align="start"
|
||||||
forceMount
|
forceMount
|
||||||
className={cn(
|
className={cn("p-0", classStyleProps?.popoverContent)}
|
||||||
"p-0",
|
|
||||||
classStyleProps?.popoverContent
|
|
||||||
)}
|
|
||||||
style={{
|
style={{
|
||||||
width: `${popoverWidth}px`,
|
width: `${popoverWidth}px`,
|
||||||
minWidth: `${popoverWidth}px`,
|
minWidth: `${popoverWidth}px`,
|
||||||
@@ -272,15 +281,25 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
>
|
>
|
||||||
<Command
|
<Command
|
||||||
key={commandResetKey}
|
key={commandResetKey}
|
||||||
|
shouldFilter={!disableSearch}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-lg border-0 shadow-none",
|
"rounded-lg border-0 shadow-none",
|
||||||
classStyleProps?.command
|
classStyleProps?.command
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<CommandInput
|
{disableSearch ? (
|
||||||
placeholder={t("searchPlaceholder")}
|
<CommandInput
|
||||||
className="h-9"
|
placeholder={t("searchPlaceholder")}
|
||||||
/>
|
className="h-9"
|
||||||
|
value={filterQuery}
|
||||||
|
onValueChange={onFilterQueryChange}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CommandInput
|
||||||
|
placeholder={t("searchPlaceholder")}
|
||||||
|
className="h-9"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<CommandList
|
<CommandList
|
||||||
className={cn(
|
className={cn(
|
||||||
"max-h-[300px]",
|
"max-h-[300px]",
|
||||||
@@ -300,7 +319,9 @@ export const Autocomplete: React.FC<AutocompleteProps> = ({
|
|||||||
key={option.id}
|
key={option.id}
|
||||||
value={`${option.text} ${option.id}`}
|
value={`${option.text} ${option.id}`}
|
||||||
onSelect={() => toggleTag(option)}
|
onSelect={() => toggleTag(option)}
|
||||||
className={classStyleProps?.commandItem}
|
className={
|
||||||
|
classStyleProps?.commandItem
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Check
|
<Check
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ export interface TagInputProps
|
|||||||
autocompleteFilter?: (option: string) => boolean;
|
autocompleteFilter?: (option: string) => boolean;
|
||||||
direction?: "row" | "column";
|
direction?: "row" | "column";
|
||||||
onInputChange?: (value: string) => void;
|
onInputChange?: (value: string) => void;
|
||||||
|
searchQuery?: string;
|
||||||
|
onSearchQueryChange?: (value: string) => void;
|
||||||
|
autocompleteContent?: React.ReactNode;
|
||||||
|
suggestedOptions?: Tag[];
|
||||||
customTagRenderer?: (tag: Tag, isActiveTag: boolean) => React.ReactNode;
|
customTagRenderer?: (tag: Tag, isActiveTag: boolean) => React.ReactNode;
|
||||||
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
onFocus?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
onBlur?: React.FocusEventHandler<HTMLInputElement>;
|
||||||
@@ -157,10 +161,26 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
disabled = false,
|
disabled = false,
|
||||||
usePortal = false,
|
usePortal = false,
|
||||||
addOnPaste = false,
|
addOnPaste = false,
|
||||||
generateTagId = uuid
|
generateTagId = uuid,
|
||||||
|
searchQuery,
|
||||||
|
onSearchQueryChange,
|
||||||
|
autocompleteContent,
|
||||||
|
suggestedOptions
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [inputValue, setInputValue] = React.useState("");
|
const [inputValue, setInputValue] = React.useState("");
|
||||||
|
const isControlled = searchQuery !== undefined;
|
||||||
|
const effectiveQuery = isControlled ? searchQuery : inputValue;
|
||||||
|
|
||||||
|
const updateQuery = React.useCallback(
|
||||||
|
(action: React.SetStateAction<string>) => {
|
||||||
|
const resolved =
|
||||||
|
typeof action === "function" ? action(effectiveQuery) : action;
|
||||||
|
if (!isControlled) setInputValue(resolved);
|
||||||
|
onSearchQueryChange?.(resolved);
|
||||||
|
},
|
||||||
|
[isControlled, effectiveQuery, onSearchQueryChange]
|
||||||
|
);
|
||||||
const [tagCount, setTagCount] = React.useState(Math.max(0, tags.length));
|
const [tagCount, setTagCount] = React.useState(Math.max(0, tags.length));
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
@@ -176,6 +196,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (suggestedOptions !== undefined) return;
|
||||||
const newValue = e.target.value;
|
const newValue = e.target.value;
|
||||||
if (addOnPaste && newValue.includes(delimiter)) {
|
if (addOnPaste && newValue.includes(delimiter)) {
|
||||||
const splitValues = newValue
|
const splitValues = newValue
|
||||||
@@ -234,9 +255,9 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setInputValue("");
|
updateQuery("");
|
||||||
} else {
|
} else {
|
||||||
setInputValue(newValue);
|
updateQuery(newValue);
|
||||||
}
|
}
|
||||||
onInputChange?.(newValue);
|
onInputChange?.(newValue);
|
||||||
};
|
};
|
||||||
@@ -247,8 +268,8 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
const handleInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {
|
||||||
if (addTagsOnBlur && inputValue.trim()) {
|
if (addTagsOnBlur && effectiveQuery.trim()) {
|
||||||
const newTagText = inputValue.trim();
|
const newTagText = effectiveQuery.trim();
|
||||||
|
|
||||||
if (validateTag && !validateTag(newTagText)) {
|
if (validateTag && !validateTag(newTagText)) {
|
||||||
return;
|
return;
|
||||||
@@ -273,7 +294,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
setTags([...tags, { id: newTagId, text: newTagText }]);
|
setTags([...tags, { id: newTagId, text: newTagText }]);
|
||||||
onTagAdd?.(newTagText);
|
onTagAdd?.(newTagText);
|
||||||
setTagCount((prevTagCount) => prevTagCount + 1);
|
setTagCount((prevTagCount) => prevTagCount + 1);
|
||||||
setInputValue("");
|
updateQuery("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +308,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
: e.key === delimiter || e.key === Delimiter.Enter
|
: e.key === delimiter || e.key === Delimiter.Enter
|
||||||
) {
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const newTagText = inputValue.trim();
|
const newTagText = effectiveQuery.trim();
|
||||||
|
|
||||||
// Check if the tag is in the autocomplete options if restrictTagsToAutocomplete is true
|
// Check if the tag is in the autocomplete options if restrictTagsToAutocomplete is true
|
||||||
if (
|
if (
|
||||||
@@ -329,7 +350,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
onTagAdd?.(newTagText);
|
onTagAdd?.(newTagText);
|
||||||
setTagCount((prevTagCount) => prevTagCount + 1);
|
setTagCount((prevTagCount) => prevTagCount + 1);
|
||||||
}
|
}
|
||||||
setInputValue("");
|
updateQuery("");
|
||||||
} else {
|
} else {
|
||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case "Delete":
|
case "Delete":
|
||||||
@@ -419,9 +440,14 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
onClearAll?.();
|
onClearAll?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
// const filteredAutocompleteOptions = autocompleteFilter
|
const mainInputValue =
|
||||||
// ? autocompleteOptions?.filter((option) => autocompleteFilter(option.text))
|
suggestedOptions !== undefined ? "" : effectiveQuery;
|
||||||
// : autocompleteOptions;
|
|
||||||
|
const useAutocompleteComponent =
|
||||||
|
enableAutocomplete || suggestedOptions !== undefined;
|
||||||
|
const resolvedAutocompleteOptions = suggestedOptions ?? autocompleteOptions;
|
||||||
|
const disableAutocompleteSearch = suggestedOptions !== undefined;
|
||||||
|
|
||||||
const displayedTags = sortTags ? [...tags].sort() : tags;
|
const displayedTags = sortTags ? [...tags].sort() : tags;
|
||||||
|
|
||||||
const truncatedTags = truncate
|
const truncatedTags = truncate
|
||||||
@@ -436,13 +462,15 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`w-full flex ${!inlineTags && tags.length > 0 ? "gap-3" : ""} ${
|
className={cn(
|
||||||
|
`w-full flex`,
|
||||||
|
!inlineTags && tags.length > 0 && "gap-3",
|
||||||
inputFieldPosition === "bottom"
|
inputFieldPosition === "bottom"
|
||||||
? "flex-col"
|
? "flex-col"
|
||||||
: inputFieldPosition === "top"
|
: inputFieldPosition === "top"
|
||||||
? "flex-col-reverse"
|
? "flex-col-reverse"
|
||||||
: "flex-row"
|
: "flex-row"
|
||||||
}`}
|
)}
|
||||||
>
|
>
|
||||||
{!usePopoverForTags &&
|
{!usePopoverForTags &&
|
||||||
(!inlineTags ? (
|
(!inlineTags ? (
|
||||||
@@ -472,7 +500,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
!enableAutocomplete && (
|
!useAutocompleteComponent && !autocompleteContent && (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -515,14 +543,14 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
"border-0 px-2 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
||||||
// className,
|
// className,
|
||||||
styleClasses?.input
|
styleClasses?.input
|
||||||
)}
|
)}
|
||||||
@@ -544,16 +572,84 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
))}
|
))}
|
||||||
{enableAutocomplete ? (
|
{!useAutocompleteComponent && autocompleteContent && (
|
||||||
|
<div className="w-full">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
`flex flex-row flex-wrap items-center gap-1.5 p-1.5 w-full rounded-md border border-input text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-50`,
|
||||||
|
styleClasses?.inlineTagsContainer
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<TagList
|
||||||
|
tags={truncatedTags}
|
||||||
|
customTagRenderer={customTagRenderer}
|
||||||
|
variant={variant}
|
||||||
|
size={size}
|
||||||
|
shape={shape}
|
||||||
|
borderStyle={borderStyle}
|
||||||
|
textCase={textCase}
|
||||||
|
interaction={interaction}
|
||||||
|
animation={animation}
|
||||||
|
textStyle={textStyle}
|
||||||
|
onTagClick={onTagClick}
|
||||||
|
draggable={draggable}
|
||||||
|
onSortEnd={onSortEnd}
|
||||||
|
onRemoveTag={removeTag}
|
||||||
|
direction={direction}
|
||||||
|
inlineTags={inlineTags}
|
||||||
|
activeTagIndex={activeTagIndex}
|
||||||
|
setActiveTagIndex={setActiveTagIndex}
|
||||||
|
classStyleProps={{
|
||||||
|
tagListClasses: styleClasses?.tagList,
|
||||||
|
tagClasses: styleClasses?.tag
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
ref={inputRef}
|
||||||
|
id={id}
|
||||||
|
type="text"
|
||||||
|
placeholder={
|
||||||
|
maxTags !== undefined && tags.length >= maxTags
|
||||||
|
? placeholderWhenFull
|
||||||
|
: placeholder
|
||||||
|
}
|
||||||
|
value={mainInputValue}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onFocus={handleInputFocus}
|
||||||
|
onBlur={handleInputBlur}
|
||||||
|
{...inputProps}
|
||||||
|
className={cn(
|
||||||
|
"border-0 px-2 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
||||||
|
styleClasses?.input
|
||||||
|
)}
|
||||||
|
autoComplete="off"
|
||||||
|
disabled={
|
||||||
|
disabled ||
|
||||||
|
(maxTags !== undefined && tags.length >= maxTags)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{autocompleteContent}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{useAutocompleteComponent ? (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
tags={tags}
|
tags={tags}
|
||||||
setTags={setTags}
|
setTags={setTags}
|
||||||
setInputValue={setInputValue}
|
setInputValue={updateQuery}
|
||||||
autocompleteOptions={
|
autocompleteOptions={
|
||||||
(autocompleteOptions || []) as Tag[]
|
(resolvedAutocompleteOptions || []) as Tag[]
|
||||||
|
}
|
||||||
|
filterQuery={effectiveQuery}
|
||||||
|
disableSearch={disableAutocompleteSearch}
|
||||||
|
onFilterQueryChange={
|
||||||
|
disableAutocompleteSearch
|
||||||
|
? onSearchQueryChange
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
filterQuery={inputValue}
|
|
||||||
setTagCount={setTagCount}
|
setTagCount={setTagCount}
|
||||||
maxTags={maxTags}
|
maxTags={maxTags}
|
||||||
onTagAdd={onTagAdd}
|
onTagAdd={onTagAdd}
|
||||||
@@ -579,7 +675,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
// <CommandInput
|
// <CommandInput
|
||||||
// placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
// placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||||
// ref={inputRef}
|
// ref={inputRef}
|
||||||
// value={inputValue}
|
// value={mainInputValue}
|
||||||
// disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
// disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||||
// onChangeCapture={handleInputChange}
|
// onChangeCapture={handleInputChange}
|
||||||
// onKeyDown={handleKeyDown}
|
// onKeyDown={handleKeyDown}
|
||||||
@@ -601,7 +697,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
@@ -662,7 +758,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
{/* <CommandInput
|
{/* <CommandInput
|
||||||
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||||
onChangeCapture={handleInputChange}
|
onChangeCapture={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
@@ -685,14 +781,14 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
"border-0 px-2 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
||||||
// className,
|
// className,
|
||||||
styleClasses?.input
|
styleClasses?.input
|
||||||
)}
|
)}
|
||||||
@@ -741,7 +837,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
{/* <CommandInput
|
{/* <CommandInput
|
||||||
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
placeholder={maxTags !== undefined && tags.length >= maxTags ? placeholderWhenFull : placeholder}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)}
|
||||||
onChangeCapture={handleInputChange}
|
onChangeCapture={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
@@ -763,14 +859,14 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
{...inputProps}
|
{...inputProps}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-0 px-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
"border-0 px-2 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit shadow-none inset-shadow-none",
|
||||||
// className,
|
// className,
|
||||||
styleClasses?.input
|
styleClasses?.input
|
||||||
)}
|
)}
|
||||||
@@ -806,7 +902,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
@@ -866,7 +962,7 @@ export function TagInput({ ref, ...props }: TagInputProps) {
|
|||||||
? placeholderWhenFull
|
? placeholderWhenFull
|
||||||
: placeholder
|
: placeholder
|
||||||
}
|
}
|
||||||
value={inputValue}
|
value={mainInputValue}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
|
|||||||
Reference in New Issue
Block a user