IconByVariant.tsx 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import type { ReactElement } from 'react';
  2. import type { SvgProps } from 'react-native-svg';
  3. import { useMemo } from 'react';
  4. import * as z from 'zod';
  5. import { useTheme } from '@/theme';
  6. import getAssetsContext from '@/theme/assets/getAssetsContext';
  7. type Properties = {
  8. readonly path: string;
  9. } & SvgProps;
  10. const icons = getAssetsContext('icons');
  11. const EXTENSION = 'svg';
  12. const SIZE = 24;
  13. function IconByVariant({
  14. height = SIZE,
  15. path,
  16. width = SIZE,
  17. ...props
  18. }: Properties) {
  19. const { variant } = useTheme();
  20. const iconProperties = { ...props, height, width };
  21. const Icon = useMemo(() => {
  22. try {
  23. const getDefaultSource = () =>
  24. z
  25. .object({
  26. default: z.custom<React.FC<SvgProps>>(() =>
  27. z.custom<ReactElement<SvgProps>>(),
  28. ),
  29. })
  30. .parse(icons(`./${path}.${EXTENSION}`)).default;
  31. if (variant === 'default') {
  32. return getDefaultSource();
  33. }
  34. try {
  35. const fetchedModule = z
  36. .object({
  37. default: z.custom<React.FC<SvgProps>>(() =>
  38. z.custom<ReactElement<SvgProps>>(),
  39. ),
  40. })
  41. .parse(icons(`./${variant}/${path}.${EXTENSION}`));
  42. return fetchedModule.default;
  43. } catch (error) {
  44. console.warn(
  45. `Couldn't load the icon: ${path}.${EXTENSION} for the variant ${variant}, Fallback to default`,
  46. error,
  47. );
  48. return getDefaultSource();
  49. }
  50. } catch (error) {
  51. console.error(`Couldn't load the icon: ${path}.${EXTENSION}`, error);
  52. throw error;
  53. }
  54. }, [variant, path]);
  55. return <Icon {...iconProperties} />;
  56. }
  57. export default IconByVariant;