Feat: Clear select option

This commit is contained in:
Daniel Hougaard
2024-06-24 19:12:38 +02:00
parent a6865585f3
commit 5a957514df
3 changed files with 122 additions and 70 deletions
+105 -51
View File
@@ -36,61 +36,73 @@ export const Select = forwardRef<HTMLButtonElement, SelectProps>(
ref ref
): JSX.Element => { ): JSX.Element => {
return ( return (
<SelectPrimitive.Root {...props} disabled={isDisabled}> <div className="flex items-center space-x-2">
<SelectPrimitive.Trigger <SelectPrimitive.Root
ref={ref} {...props}
className={twMerge( onValueChange={(value) => {
`inline-flex items-center justify-between rounded-md if (!props.onValueChange) return;
bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none focus:bg-mineshaft-700/80 data-[placeholder]:text-mineshaft-200`,
className,
isDisabled && "cursor-not-allowed opacity-50"
)}
>
<SelectPrimitive.Value placeholder={placeholder}>
{props.icon ? <FontAwesomeIcon icon={props.icon} /> : placeholder}
</SelectPrimitive.Value>
<SelectPrimitive.Icon className="ml-3"> const newValue = value === "EMPTY-VALUE" ? "" : value;
<FontAwesomeIcon props.onValueChange(newValue);
icon={faCaretDown} }}
size="sm" disabled={isDisabled}
className={twMerge(isDisabled && "opacity-30")} >
/> <SelectPrimitive.Trigger
</SelectPrimitive.Icon> ref={ref}
</SelectPrimitive.Trigger>
<SelectPrimitive.Portal>
<SelectPrimitive.Content
className={twMerge( className={twMerge(
"relative top-1 z-[100] overflow-hidden rounded-md border border-mineshaft-600 bg-mineshaft-900 font-inter text-bunker-100 shadow-md", `inline-flex items-center justify-between rounded-md
position === "popper" && "max-h-72", bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none focus:bg-mineshaft-700/80 data-[placeholder]:text-mineshaft-200`,
dropdownContainerClassName className,
isDisabled && "cursor-not-allowed opacity-50"
)} )}
position={position}
style={{ width: "var(--radix-select-trigger-width)" }}
> >
<SelectPrimitive.ScrollUpButton> <div className="flex items-center space-x-2">
<div className="flex items-center justify-center"> {props.icon && <FontAwesomeIcon icon={props.icon} />}
<FontAwesomeIcon icon={faCaretUp} size="sm" /> <SelectPrimitive.Value placeholder={placeholder} />
</div> </div>
</SelectPrimitive.ScrollUpButton>
<SelectPrimitive.Viewport className="p-1"> <SelectPrimitive.Icon className="ml-3">
{isLoading ? ( <FontAwesomeIcon
<div className="flex items-center justify-center"> icon={faCaretDown}
<Spinner size="xs" /> size="sm"
<span className="ml-2 text-xs text-gray-500">Loading...</span> className={twMerge(isDisabled && "opacity-30")}
</div> />
) : ( </SelectPrimitive.Icon>
children </SelectPrimitive.Trigger>
<SelectPrimitive.Portal>
<SelectPrimitive.Content
className={twMerge(
"relative top-1 z-[100] overflow-hidden rounded-md border border-mineshaft-600 bg-mineshaft-900 font-inter text-bunker-100 shadow-md",
position === "popper" && "max-h-72",
dropdownContainerClassName
)} )}
</SelectPrimitive.Viewport> position={position}
<SelectPrimitive.ScrollDownButton> style={{ width: "var(--radix-select-trigger-width)" }}
<div className="flex items-center justify-center"> >
<FontAwesomeIcon icon={faCaretDown} size="sm" /> <SelectPrimitive.ScrollUpButton>
</div> <div className="flex items-center justify-center">
</SelectPrimitive.ScrollDownButton> <FontAwesomeIcon icon={faCaretUp} size="sm" />
</SelectPrimitive.Content> </div>
</SelectPrimitive.Portal> </SelectPrimitive.ScrollUpButton>
</SelectPrimitive.Root> <SelectPrimitive.Viewport className="p-1">
{isLoading ? (
<div className="flex items-center justify-center">
<Spinner size="xs" />
<span className="ml-2 text-xs text-gray-500">Loading...</span>
</div>
) : (
children
)}
</SelectPrimitive.Viewport>
<SelectPrimitive.ScrollDownButton>
<div className="flex items-center justify-center">
<FontAwesomeIcon icon={faCaretDown} size="sm" />
</div>
</SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
</SelectPrimitive.Root>
</div>
); );
} }
); );
@@ -114,7 +126,7 @@ export const SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(
outline-none transition-all hover:bg-mineshaft-500 data-[highlighted]:bg-mineshaft-700/80`, outline-none transition-all hover:bg-mineshaft-500 data-[highlighted]:bg-mineshaft-700/80`,
isSelected && "bg-primary", isSelected && "bg-primary",
isDisabled && isDisabled &&
"cursor-not-allowed text-gray-600 hover:bg-transparent hover:text-mineshaft-600", "cursor-not-allowed text-gray-600 hover:bg-transparent hover:text-mineshaft-600",
className className
)} )}
ref={forwardedRef} ref={forwardedRef}
@@ -129,3 +141,45 @@ export const SelectItem = forwardRef<HTMLDivElement, SelectItemProps>(
); );
SelectItem.displayName = "SelectItem"; SelectItem.displayName = "SelectItem";
export type SelectClearProps = Omit<SelectItemProps, "disabled" | "value"> & {
onClear: () => void;
selectValue: string;
};
export const SelectClear = forwardRef<HTMLDivElement, SelectClearProps>(
(
{ children, className, isSelected, isDisabled, onClear, selectValue, ...props },
forwardedRef
) => {
return (
<SelectPrimitive.Item
{...props}
value="EMPTY-VALUE"
onSelect={() => onClear()}
onClick={() => onClear()}
className={twMerge(
`relative mb-0.5 flex
cursor-pointer select-none items-center rounded-md py-2 pl-10 pr-4 text-sm
outline-none transition-all hover:bg-mineshaft-500 data-[highlighted]:bg-mineshaft-700/80`,
isSelected && "bg-primary",
isDisabled &&
"cursor-not-allowed text-gray-600 hover:bg-transparent hover:text-mineshaft-600",
className
)}
ref={forwardedRef}
>
<div
className={twMerge(
"absolute left-3.5 text-primary",
selectValue === "" ? "visible" : "hidden"
)}
>
<FontAwesomeIcon icon={faCheck} />
</div>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
);
}
);
SelectClear.displayName = "SelectClear";
+1 -1
View File
@@ -1,2 +1,2 @@
export type { SelectItemProps, SelectProps } from "./Select"; export type { SelectItemProps, SelectProps } from "./Select";
export { Select, SelectItem } from "./Select"; export { Select, SelectClear, SelectItem } from "./Select";
@@ -13,6 +13,7 @@ import {
FormControl, FormControl,
Input, Input,
Select, Select,
SelectClear,
SelectItem, SelectItem,
Switch, Switch,
Tab, Tab,
@@ -68,7 +69,8 @@ export const AdminDashboardPage = () => {
} }
}); });
const signupMode = watch("signUpMode"); const signUpMode = watch("signUpMode");
const defaultAuthOrgId = watch("defaultAuthOrgId");
const { user, isLoading: isUserLoading } = useUser(); const { user, isLoading: isUserLoading } = useUser();
const { orgs } = useOrganization(); const { orgs } = useOrganization();
@@ -90,14 +92,7 @@ export const AdminDashboardPage = () => {
const onFormSubmit = async (formData: TDashboardForm) => { const onFormSubmit = async (formData: TDashboardForm) => {
try { try {
const { const { allowedSignUpDomain, trustSamlEmails, trustLdapEmails, trustOidcEmails } = formData;
signUpMode,
allowedSignUpDomain,
trustSamlEmails,
trustLdapEmails,
trustOidcEmails,
defaultAuthOrgId
} = formData;
await updateServerConfig({ await updateServerConfig({
defaultAuthOrgId: defaultAuthOrgId || null, defaultAuthOrgId: defaultAuthOrgId || null,
@@ -175,7 +170,7 @@ export const AdminDashboardPage = () => {
)} )}
/> />
</div> </div>
{signupMode === "anyone" && ( {signUpMode === "anyone" && (
<div className="flex flex-col justify-start"> <div className="flex flex-col justify-start">
<div className="mb-4 text-xl font-semibold text-mineshaft-100"> <div className="mb-4 text-xl font-semibold text-mineshaft-100">
Restrict signup by email domain(s) Restrict signup by email domain(s)
@@ -222,19 +217,22 @@ export const AdminDashboardPage = () => {
isError={Boolean(error)} isError={Boolean(error)}
> >
<Select <Select
placeholder="Allow all organizations"
className="w-full bg-mineshaft-700" className="w-full bg-mineshaft-700"
dropdownContainerClassName="bg-mineshaft-800" dropdownContainerClassName="bg-mineshaft-800"
defaultValue={field.value ?? " "} defaultValue={field.value ?? " "}
onValueChange={(e) => { onValueChange={(e) => onChange(e)}
if (e === "EMPTY") {
onChange("");
return;
}
onChange(e);
}}
{...field} {...field}
> >
<SelectItem value="EMPTY">Select organization...</SelectItem> <SelectClear
selectValue={defaultAuthOrgId}
onClear={() => {
console.log("clearing");
onChange("");
}}
>
Allow all organizations
</SelectClear>
{organizations.data?.map((org) => ( {organizations.data?.map((org) => (
<SelectItem key={org.id} value={org.id}> <SelectItem key={org.id} value={org.id}>
{org.name} {org.name}