Fix Icon Lazy Loading (#2984)

Fix Icon picker
This commit is contained in:
Charles Bochet
2023-12-14 12:13:02 +01:00
committed by GitHub
parent ed2cd408bf
commit 8916dee352
33 changed files with 4366 additions and 192 deletions

View File

@ -0,0 +1,20 @@
import { useEffect } from 'react';
import { useSetRecoilState } from 'recoil';
import { iconsState } from '@/ui/display/icon/states/iconsState';
type IconsProviderProps = {
children: JSX.Element;
};
export const IconsProvider = ({ children }: IconsProviderProps) => {
const setIcons = useSetRecoilState(iconsState);
useEffect(() => {
import('../constants/index').then((lazyLoadedIcons) => {
setIcons(lazyLoadedIcons.default);
});
}, [setIcons]);
return children;
};

View File

@ -0,0 +1,20 @@
import { useRecoilValue } from 'recoil';
import { Icon123 } from '@/ui/display/icon';
import { iconsState } from '@/ui/display/icon/states/iconsState';
export const useIcons = () => {
const icons = useRecoilValue(iconsState);
const defaultIcon = Icon123;
const getIcons = () => {
return icons;
};
const getIcon = (iconKey?: string | null) => {
if (!iconKey) return defaultIcon;
return icons[iconKey] ?? defaultIcon;
};
return { getIcons, getIcon };
};

View File

@ -1,8 +1,10 @@
/* eslint-disable no-restricted-imports */
export type { TablerIconsProps } from '@tabler/icons-react';
export {
Icon123,
IconAlertCircle,
IconAlertTriangle,
IconApps,
IconArchive,
IconArchiveOff,
IconArrowDown,
@ -36,19 +38,25 @@ export {
IconCopy,
IconCurrencyDollar,
IconDatabase,
IconDeviceFloppy,
IconDotsVertical,
IconDownload,
IconEye,
IconEyeOff,
IconFile,
IconFileCheck,
IconFileImport,
IconFileText,
IconFileUpload,
IconFileZip,
IconForbid,
IconGripVertical,
IconHeadphones,
IconHeart,
IconHeartOff,
IconHelpCircle,
IconHierarchy2,
IconInfoCircle,
IconKey,
IconLanguage,
IconLayoutKanban,
@ -70,8 +78,10 @@ export {
IconPaperclip,
IconPencil,
IconPhone,
IconPhoto,
IconPlug,
IconPlus,
IconPresentation,
IconProgressCheck,
IconRelationManyToMany,
IconRelationOneToMany,
@ -80,6 +90,7 @@ export {
IconRobot,
IconSearch,
IconSettings,
IconTable,
IconTag,
IconTarget,
IconTargetArrow,
@ -90,5 +101,7 @@ export {
IconUser,
IconUserCircle,
IconUsers,
IconVideo,
IconWorld,
IconX,
} from '@tabler/icons-react';

View File

@ -1,6 +1,8 @@
import { useMemo, useState } from 'react';
import styled from '@emotion/styled';
import { IconApps } from '@/ui/display/icon';
import { useIcons } from '@/ui/display/icon/hooks/useIcons';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
@ -16,9 +18,6 @@ import { arrayToChunks } from '~/utils/array/array-to-chunks';
import { IconButton, IconButtonVariant } from '../button/components/IconButton';
import { LightIconButton } from '../button/components/LightIconButton';
import { IconApps } from '../constants/icons';
import { useLazyLoadIcons } from '../hooks/useLazyLoadIcons';
import { DropdownMenuSkeletonItem } from '../relation-picker/components/skeletons/DropdownMenuSkeletonItem';
import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope';
type IconPickerProps = {
@ -95,7 +94,8 @@ export const IconPicker = ({
const { closeDropdown } = useDropdown({ dropdownScopeId });
const { icons, isLoadingIcons: isLoading } = useLazyLoadIcons();
const { getIcons, getIcon } = useIcons();
const { icons } = getIcons();
const iconKeys = useMemo(() => {
const filteredIconKeys = Object.keys(icons).filter((iconKey) => {
@ -128,7 +128,7 @@ export const IconPicker = ({
clickableComponent={
<IconButton
disabled={disabled}
Icon={selectedIconKey ? icons[selectedIconKey] : IconApps}
Icon={selectedIconKey ? getIcon(selectedIconKey) : IconApps}
variant={variant}
/>
}
@ -139,7 +139,7 @@ export const IconPicker = ({
selectableItemIds={iconKeys2d}
hotkeyScope={IconPickerHotkeyScope.IconPicker}
onEnter={(iconKey) => {
onChange({ iconKey, Icon: icons[iconKey] });
onChange({ iconKey, Icon: getIcon(iconKey) });
closeDropdown();
}}
>
@ -159,24 +159,20 @@ export const IconPicker = ({
onMouseLeave={goBackToPreviousHotkeyScope}
>
<DropdownMenuItemsContainer>
{isLoading ? (
<DropdownMenuSkeletonItem />
) : (
<StyledMenuIconItemsContainer>
{iconKeys.map((iconKey) => (
<IconPickerIcon
key={iconKey}
iconKey={iconKey}
onClick={() => {
onChange({ iconKey, Icon: icons[iconKey] });
closeDropdown();
}}
selectedIconKey={selectedIconKey}
Icon={icons[iconKey]}
/>
))}
</StyledMenuIconItemsContainer>
)}
<StyledMenuIconItemsContainer>
{iconKeys.map((iconKey) => (
<IconPickerIcon
key={iconKey}
iconKey={iconKey}
onClick={() => {
onChange({ iconKey, Icon: getIcon(iconKey) });
closeDropdown();
}}
selectedIconKey={selectedIconKey}
Icon={getIcon(iconKey)}
/>
))}
</StyledMenuIconItemsContainer>
</DropdownMenuItemsContainer>
</div>
</DropdownMenu>

View File

@ -6,8 +6,7 @@ import { hasFlag } from 'country-flag-icons';
import * as Flags from 'country-flag-icons/react/3x2';
import { CountryCallingCode } from 'libphonenumber-js';
import { IconChevronDown } from '@/ui/display/icon';
import { IconWorld } from '@/ui/input/constants/icons';
import { IconChevronDown, IconWorld } from '@/ui/display/icon';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';

View File

@ -1,22 +0,0 @@
import { useEffect, useState } from 'react';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { useLazyLoadIcons } from './useLazyLoadIcons';
export const useLazyLoadIcon = (iconKey: string) => {
const { isLoadingIcons, icons } = useLazyLoadIcons();
const [Icon, setIcon] = useState<IconComponent | undefined>();
const [isLoadingIcon, setIsLoadingIcon] = useState(true);
useEffect(() => {
if (!iconKey) return;
if (!isLoadingIcons) {
setIcon(icons[iconKey]);
setIsLoadingIcon(false);
}
}, [iconKey, icons, isLoadingIcons]);
return { Icon, isLoadingIcon };
};

View File

@ -1,18 +0,0 @@
import { useEffect, useState } from 'react';
import { useRecoilState } from 'recoil';
import { iconsState } from '@/ui/input/states/iconsState';
export const useLazyLoadIcons = () => {
const [icons, setIcons] = useRecoilState(iconsState);
const [isLoadingIcons, setIsLoadingIcons] = useState(true);
useEffect(() => {
import('../constants/icons').then((lazyLoadedIcons) => {
setIcons(lazyLoadedIcons);
setIsLoadingIcons(false);
});
}, [setIcons]);
return { icons, isLoadingIcons };
};

View File

@ -1,9 +1,8 @@
import { atom } from 'recoil';
import { IconApps } from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { IconApps } from '../constants/icons';
type IconPickerState = {
Icon: IconComponent;
iconKey: string;