Added CurrencyFieldInput design (#4254)
* #4123 CurrencyFieldInput design is ready * resolved comment and currency code * resolved design comment --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
@ -0,0 +1,108 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { CurrencyCode } from '@/object-record/record-field/types/CurrencyCode';
|
||||
import { IconChevronDown } from '@/ui/display/icon';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
|
||||
import { CurrencyPickerHotkeyScope } from '../types/CurrencyPickerHotkeyScope';
|
||||
|
||||
import { CurrencyPickerDropdownSelect } from './CurrencyPickerDropdownSelect';
|
||||
|
||||
type StyledDropdownButtonProps = {
|
||||
isUnfolded: boolean;
|
||||
};
|
||||
|
||||
export const StyledDropdownButtonContainer = styled.div<StyledDropdownButtonProps>`
|
||||
align-items: center;
|
||||
color: ${({ color }) => color ?? 'none'};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
border-right: ${({ theme }) => `1px solid ${theme.border.color.medium}`};
|
||||
height: 32px;
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||
user-select: none;
|
||||
&:hover {
|
||||
filter: brightness(0.95);
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledIconContainer = styled.div`
|
||||
align-items: center;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
justify-content: center;
|
||||
|
||||
svg {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 16px;
|
||||
justify-content: center;
|
||||
}
|
||||
`;
|
||||
|
||||
export type Currency = {
|
||||
label: string;
|
||||
value: string;
|
||||
Icon: any;
|
||||
};
|
||||
|
||||
export const CurrencyPickerDropdownButton = ({
|
||||
valueCode,
|
||||
onChange,
|
||||
currencies,
|
||||
}: {
|
||||
valueCode: string;
|
||||
onChange: (currency: Currency) => void;
|
||||
currencies: Currency[];
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const [selectedCurrency, setSelectedCurrency] = useState<Currency>();
|
||||
|
||||
const { isDropdownOpen, closeDropdown } = useDropdown(
|
||||
CurrencyPickerHotkeyScope.CurrencyPicker,
|
||||
);
|
||||
|
||||
const handleChange = (currency: Currency) => {
|
||||
onChange(currency);
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const currency = currencies.find(({ value }) => value === valueCode);
|
||||
if (currency) {
|
||||
setSelectedCurrency(currency);
|
||||
}
|
||||
}, [valueCode, currencies]);
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownMenuWidth={200}
|
||||
dropdownId="currncy-picker-dropdown-id"
|
||||
dropdownHotkeyScope={{ scope: CurrencyPickerHotkeyScope.CurrencyPicker }}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
||||
<StyledIconContainer>
|
||||
{selectedCurrency ? selectedCurrency.value : CurrencyCode.USD}
|
||||
<IconChevronDown size={theme.icon.size.sm} />
|
||||
</StyledIconContainer>
|
||||
</StyledDropdownButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
<CurrencyPickerDropdownSelect
|
||||
currencies={currencies}
|
||||
selectedCurrency={selectedCurrency}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,71 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar';
|
||||
|
||||
import { Currency } from './CurrencyPickerDropdownButton';
|
||||
|
||||
export const CurrencyPickerDropdownSelect = ({
|
||||
currencies,
|
||||
selectedCurrency,
|
||||
onChange,
|
||||
}: {
|
||||
currencies: Currency[];
|
||||
selectedCurrency?: Currency;
|
||||
onChange: (currency: Currency) => void;
|
||||
}) => {
|
||||
const [searchFilter, setSearchFilter] = useState<string>('');
|
||||
|
||||
const filteredCurrencies = useMemo(
|
||||
() =>
|
||||
currencies.filter(
|
||||
({ value, label }) =>
|
||||
value
|
||||
.toLocaleLowerCase()
|
||||
.includes(searchFilter.toLocaleLowerCase()) ||
|
||||
label.toLocaleLowerCase().includes(searchFilter.toLocaleLowerCase()),
|
||||
),
|
||||
[currencies, searchFilter],
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownMenu width="200px" disableBlur>
|
||||
<DropdownMenuSearchInput
|
||||
value={searchFilter}
|
||||
onChange={(event) => setSearchFilter(event.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
{filteredCurrencies.length === 0 ? (
|
||||
<MenuItem text="No result" />
|
||||
) : (
|
||||
<>
|
||||
{selectedCurrency && (
|
||||
<MenuItemSelectAvatar
|
||||
key={selectedCurrency.value}
|
||||
selected={true}
|
||||
onClick={() => onChange(selectedCurrency)}
|
||||
text={`${selectedCurrency.label} (${selectedCurrency.value})`}
|
||||
/>
|
||||
)}
|
||||
{filteredCurrencies.map((item) =>
|
||||
selectedCurrency?.value === item.value ? null : (
|
||||
<MenuItemSelectAvatar
|
||||
key={item.value}
|
||||
selected={selectedCurrency?.value === item.value}
|
||||
onClick={() => onChange(item)}
|
||||
text={`${item.label} (${item.value})`}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,3 @@
|
||||
export enum CurrencyPickerHotkeyScope {
|
||||
CurrencyPicker = 'currency-picker',
|
||||
}
|
||||
Reference in New Issue
Block a user