diff --git a/src/app/[orgId]/settings/sites/SitesTable.tsx b/src/app/[orgId]/settings/sites/SitesTable.tsx index 0a30459c..c0cc5801 100644 --- a/src/app/[orgId]/settings/sites/SitesTable.tsx +++ b/src/app/[orgId]/settings/sites/SitesTable.tsx @@ -283,17 +283,46 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) { {selectedSite && ( deleteSite(selectedSite.id)} + setOpen={(val) => { + setIsDeleteModalOpen(val); + setSelectedSite(null); + }} + dialog={ +
+

+ Are you sure you want to remove the site{" "} + {selectedSite?.name || selectedSite?.id}{" "} + from the organization? +

+ +

+ Once removed, the site will no longer be + accessible.{" "} + + All resources and targets associated with + the site will also be removed. + +

+ +

+ To confirm, please type the name of the site + below. +

+
+ } + buttonText="Confirm Delete Site" + onConfirm={async () => deleteSite(selectedSite!.id)} + string={selectedSite.name} title="Delete Site" - description="Are you sure you want to delete this site? This action cannot be undone." /> )} router.push(`/${orgId}/settings/sites/create`)} + createSite={() => + router.push(`/${orgId}/settings/sites/create`) + } /> ); diff --git a/src/components/tags/autocomplete.tsx b/src/components/tags/autocomplete.tsx index 64efb5ec..db8d76c3 100644 --- a/src/components/tags/autocomplete.tsx +++ b/src/components/tags/autocomplete.tsx @@ -306,7 +306,7 @@ export const Autocomplete: React.FC = ({ role="option" aria-selected={isSelected} className={cn( - "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden aria-selected:bg-accent aria-selected:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 hover:bg-accent", + "relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 hover:bg-accent", isSelected && "bg-accent text-accent-foreground", classStyleProps?.commandItem diff --git a/src/components/tags/tag-input.tsx b/src/components/tags/tag-input.tsx index b50388f2..3510e968 100644 --- a/src/components/tags/tag-input.tsx +++ b/src/components/tags/tag-input.tsx @@ -105,93 +105,193 @@ export interface TagInputProps generateTagId?: () => string; } -const TagInput = ( - { - ref, - ...props - }: TagInputProps & { - ref: React.RefObject; - } -) => { - const { - id, - placeholder, - tags, - setTags, - variant, - size, - shape, - enableAutocomplete, - autocompleteOptions, - maxTags, - delimiter = Delimiter.Comma, - onTagAdd, - onTagRemove, - allowDuplicates, - showCount, - validateTag, - placeholderWhenFull = "Max tags reached", - sortTags, - delimiterList, - truncate, - autocompleteFilter, - borderStyle, - textCase, - interaction, - animation, - textStyle, - minLength, - maxLength, - direction = "row", - onInputChange, - customTagRenderer, - onFocus, - onBlur, - onTagClick, - draggable = false, - inputFieldPosition = "bottom", - clearAll = false, - onClearAll, - usePopoverForTags = false, - inputProps = {}, - restrictTagsToAutocompleteOptions, - inlineTags = true, - addTagsOnBlur = false, - activeTagIndex, - setActiveTagIndex, - styleClasses = {}, - disabled = false, - usePortal = false, - addOnPaste = false, - generateTagId = uuid - } = props; +const TagInput = React.forwardRef( + (props, ref) => { + const { + id, + placeholder, + tags, + setTags, + variant, + size, + shape, + enableAutocomplete, + autocompleteOptions, + maxTags, + delimiter = Delimiter.Comma, + onTagAdd, + onTagRemove, + allowDuplicates, + showCount, + validateTag, + placeholderWhenFull = "Max tags reached", + sortTags, + delimiterList, + truncate, + autocompleteFilter, + borderStyle, + textCase, + interaction, + animation, + textStyle, + minLength, + maxLength, + direction = "row", + onInputChange, + customTagRenderer, + onFocus, + onBlur, + onTagClick, + draggable = false, + inputFieldPosition = "bottom", + clearAll = false, + onClearAll, + usePopoverForTags = false, + inputProps = {}, + restrictTagsToAutocompleteOptions, + inlineTags = true, + addTagsOnBlur = false, + activeTagIndex, + setActiveTagIndex, + styleClasses = {}, + disabled = false, + usePortal = false, + addOnPaste = false, + generateTagId = uuid + } = props; - const [inputValue, setInputValue] = React.useState(""); - const [tagCount, setTagCount] = React.useState( - Math.max(0, tags.length) - ); - const inputRef = React.useRef(null); + const [inputValue, setInputValue] = React.useState(""); + const [tagCount, setTagCount] = React.useState( + Math.max(0, tags.length) + ); + const inputRef = React.useRef(null); - if ( - (maxTags !== undefined && maxTags < 0) || - (props.minTags !== undefined && props.minTags < 0) - ) { - console.warn("maxTags and minTags cannot be less than 0"); - // error - return null; - } + if ( + (maxTags !== undefined && maxTags < 0) || + (props.minTags !== undefined && props.minTags < 0) + ) { + console.warn("maxTags and minTags cannot be less than 0"); + // error + return null; + } - const handleInputChange = (e: React.ChangeEvent) => { - const newValue = e.target.value; - if (addOnPaste && newValue.includes(delimiter)) { - const splitValues = newValue - .split(delimiter) - .map((v) => v.trim()) - .filter((v) => v); - splitValues.forEach((value) => { - if (!value) return; // Skip empty strings from split + const handleInputChange = (e: React.ChangeEvent) => { + const newValue = e.target.value; + if (addOnPaste && newValue.includes(delimiter)) { + const splitValues = newValue + .split(delimiter) + .map((v) => v.trim()) + .filter((v) => v); + splitValues.forEach((value) => { + if (!value) return; // Skip empty strings from split - const newTagText = value.trim(); + const newTagText = value.trim(); + + // Check if the tag is in the autocomplete options if restrictTagsToAutocomplete is true + if ( + restrictTagsToAutocompleteOptions && + !autocompleteOptions?.some( + (option) => option.text === newTagText + ) + ) { + console.warn( + "Tag not allowed as per autocomplete options" + ); + return; + } + + if (validateTag && !validateTag(newTagText)) { + console.warn("Invalid tag as per validateTag"); + return; + } + + if (minLength && newTagText.length < minLength) { + console.warn(`Tag "${newTagText}" is too short`); + return; + } + + if (maxLength && newTagText.length > maxLength) { + console.warn(`Tag "${newTagText}" is too long`); + return; + } + + const newTagId = generateTagId(); + + // Add tag if duplicates are allowed or tag does not already exist + if ( + allowDuplicates || + !tags.some((tag) => tag.text === newTagText) + ) { + if (maxTags === undefined || tags.length < maxTags) { + // Check for maxTags limit + const newTag = { id: newTagId, text: newTagText }; + setTags((prevTags) => [...prevTags, newTag]); + onTagAdd?.(newTagText); + } else { + console.warn( + "Reached the maximum number of tags allowed" + ); + } + } else { + console.warn(`Duplicate tag "${newTagText}" not added`); + } + }); + setInputValue(""); + } else { + setInputValue(newValue); + } + onInputChange?.(newValue); + }; + + const handleInputFocus = ( + event: React.FocusEvent + ) => { + setActiveTagIndex(null); // Reset active tag index when the input field gains focus + onFocus?.(event); + }; + + const handleInputBlur = (event: React.FocusEvent) => { + if (addTagsOnBlur && inputValue.trim()) { + const newTagText = inputValue.trim(); + + if (validateTag && !validateTag(newTagText)) { + return; + } + + if (minLength && newTagText.length < minLength) { + console.warn("Tag is too short"); + return; + } + + if (maxLength && newTagText.length > maxLength) { + console.warn("Tag is too long"); + return; + } + + if ( + (allowDuplicates || + !tags.some((tag) => tag.text === newTagText)) && + (maxTags === undefined || tags.length < maxTags) + ) { + const newTagId = generateTagId(); + setTags([...tags, { id: newTagId, text: newTagText }]); + onTagAdd?.(newTagText); + setTagCount((prevTagCount) => prevTagCount + 1); + setInputValue(""); + } + } + + onBlur?.(event); + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if ( + delimiterList + ? delimiterList.includes(e.key) + : e.key === delimiter || e.key === Delimiter.Enter + ) { + e.preventDefault(); + const newTagText = inputValue.trim(); // Check if the tag is in the autocomplete options if restrictTagsToAutocomplete is true if ( @@ -200,465 +300,203 @@ const TagInput = ( (option) => option.text === newTagText ) ) { - console.warn( - "Tag not allowed as per autocomplete options" - ); + // error return; } if (validateTag && !validateTag(newTagText)) { - console.warn("Invalid tag as per validateTag"); return; } if (minLength && newTagText.length < minLength) { - console.warn(`Tag "${newTagText}" is too short`); + console.warn("Tag is too short"); + // error return; } + // Validate maxLength if (maxLength && newTagText.length > maxLength) { - console.warn(`Tag "${newTagText}" is too long`); + // error + console.warn("Tag is too long"); return; } const newTagId = generateTagId(); - // Add tag if duplicates are allowed or tag does not already exist if ( - allowDuplicates || - !tags.some((tag) => tag.text === newTagText) + newTagText && + (allowDuplicates || + !tags.some((tag) => tag.text === newTagText)) && + (maxTags === undefined || tags.length < maxTags) ) { - if (maxTags === undefined || tags.length < maxTags) { - // Check for maxTags limit - const newTag = { id: newTagId, text: newTagText }; - setTags((prevTags) => [...prevTags, newTag]); - onTagAdd?.(newTagText); - } else { - console.warn( - "Reached the maximum number of tags allowed" - ); - } - } else { - console.warn(`Duplicate tag "${newTagText}" not added`); + setTags([...tags, { id: newTagId, text: newTagText }]); + onTagAdd?.(newTagText); + setTagCount((prevTagCount) => prevTagCount + 1); } - }); - setInputValue(""); - } else { - setInputValue(newValue); - } - onInputChange?.(newValue); - }; - - const handleInputFocus = ( - event: React.FocusEvent - ) => { - setActiveTagIndex(null); // Reset active tag index when the input field gains focus - onFocus?.(event); - }; - - const handleInputBlur = (event: React.FocusEvent) => { - if (addTagsOnBlur && inputValue.trim()) { - const newTagText = inputValue.trim(); - - if (validateTag && !validateTag(newTagText)) { - return; - } - - if (minLength && newTagText.length < minLength) { - console.warn("Tag is too short"); - return; - } - - if (maxLength && newTagText.length > maxLength) { - console.warn("Tag is too long"); - return; - } - - if ( - (allowDuplicates || - !tags.some((tag) => tag.text === newTagText)) && - (maxTags === undefined || tags.length < maxTags) - ) { - const newTagId = generateTagId(); - setTags([...tags, { id: newTagId, text: newTagText }]); - onTagAdd?.(newTagText); - setTagCount((prevTagCount) => prevTagCount + 1); setInputValue(""); - } - } - - onBlur?.(event); - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if ( - delimiterList - ? delimiterList.includes(e.key) - : e.key === delimiter || e.key === Delimiter.Enter - ) { - e.preventDefault(); - const newTagText = inputValue.trim(); - - // Check if the tag is in the autocomplete options if restrictTagsToAutocomplete is true - if ( - restrictTagsToAutocompleteOptions && - !autocompleteOptions?.some( - (option) => option.text === newTagText - ) - ) { - // error - return; - } - - if (validateTag && !validateTag(newTagText)) { - return; - } - - if (minLength && newTagText.length < minLength) { - console.warn("Tag is too short"); - // error - return; - } - - // Validate maxLength - if (maxLength && newTagText.length > maxLength) { - // error - console.warn("Tag is too long"); - return; - } - - const newTagId = generateTagId(); - - if ( - newTagText && - (allowDuplicates || - !tags.some((tag) => tag.text === newTagText)) && - (maxTags === undefined || tags.length < maxTags) - ) { - setTags([...tags, { id: newTagId, text: newTagText }]); - onTagAdd?.(newTagText); - setTagCount((prevTagCount) => prevTagCount + 1); - } - setInputValue(""); - } else { - switch (e.key) { - case "Delete": - if (activeTagIndex !== null) { - e.preventDefault(); - const newTags = [...tags]; - newTags.splice(activeTagIndex, 1); - setTags(newTags); - setActiveTagIndex((prev) => - newTags.length === 0 - ? null - : prev! >= newTags.length - ? newTags.length - 1 - : prev - ); - setTagCount((prevTagCount) => prevTagCount - 1); - onTagRemove?.(tags[activeTagIndex].text); - } - break; - case "Backspace": - if (activeTagIndex !== null) { - e.preventDefault(); - const newTags = [...tags]; - newTags.splice(activeTagIndex, 1); - setTags(newTags); - setActiveTagIndex((prev) => - prev! === 0 ? null : prev! - 1 - ); - setTagCount((prevTagCount) => prevTagCount - 1); - onTagRemove?.(tags[activeTagIndex].text); - } - break; - case "ArrowRight": - e.preventDefault(); - if (activeTagIndex === null) { - setActiveTagIndex(0); - } else { - setActiveTagIndex((prev) => - prev! + 1 >= tags.length ? 0 : prev! + 1 - ); - } - break; - case "ArrowLeft": - e.preventDefault(); - if (activeTagIndex === null) { - setActiveTagIndex(tags.length - 1); - } else { - setActiveTagIndex((prev) => - prev! === 0 ? tags.length - 1 : prev! - 1 - ); - } - break; - case "Home": - e.preventDefault(); - setActiveTagIndex(0); - break; - case "End": - e.preventDefault(); - setActiveTagIndex(tags.length - 1); - break; - } - } - }; - - const removeTag = (idToRemove: string) => { - setTags(tags.filter((tag) => tag.id !== idToRemove)); - onTagRemove?.( - tags.find((tag) => tag.id === idToRemove)?.text || "" - ); - setTagCount((prevTagCount) => prevTagCount - 1); - }; - - const onSortEnd = (oldIndex: number, newIndex: number) => { - setTags((currentTags) => { - const newTags = [...currentTags]; - const [removedTag] = newTags.splice(oldIndex, 1); - newTags.splice(newIndex, 0, removedTag); - - return newTags; - }); - }; - - const handleClearAll = () => { - if (!onClearAll) { - setActiveTagIndex(-1); - setTags([]); - return; - } - onClearAll?.(); - }; - - // const filteredAutocompleteOptions = autocompleteFilter - // ? autocompleteOptions?.filter((option) => autocompleteFilter(option.text)) - // : autocompleteOptions; - const filteredAutocompleteOptions = useMemo(() => { - return (autocompleteOptions || []).filter((option) => - option.text - .toLowerCase() - .includes(inputValue ? inputValue.toLowerCase() : "") - ); - }, [inputValue, autocompleteOptions]); - - const displayedTags = sortTags ? [...tags].sort() : tags; - - const truncatedTags = truncate - ? tags.map((tag) => ({ - id: tag.id, - text: - tag.text?.length > truncate - ? `${tag.text.substring(0, truncate)}...` - : tag.text - })) - : displayedTags; - - return ( - (
0 ? "gap-3" : ""} ${ - inputFieldPosition === "bottom" - ? "flex-col" - : inputFieldPosition === "top" - ? "flex-col-reverse" - : "flex-row" - }`} - > - {!usePopoverForTags && - (!inlineTags ? ( - - ) : ( - !enableAutocomplete && ( -
-
- - = maxTags - ? placeholderWhenFull - : placeholder - } - value={inputValue} - onChange={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - {...inputProps} - className={cn( - "border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit", - // className, - styleClasses?.input - )} - autoComplete={ - enableAutocomplete ? "on" : "off" - } - list={ - enableAutocomplete - ? "autocomplete-options" - : undefined - } - disabled={ - disabled || - (maxTags !== undefined && - tags.length >= maxTags) - } - /> -
-
- ) - ))} - {enableAutocomplete ? ( -
- + newTags.length === 0 + ? null + : prev! >= newTags.length + ? newTags.length - 1 + : prev + ); + setTagCount((prevTagCount) => prevTagCount - 1); + onTagRemove?.(tags[activeTagIndex].text); } - setTagCount={setTagCount} - maxTags={maxTags} - onTagAdd={onTagAdd} - onTagRemove={onTagRemove} - allowDuplicates={allowDuplicates ?? false} - inlineTags={inlineTags} - usePortal={usePortal} - classStyleProps={{ - command: styleClasses?.autoComplete?.command, - popoverTrigger: - styleClasses?.autoComplete?.popoverTrigger, - popoverContent: - styleClasses?.autoComplete?.popoverContent, - commandList: - styleClasses?.autoComplete?.commandList, - commandGroup: - styleClasses?.autoComplete?.commandGroup, - commandItem: - styleClasses?.autoComplete?.commandItem - }} - > - {!usePopoverForTags ? ( - !inlineTags ? ( - // = maxTags ? placeholderWhenFull : placeholder} - // ref={inputRef} - // value={inputValue} - // disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} - // onChangeCapture={handleInputChange} - // onKeyDown={handleKeyDown} - // onFocus={handleInputFocus} - // onBlur={handleInputBlur} - // className={cn( - // 'w-full', - // // className, - // styleClasses?.input, - // )} - // /> - (= maxTags - ? placeholderWhenFull - : placeholder - } - value={inputValue} - onChange={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - {...inputProps} - className={cn( - "border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit", - // className, - styleClasses?.input - )} - autoComplete={ - enableAutocomplete ? "on" : "off" - } - list={ - enableAutocomplete - ? "autocomplete-options" - : undefined - } - disabled={ - disabled || - (maxTags !== undefined && - tags.length >= maxTags) - } - />) - ) : ( + break; + case "Backspace": + if (activeTagIndex !== null) { + e.preventDefault(); + const newTags = [...tags]; + newTags.splice(activeTagIndex, 1); + setTags(newTags); + setActiveTagIndex((prev) => + prev! === 0 ? null : prev! - 1 + ); + setTagCount((prevTagCount) => prevTagCount - 1); + onTagRemove?.(tags[activeTagIndex].text); + } + break; + case "ArrowRight": + e.preventDefault(); + if (activeTagIndex === null) { + setActiveTagIndex(0); + } else { + setActiveTagIndex((prev) => + prev! + 1 >= tags.length ? 0 : prev! + 1 + ); + } + break; + case "ArrowLeft": + e.preventDefault(); + if (activeTagIndex === null) { + setActiveTagIndex(tags.length - 1); + } else { + setActiveTagIndex((prev) => + prev! === 0 ? tags.length - 1 : prev! - 1 + ); + } + break; + case "Home": + e.preventDefault(); + setActiveTagIndex(0); + break; + case "End": + e.preventDefault(); + setActiveTagIndex(tags.length - 1); + break; + } + } + }; + + const removeTag = (idToRemove: string) => { + setTags(tags.filter((tag) => tag.id !== idToRemove)); + onTagRemove?.( + tags.find((tag) => tag.id === idToRemove)?.text || "" + ); + setTagCount((prevTagCount) => prevTagCount - 1); + }; + + const onSortEnd = (oldIndex: number, newIndex: number) => { + setTags((currentTags) => { + const newTags = [...currentTags]; + const [removedTag] = newTags.splice(oldIndex, 1); + newTags.splice(newIndex, 0, removedTag); + + return newTags; + }); + }; + + const handleClearAll = () => { + if (!onClearAll) { + setActiveTagIndex(-1); + setTags([]); + return; + } + onClearAll?.(); + }; + + // const filteredAutocompleteOptions = autocompleteFilter + // ? autocompleteOptions?.filter((option) => autocompleteFilter(option.text)) + // : autocompleteOptions; + const filteredAutocompleteOptions = useMemo(() => { + return (autocompleteOptions || []).filter((option) => + option.text + .toLowerCase() + .includes(inputValue ? inputValue.toLowerCase() : "") + ); + }, [inputValue, autocompleteOptions]); + + const displayedTags = sortTags ? [...tags].sort() : tags; + + const truncatedTags = truncate + ? tags.map((tag) => ({ + id: tag.id, + text: + tag.text?.length > truncate + ? `${tag.text.substring(0, truncate)}...` + : tag.text + })) + : displayedTags; + + return ( +
0 ? "gap-3" : ""} ${ + inputFieldPosition === "bottom" + ? "flex-col" + : inputFieldPosition === "top" + ? "flex-col-reverse" + : "flex-row" + }`} + > + {!usePopoverForTags && + (!inlineTags ? ( + + ) : ( + !enableAutocomplete && ( +
- {/* = maxTags ? placeholderWhenFull : placeholder} - ref={inputRef} - value={inputValue} - disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} - onChangeCapture={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - inlineTags={inlineTags} - className={cn( - 'border-0 flex-1 w-fit h-5', - // className, - styleClasses?.input, - )} - /> */}
- ) +
+ ) + ))} + {enableAutocomplete ? ( +
+ + {!usePopoverForTags ? ( + !inlineTags ? ( + // = maxTags ? placeholderWhenFull : placeholder} + // ref={inputRef} + // value={inputValue} + // disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} + // onChangeCapture={handleInputChange} + // onKeyDown={handleKeyDown} + // onFocus={handleInputFocus} + // onBlur={handleInputBlur} + // className={cn( + // 'w-full', + // // className, + // styleClasses?.input, + // )} + // /> + = maxTags + ? placeholderWhenFull + : placeholder + } + value={inputValue} + onChange={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + {...inputProps} + className={cn( + "border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit", + // className, + styleClasses?.input + )} + autoComplete={ + enableAutocomplete ? "on" : "off" + } + list={ + enableAutocomplete + ? "autocomplete-options" + : undefined + } + disabled={ + disabled || + (maxTags !== undefined && + tags.length >= maxTags) + } + /> + ) : ( +
+ + {/* = maxTags ? placeholderWhenFull : placeholder} + ref={inputRef} + value={inputValue} + disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} + onChangeCapture={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + inlineTags={inlineTags} + className={cn( + 'border-0 flex-1 w-fit h-5', + // className, + styleClasses?.input, + )} + /> */} + = maxTags + ? placeholderWhenFull + : placeholder + } + value={inputValue} + onChange={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + {...inputProps} + className={cn( + "border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit", + // className, + styleClasses?.input + )} + autoComplete={ + enableAutocomplete + ? "on" + : "off" + } + list={ + enableAutocomplete + ? "autocomplete-options" + : undefined + } + disabled={ + disabled || + (maxTags !== undefined && + tags.length >= maxTags) + } + /> +
+ ) + ) : ( + + {/* = maxTags ? placeholderWhenFull : placeholder} + ref={inputRef} + value={inputValue} + disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} + onChangeCapture={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + className={cn( + 'w-full', + // className, + styleClasses?.input, + )} + /> */} + = maxTags + ? placeholderWhenFull + : placeholder + } + value={inputValue} + onChange={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + {...inputProps} + className={cn( + "border-0 h-5 bg-transparent focus-visible:ring-0 focus-visible:ring-transparent focus-visible:ring-offset-0 flex-1 w-fit", + // className, + styleClasses?.input + )} + autoComplete={ + enableAutocomplete ? "on" : "off" + } + list={ + enableAutocomplete + ? "autocomplete-options" + : undefined + } + disabled={ + disabled || + (maxTags !== undefined && + tags.length >= maxTags) + } + /> + + )} +
+
+ ) : ( +
+ {!usePopoverForTags ? ( + !inlineTags ? ( + = maxTags + ? placeholderWhenFull + : placeholder + } + value={inputValue} + onChange={handleInputChange} + onKeyDown={handleKeyDown} + onFocus={handleInputFocus} + onBlur={handleInputBlur} + {...inputProps} + className={cn( + styleClasses?.input + // className + )} + autoComplete={ + enableAutocomplete ? "on" : "off" + } + list={ + enableAutocomplete + ? "autocomplete-options" + : undefined + } + disabled={ + disabled || + (maxTags !== undefined && + tags.length >= maxTags) + } + /> + ) : null ) : ( - {/* = maxTags ? placeholderWhenFull : placeholder} - ref={inputRef} - value={inputValue} - disabled={disabled || (maxTags !== undefined && tags.length >= maxTags)} - onChangeCapture={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - className={cn( - 'w-full', - // className, - styleClasses?.input, - )} - /> */} = maxTags) } + className={cn( + "border-0 w-full", + styleClasses?.input + // className + )} /> )} - -
- ) : ( -
- {!usePopoverForTags ? ( - !inlineTags ? ( - = maxTags - ? placeholderWhenFull - : placeholder - } - value={inputValue} - onChange={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - {...inputProps} - className={cn( - styleClasses?.input - // className - )} - autoComplete={ - enableAutocomplete ? "on" : "off" - } - list={ - enableAutocomplete - ? "autocomplete-options" - : undefined - } - disabled={ - disabled || - (maxTags !== undefined && - tags.length >= maxTags) - } - /> - ) : null - ) : ( - - = maxTags - ? placeholderWhenFull - : placeholder - } - value={inputValue} - onChange={handleInputChange} - onKeyDown={handleKeyDown} - onFocus={handleInputFocus} - onBlur={handleInputBlur} - {...inputProps} - autoComplete={ - enableAutocomplete ? "on" : "off" - } - list={ - enableAutocomplete - ? "autocomplete-options" - : undefined - } - disabled={ - disabled || - (maxTags !== undefined && - tags.length >= maxTags) - } - className={cn( - "border-0 w-full", - styleClasses?.input - // className - )} - /> - - )} -
- )} - {showCount && maxTags && ( -
- - {`${tagCount}`}/{`${maxTags}`} - -
- )} - {clearAll && ( - - )} -
) - ); -}; +
+ )} + + {showCount && maxTags && ( +
+ + {`${tagCount}`}/{`${maxTags}`} + +
+ )} + {clearAll && ( + + )} +
+ ); + } +); TagInput.displayName = "TagInput"; diff --git a/src/components/ui/alert.tsx b/src/components/ui/alert.tsx index df3f143b..8f3e489a 100644 --- a/src/components/ui/alert.tsx +++ b/src/components/ui/alert.tsx @@ -22,52 +22,44 @@ const alertVariants = cva( }, ); -const Alert = ( - { - ref, - className, - variant, - ...props - } -) => (
); +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)); Alert.displayName = "Alert"; -const AlertTitle = ( - { - ref, - className, - ...props - }: React.HTMLAttributes & { - ref: React.RefObject; - } -) => (
); +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); AlertTitle.displayName = "AlertTitle"; -const AlertDescription = ( - { - ref, - className, - ...props - }: React.HTMLAttributes & { - ref: React.RefObject; - } -) => (
); +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); AlertDescription.displayName = "AlertDescription"; export { Alert, AlertTitle, AlertDescription }; diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx index b02832a5..ef6e4355 100644 --- a/src/components/ui/avatar.tsx +++ b/src/components/ui/avatar.tsx @@ -5,55 +5,46 @@ import * as AvatarPrimitive from "@radix-ui/react-avatar" import { cn } from "@app/lib/cn" -const Avatar = ( - { - ref, - className, - ...props - }: React.ComponentPropsWithoutRef & { - ref: React.RefObject>; - } -) => () +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) Avatar.displayName = AvatarPrimitive.Root.displayName -const AvatarImage = ( - { - ref, - className, - ...props - }: React.ComponentPropsWithoutRef & { - ref: React.RefObject>; - } -) => () +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) AvatarImage.displayName = AvatarPrimitive.Image.displayName -const AvatarFallback = ( - { - ref, - className, - ...props - }: React.ComponentPropsWithoutRef & { - ref: React.RefObject>; - } -) => () +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName export { Avatar, AvatarImage, AvatarFallback } diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index f4ead817..0c44fda2 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "@app/lib/cn"; const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2", + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", { variants: { variant: { diff --git a/src/components/ui/breadcrumb.tsx b/src/components/ui/breadcrumb.tsx index 464475f8..dd40aa55 100644 --- a/src/components/ui/breadcrumb.tsx +++ b/src/components/ui/breadcrumb.tsx @@ -4,55 +4,47 @@ import { ChevronRight, MoreHorizontal } from "lucide-react" import { cn } from "@app/lib/cn" -const Breadcrumb = ( - { - ref, - ...props +const Breadcrumb = React.forwardRef< + HTMLElement, + React.ComponentPropsWithoutRef<"nav"> & { + separator?: React.ReactNode } -) =>