-
Notifications
You must be signed in to change notification settings - Fork 110
frontend: style multi select dropdown #2129
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
frontend: style multi select dropdown #2129
Conversation
c443eff
to
d4d4261
Compare
There's unfortunately a known issue in react-select that I discovered while developing. When opening the multi select/dropdown, it automatically focuses on the first option. I believe this shouldn't be a default behaviour, but unfort. it is, and I still have no way to fix it that's not too hacky. (right now, only the focus colour is not shown due to CSS. But technically/programatically, it's still focusing automatically on the first option - so if a user opens the dropdown and presses the SO question: https://stackoverflow.com/questions/65510875/disable-focus-on-first-option-in-react-select (the solution is outdated as it's intended for v4, we're using v5). Github PR that's been open for years at their end and also some discussion: JedWatson/react-select#4080 |
IMO having focus on the first item is fine. but the focus should be visible. |
/* | ||
displays ', ' as a pseudo component for all currency component | ||
except the last displayed component (the 3rd currency component). | ||
The reason for :nth-last-child(2) instead of just :last-child is because there's an extra | ||
component created by react-select after the actual last currency component. | ||
So, we're targetting the second to last component here, | ||
which is the last selected currency in the DOM. | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):not(:nth-last-child(2))::after { | ||
content: ', '; | ||
} | ||
|
||
/* | ||
displays '...' as a pseudo component of the 3rd currency and only when there's more than 3 selected. | ||
:nth-last-child(2) is used for the same reason as above | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):nth-child(3):not(:nth-last-child(2))::after { | ||
content: ' ...'; | ||
} | ||
|
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.
Might look "hacky" here just to display a string like "GBP, CHF" or "GBP, CHF, USD" or "AUD, GBP, CHF ..."
but for multi select using react-select, we can't just display a single string unfortunately - as AFAIK it's designed to display each selected item as a single component.
Under the hood, in react-select multi, for each selected component, a single component (div) with class .react-select__multi-value
gets generated and shown. Here, we just separate them with ',' and then '...' for the last element if there's more than 3 selected.
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.
the "badges" with close button look cool, but I guess not necessary I guess better if we keep it minimal text-only for now.
isMulti | ||
closeMenuOnSelect={false} | ||
hideSelectedOptions={false} | ||
value={[...selectedCurrencies].reverse()} |
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.
reverse() here so the latest selected currency will be displayed at the most front of the string.
E.g:
- Let's say selected currencies looks like this: GBP, EUR
- User selects AUD
- Now, selected looks like this: AUD, GBP, EUR
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.
ahh that makes sense, I was wondering what the order is and why it changes before. This way it always shows the newest nice 👍
c76b834
to
325775d
Compare
changes made, demo updated in PR's desc. cc @jadzeidan |
fe00852
to
ba438c6
Compare
frontends/web/src/api/account.ts
Outdated
export type FiatWithDisplayName = { | ||
currency: Fiat, | ||
displayName: 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.
Since this is only used in rates component and not coming from backend I think better to move to rates.tsx
import saveLightSVG from './assets/icons/save-light.svg'; | ||
import starSVG from './assets/icons/star.svg'; | ||
import starInactiveSVG from './assets/icons/star-inactive.svg'; | ||
import selectedCheckLight from './assets/icons/selected-check-light.svg'; |
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.
nit: for consistency add SVG at the end as all other imported svgs end with SVG in the imoported name.
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.
oops..
export const SaveLight = (props: ImgProps) => (<img src={saveLightSVG} draggable={false} {...props} />); | ||
export const Star = (props: ImgProps) => (<img src={starSVG} draggable={false} {...props} />); | ||
export const StarInactive = (props: ImgProps) => (<img src={starInactiveSVG} draggable={false} {...props} />); | ||
// check component for cusotm multi-dropdown select |
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 not needed IMO, this icon could also be used in a different component in the future.
{ currency: 'SEK', displayName: 'Swedish krona' }, | ||
{ currency: 'SGD', displayName: 'Singapore dollar' }, | ||
{ currency: 'USD', displayName: 'United States dollar' }, | ||
{ currency: 'BTC', displayName: 'Bitcoin' } |
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 thought about if we should display the currency name in the native language. i.e. "Svensk krona" instead of "Swedish krona", but that does't really work for "Swiss france" with our 4 official languages 🤦
so I guess better to have everything in English.
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.
Please note we have a new lang (Czech) and new Fiat currencies on master, maybe merge master->staging-revamp-settings first?
|
||
const ActiveCurrenciesDropdownSetting = ({ selected, active }: SharedProps) => { | ||
const formattedCurrencies = currencies.map((currency) => ({ label: currency, value: currency })); | ||
const formattedCurrencies = currenciesWithDisplayName.map((fiat) => ({ label: `${fiat.displayName} (${fiat.currency})`, value: fiat.currency })); |
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.
nit: this calls array map over and over but the formattedCurrencies are always the same. Maybe rates component could map once and export?
same with formattedCurrencies in defaultCurrencyDropdownSetting component (as it now always contains all currencies)
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.
Sure I'll do this, but these exported values are probably only gonna be used in the respective dropdown(s), as it's only used for exactly the dropdown/select component (thus it needs a label
and value
).
Will also move defaultValueLabel
😉 👓
which is the last selected currency in the DOM. | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):not(:nth-last-child(2))::after { | ||
content: ', '; |
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.
looks like space doens't work it seems to collapse and be ignored in pseudo element via content.
It would look nicer with a bit of space after the comma, can you add padding-right: 2px;
?
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.
Ooh lol good catch, I didnt even notice.. 🤔
:nth-last-child(2) is used for the same reason as above | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):nth-child(3):not(:nth-last-child(2))::after { | ||
content: ' ...'; |
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 CSS selector is a bit crazy :) but I guess adding …
via JSX would make the component a lot more complicated. then fine I guess…
remove space as it doesn't support leading space in content property and I think space is not needed from layout perspective.
and could you use …
tripple dot …
🤓 ?
/* | ||
displays ', ' as a pseudo component for all currency component | ||
except the last displayed component (the 3rd currency component). | ||
The reason for :nth-last-child(2) instead of just :last-child is because there's an extra | ||
component created by react-select after the actual last currency component. | ||
So, we're targetting the second to last component here, | ||
which is the last selected currency in the DOM. | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):not(:nth-last-child(2))::after { | ||
content: ', '; | ||
} | ||
|
||
/* | ||
displays '...' as a pseudo component of the 3rd currency and only when there's more than 3 selected. | ||
:nth-last-child(2) is used for the same reason as above | ||
*/ | ||
.select:not(.hideMultiSelect) :global(.react-select__multi-value):nth-child(3):not(:nth-last-child(2))::after { | ||
content: ' ...'; | ||
} | ||
|
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 "badges" with close button look cool, but I guess not necessary I guess better if we keep it minimal text-only for now.
isMulti | ||
closeMenuOnSelect={false} | ||
hideSelectedOptions={false} | ||
value={[...selectedCurrencies].reverse()} |
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.
ahh that makes sense, I was wondering what the order is and why it changes before. This way it always shows the newest nice 👍
import Select, { components, DropdownIndicatorProps, SingleValue as SingleValueType, SingleValueProps, OptionProps } from 'react-select'; | ||
import styles from './singledropdown.module.css'; | ||
import Select, { components, DropdownIndicatorProps, SingleValueProps, OptionProps } from 'react-select'; | ||
import dropdownStyles from '../dropdowns/dropdowns.module.css'; |
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.
from './dropdowns.module.css';
to improve our UI, we'd like to style our Active Currencies multi dropdown. In this commit we also refactored it, along with the single dropdown component.
ba438c6
to
9a8bd51
Compare
@thisconnect Thanks for the review! Changes made, PTAL 🙏 Also... yeah why not.. we can merge master to the staging branch first 🤷♂️ |
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.
thanks LGTM
…ect-dropdown-active-currencies
to improve our UI, we'd like to style our Active Currencies multi dropdown.
In this PR we also refactored it, along with the single dropdown component.
Most up-to-date preview:
Screen.Recording.2023-05-30.at.15.55.50.mov