-
Notifications
You must be signed in to change notification settings - Fork 0
[Component] Dropdown #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: nextjs-tailwind
Are you sure you want to change the base?
Conversation
…lose-on-clickOutside
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left some comments requesting changes to a few files.
6d83fbe
to
3c43dc2
Compare
3c43dc2
to
10e13db
Compare
open, | ||
onOpenChange: setOpen, // Floating UI will control open state | ||
whileElementsMounted: autoUpdate, // auto reposition on resize/scroll | ||
strategy: "fixed" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line of code is canceling out the position absolute styles you applied to the div that is also receiving the floatingStyles from the style prop. This strategy: "fixed" line of code can be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! 'absolute' is unnecessary when using floating-ui.
But, I would like to decide if we want to proceed floating-ui before i correct these areas.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't find the popovers to be aligned properly without this style for floating. I'd suggest we retain the floating-ui in Dropdown for the moment, and rework on it (remove or handle the popup aligning manually) after the main components are ready. I will not use the floating-ui in the Selectbox
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that is the case there is something incorrect with the styles in the file you are working on and we need to have a call to figure out what the issue is. There is no reason to keep this package when the problem stated for why it is needed can be solved by adding a single tailwind class name.
|
||
return ( | ||
<div className={cn(dropdownVariants({ size }))}> | ||
<span ref={refs.setReference}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the div doesn't have any margin or padding and the button doesn't have a margin, you can remove the element and attach the ref to the root container div element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While using floating-ui, ref has to be attached to the element respective to which the floating popover should be placed. hence here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment resolved, floating-ui was removed.
} | ||
}; | ||
|
||
const dropdownRef = useRef<HTMLDivElement>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dropdownRef isn't being assigned to any element so it isn't actually being used for anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a miss.
Should have been
return (
<div className="relative" ref={dropdownRef}>
<span ref={refs.setReference}>
But, that is unnecessary when using floating-ui as it itself handles close-on-click-outside, so we wouldn't need to attach a separate 'click' event listener to close the popup when clicked outside of target area.
Let me know what your ideas are on keeping the floating-ui package intact. And, i can do this correction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit error. Supposed to be attached here-
return (
<div className="relative" ref={dropdownRef}>
<span ref={refs.setReference}>
<Button
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment resolved, floating-ui was removed.
@@ -0,0 +1,196 @@ | |||
'use client'; | |||
import React, { useEffect, useRef, useState } from 'react'; | |||
import { useFloating, offset, flip, shift, autoUpdate, useDismiss, useInteractions } from "@floating-ui/react"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On my local instance I removed all of the floatingUI code and I added the ref to the root parent div and all the functionality seems to be working as expected. Remind me again, what was the rational for add this third party library?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider the scenario of our Sort, Filter buttons above the Counterexample Trace table. They are aligned to the far left of the container. In that scenario, we need to determine dynamically how our dropdown list popup should be opened so that it is positioned correctly. When no particular styles applied, it will be placed like in below screengrab -
Even with just flex-direction: row-reverse
for a container that holds the buttons, and position:absolute
for the popover div
, we still will need to dynamically determine within the DropdownComponent if there is enough viewport space for the dropdown contents to be visible, then set right:0 / left:0 respectively.
We would have to deal this entirely with our set of calculations, but with floating-ui it is handled in much cleaner/easier with minimal effort from our end.
floating-ui.webm
let me know if we do not want to seek support from any third-party packages big/small, and I can edit to handle this vanilla.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shall discuss this in person.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed - Use a position
prop left
/right
for now and style with class accordingly.
} else { | ||
setSelected([value]); | ||
onChange?.(value); | ||
setOpen(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There could be a case where a user opens the select menu options, choses an option to see what it does and then wants to click on a different option. If the setOpen to false is here that would mean the user has to re-open the menu each time they want to select a new radio button option. I think the menu button close event should work the same regardless of the content shown inside of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, done 👍
if (!dropdownRef.current || dropdownRef.current.contains(event.target as Node)) { | ||
return; | ||
} | ||
setOpen(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are trying to setState from inside of a useEffect hook this state is considered a reactive value. The problem with an empty dependency array is that you will end up with a state value for the open state. You could include 'open' in the dependency array but then this would cause the eventListener to be torn down and setup each time the value for open changes, which isn't ideal. You can update the code as follows that way you can ensure you aren't falsely calling the setOpen(false) statement.
const openRef = useRef(open);
useEffect(() => {
openRef.current = open;
}, [open]);
useEffect(() => {
const listener = (event: MouseEvent) => {
if (!openRef.current || dropdownRef.current?.contains(event.target as Node)) {
return;
}
setOpen(false);
};
document.addEventListener("click", listener, true);
return () => {
document.removeEventListener("click", listener, true);
};
}, []);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will look into this after deciding upon whether or not to keep floating-ui.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[] in useEffect, attaches a single global listener and is ideal for as long the useEffect does not reply on a stale state open
(in this case which isn't)
The suggestion to check openRef.current
if dropdown popover is currently open, is 💯 right, and thus added that in.
I'm commiting my change for this bit .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two useEffects above, which one are you talking about in your first sentence?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second one which binds listener to setOpen(false) when clicked anywhere outside the dropdown targets.
Note: floating-ui offers useDismiss
to handle this scenario. Then we would not have to bind additional events to listen the same, given we are continuing with the package.
We shall discuss this as well in a call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment resolved, floating-ui was removed.
options: Option[]; | ||
multi?: boolean; | ||
radio?: boolean; | ||
label: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are two label props defined in this component, let's made the code easier to read by identifying that the labels correspond to. You can call this label btnLabel
and the one on the options interface itemLabel
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btnLabel
is updated. Retained label
within options , as if it is changed to itemLabel
would have to change value to itemValue
for naming consistency. Hence,
open, | ||
onOpenChange: setOpen, // Floating UI will control open state | ||
whileElementsMounted: autoUpdate, // auto reposition on resize/scroll | ||
strategy: "fixed" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If that is the case there is something incorrect with the styles in the file you are working on and we need to have a call to figure out what the issue is. There is no reason to keep this package when the problem stated for why it is needed can be solved by adding a single tailwind class name.
@KJES4 , I've pulled your latest changes. But I've updated the way |
"lint": "next lint" | ||
}, | ||
"dependencies": { | ||
"@floating-ui/react": "^0.27.16", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since floating-ui is no longer being used please make sure it is uninstalled and removed from the package.json file.
@amnambiar are you saying on your end there are two files |
<Checkbox label='Checkbox Label Small' size='small' defaultChecked={true} /> | ||
<Checkbox label='Checkbox Label Medium' size='medium'/> | ||
<Checkbox label='Checkbox Label Disabled' disabled /> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you move the Dropdown components into the third column so they don't break the layout on this page and cause a scroll bar to appear?
const [settingsMenuValue, setSettingsMenuValue] = useState<string | null>(null); | ||
|
||
|
||
const handleFilterChange = useCallback((val: string | string[] | null) => setFilterValues(val as string[]), []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the rational for using useCallback here?
suffixText?: string; | ||
} | ||
|
||
export interface DropdownProps { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the dropdownMenu component I added a size property. Can you take a look at how I implemented that and add that prop to this file? This will help allow the component to be more condensed when used inside of a table.
Pull request template
Description
Details of this Dropdown component and its behaviour is as per this document
Task
Checklist