Files
twenty/front/src/modules/ui/input/components/IconPicker.tsx
T
Charles Bochet 258685467b Refactor UI folder (#2016)
* Added Overview page

* Revised Getting Started page

* Minor revision

* Edited readme, minor modifications to docs

* Removed sweep.yaml, .devcontainer, .ergomake

* Moved security.md to .github, added contributing.md

* changes as per code review

* updated contributing.md

* fixed broken links & added missing links in doc, improved structure

* fixed link in wsl setup

* fixed server link, added https cloning in yarn-setup

* removed package-lock.json

* added doc card, admonitions

* removed underline from nav buttons

* refactoring modules/ui

* refactoring modules/ui

* Change folder case

* Fix theme location

* Fix case 2

* Fix storybook

---------

Co-authored-by: Nimra Ahmed <nimra1408@gmail.com>
Co-authored-by: Nimra Ahmed <50912134+nimraahmed@users.noreply.github.com>
2023-10-14 00:04:29 +02:00

128 lines
4.4 KiB
TypeScript

import { useEffect, useMemo, useState } from 'react';
import styled from '@emotion/styled';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
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 { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { IconButton } from '../button/components/IconButton';
import { LightIconButton } from '../button/components/LightIconButton';
import { IconApps } from '../constants/icons';
import { DropdownMenuSkeletonItem } from '../relation-picker/components/skeletons/DropdownMenuSkeletonItem';
import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope';
type IconPickerProps = {
onChange: (params: { iconKey: string; Icon: IconComponent }) => void;
selectedIconKey?: string;
onClickOutside?: () => void;
onClose?: () => void;
onOpen?: () => void;
};
const StyledMenuIconItemsContainer = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
`;
const StyledLightIconButton = styled(LightIconButton)<{ isSelected?: boolean }>`
background: ${({ theme, isSelected }) =>
isSelected ? theme.background.transparent.light : 'transparent'};
`;
const convertIconKeyToLabel = (iconKey: string) =>
iconKey.replace(/[A-Z]/g, (letter) => ` ${letter}`).trim();
export const IconPicker = ({
onChange,
selectedIconKey,
onClickOutside,
onClose,
onOpen,
}: IconPickerProps) => {
const [searchString, setSearchString] = useState('');
const [isLoading, setIsLoading] = useState(true);
const [icons, setIcons] = useState<Record<string, IconComponent>>({});
const { closeDropdown } = useDropdown({ dropdownScopeId: 'icon-picker' });
useEffect(() => {
import('../constants/icons').then((lazyLoadedIcons) => {
setIcons(lazyLoadedIcons);
setIsLoading(false);
});
}, []);
const iconKeys = useMemo(() => {
const filteredIconKeys = Object.keys(icons).filter(
(iconKey) =>
iconKey !== selectedIconKey &&
(!searchString ||
[iconKey, convertIconKeyToLabel(iconKey)].some((label) =>
label.toLowerCase().includes(searchString.toLowerCase()),
)),
);
return (
selectedIconKey
? [selectedIconKey, ...filteredIconKeys]
: filteredIconKeys
).slice(0, 25);
}, [icons, searchString, selectedIconKey]);
return (
<DropdownScope dropdownScopeId="icon-picker">
<DropdownMenu
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
clickableComponent={
<IconButton
Icon={selectedIconKey ? icons[selectedIconKey] : IconApps}
variant="secondary"
/>
}
dropdownComponents={
<StyledDropdownMenu width={168}>
<DropdownMenuSearchInput
placeholder="Search icon"
autoFocus
onChange={(event) => setSearchString(event.target.value)}
/>
<StyledDropdownMenuSeparator />
<DropdownMenuItemsContainer>
{isLoading ? (
<DropdownMenuSkeletonItem />
) : (
<StyledMenuIconItemsContainer>
{iconKeys.map((iconKey) => (
<StyledLightIconButton
aria-label={convertIconKeyToLabel(iconKey)}
isSelected={selectedIconKey === iconKey}
size="medium"
Icon={icons[iconKey]}
onClick={() => {
onChange({ iconKey, Icon: icons[iconKey] });
closeDropdown();
}}
/>
))}
</StyledMenuIconItemsContainer>
)}
</DropdownMenuItemsContainer>
</StyledDropdownMenu>
}
onClickOutside={onClickOutside}
onClose={() => {
onClose?.();
setSearchString('');
}}
onOpen={onOpen}
></DropdownMenu>
</DropdownScope>
);
};