mirror of
https://github.com/makeplane/plane.git
synced 2026-01-28 17:29:02 -06:00
[WEB-2783]fix: dropdown visibility in onboarding (#6329)
* fix: dropdown visibility on scroll to bottom * chore: removed unused variables
This commit is contained in:
@@ -15,8 +15,9 @@ import {
|
||||
useForm,
|
||||
} from "react-hook-form";
|
||||
// icons
|
||||
import { usePopper } from "react-popper";
|
||||
import { Check, ChevronDown, Plus, XCircle } from "lucide-react";
|
||||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import { Listbox } from "@headlessui/react";
|
||||
// types
|
||||
import { IUser, IWorkspace } from "@plane/types";
|
||||
// ui
|
||||
@@ -28,7 +29,6 @@ import { ROLE, ROLE_DETAILS } from "@/constants/workspace";
|
||||
import { getUserRole } from "@/helpers/user.helper";
|
||||
// hooks
|
||||
import { useEventTracker } from "@/hooks/store";
|
||||
import useDynamicDropdownPosition from "@/hooks/use-dynamic-dropdown";
|
||||
// plane web constants
|
||||
import { EUserPermissions } from "@/plane-web/constants/user-permissions";
|
||||
// services
|
||||
@@ -101,12 +101,8 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
|
||||
watch,
|
||||
} = props;
|
||||
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
|
||||
useDynamicDropdownPosition(isDropdownOpen, () => setIsDropdownOpen(false), buttonRef, dropdownRef);
|
||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const email = watch(`emails.${index}.email`);
|
||||
|
||||
@@ -134,6 +130,18 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||
placement: "bottom-end",
|
||||
modifiers: [
|
||||
{
|
||||
name: "preventOverflow",
|
||||
options: {
|
||||
padding: 12,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="group relative grid grid-cols-10 gap-4">
|
||||
@@ -177,15 +185,13 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
|
||||
value={value}
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
setIsDropdownOpen(false);
|
||||
setValue(`emails.${index}.role_active`, true);
|
||||
}}
|
||||
className="w-full flex-shrink-0 text-left"
|
||||
>
|
||||
<Listbox.Button
|
||||
type="button"
|
||||
ref={buttonRef}
|
||||
onClick={() => setIsDropdownOpen((prev) => !prev)}
|
||||
ref={setReferenceElement}
|
||||
className="flex w-full items-center justify-between gap-1 rounded-md px-2.5 py-2 text-sm border-[0.5px] border-onboarding-border-100"
|
||||
>
|
||||
<span
|
||||
@@ -207,45 +213,37 @@ const InviteMemberInput: React.FC<InviteMemberFormProps> = (props) => {
|
||||
/>
|
||||
</Listbox.Button>
|
||||
|
||||
<Transition
|
||||
show={isDropdownOpen}
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-100"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Listbox.Options
|
||||
ref={dropdownRef}
|
||||
className="fixed z-10 mt-1 h-fit w-48 sm:w-60 overflow-y-auto rounded-md border border-onboarding-border-100 bg-onboarding-background-200 shadow-sm focus:outline-none"
|
||||
<Listbox.Options as="div">
|
||||
<div
|
||||
className="p-2 absolute space-y-1 z-10 mt-1 h-fit w-48 sm:w-60 rounded-md border border-onboarding-border-100 bg-onboarding-background-200 shadow-sm focus:outline-none"
|
||||
ref={setPopperElement}
|
||||
style={styles.popper}
|
||||
{...attributes.popper}
|
||||
>
|
||||
<div className="space-y-1 p-2">
|
||||
{Object.entries(ROLE_DETAILS).map(([key, value]) => (
|
||||
<Listbox.Option
|
||||
key={key}
|
||||
value={parseInt(key)}
|
||||
className={({ active, selected }) =>
|
||||
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
|
||||
active || selected ? "bg-onboarding-background-400/40" : ""
|
||||
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
|
||||
}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<div className="flex items-center text-wrap gap-2 p-1">
|
||||
<div className="flex flex-col">
|
||||
<div className="text-sm font-medium">{value.title}</div>
|
||||
<div className="flex text-xs text-custom-text-300">{value.description}</div>
|
||||
</div>
|
||||
{selected && <Check className="h-4 w-4 shrink-0" />}
|
||||
{Object.entries(ROLE_DETAILS).map(([key, value]) => (
|
||||
<Listbox.Option
|
||||
as="div"
|
||||
key={key}
|
||||
value={parseInt(key)}
|
||||
className={({ active, selected }) =>
|
||||
`cursor-pointer select-none truncate rounded px-1 py-1.5 ${
|
||||
active || selected ? "bg-onboarding-background-400/40" : ""
|
||||
} ${selected ? "text-onboarding-text-100" : "text-custom-text-200"}`
|
||||
}
|
||||
>
|
||||
{({ selected }) => (
|
||||
<div className="flex items-center text-wrap gap-2 p-1">
|
||||
<div className="flex flex-col">
|
||||
<div className="text-sm font-medium">{value.title}</div>
|
||||
<div className="flex text-xs text-custom-text-300">{value.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</div>
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
{selected && <Check className="h-4 w-4 shrink-0" />}
|
||||
</div>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</div>
|
||||
</Listbox.Options>
|
||||
</Listbox>
|
||||
)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user