Skip to content

Commit

Permalink
Convert Chain Selection DropdownMenu to Backend Networks (#6344)
Browse files Browse the repository at this point in the history
* start work on converting existing chain selection dropdowns to Zeego

* available networks v2 convert

* add token icons to claim dropdown and fix but with AvailableNetworks not showing ever

* latest changes to try to get hitslop to work
  • Loading branch information
walmat authored Dec 23, 2024
1 parent 2a3d313 commit e093c7a
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 224 deletions.
52 changes: 13 additions & 39 deletions src/__swaps__/screens/Swap/components/TokenList/ChainSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import { ChainId } from '@/state/backendNetworks/types';
import { opacity } from '@/__swaps__/utils/swaps';
import { analyticsV2 } from '@/analytics';
import { ChainImage } from '@/components/coin-icon/ChainImage';
import { ContextMenuButton } from '@/components/context-menu';
import { AnimatedText, Bleed, Box, Inline, Text, TextIcon, globalColors, useColorMode } from '@/design-system';
import { useAccountAccentColor } from '@/hooks';
import { useSharedValueState } from '@/hooks/reanimated/useSharedValueState';
import { userAssetsStore, useUserAssetsStore } from '@/state/assets/userAssets';
import { swapsStore } from '@/state/swaps/swapsStore';
import { showActionSheetWithOptions } from '@/utils';
import { OnPressMenuItemEventObject } from 'react-native-ios-context-menu';
import { getChainsLabelWorklet, getChainsNameWorklet, useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { getChainsBadgeWorklet, getChainsLabelWorklet, useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { DropdownMenu, MenuItem } from '@/components/DropdownMenu';

type ChainSelectionProps = {
allText?: string;
Expand Down Expand Up @@ -58,7 +56,7 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
});

const handleSelectChain = useCallback(
({ nativeEvent: { actionKey } }: Omit<OnPressMenuItemEventObject, 'isUsingActionSheetFallback'>) => {
(actionKey: string) => {
analyticsV2.track(analyticsV2.event.swapsChangedChainId, {
inputAsset: swapsStore.getState().inputAsset,
type: output ? 'output' : 'input',
Expand All @@ -78,14 +76,16 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
);

const menuConfig = useMemo(() => {
const supportedChains = balanceSortedChainList.map(chainId => {
let supportedChains: MenuItem<string>[] = [];
supportedChains = balanceSortedChainList.map(chainId => {
return {
actionKey: `${chainId}`,
actionTitle: getChainsLabelWorklet(backendNetworks)[chainId],
icon: {
iconType: 'ASSET',
// NOTE: chainsName[chainId] for mainnet is 'mainnet' and we need it to be 'ethereum'
iconValue: chainId === ChainId.mainnet ? 'ethereumBadge' : `${getChainsNameWorklet(backendNetworks)[chainId]}BadgeNoShadow`,
iconType: 'REMOTE',
iconValue: {
uri: getChainsBadgeWorklet(backendNetworks)[chainId],
},
},
};
});
Expand All @@ -95,8 +95,8 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
actionKey: 'all',
actionTitle: i18n.t(i18n.l.exchange.all_networks),
icon: {
iconType: 'icon',
iconValue: '􀆪',
iconType: 'SYSTEM',
iconValue: 'globe',
},
});
}
Expand All @@ -106,24 +106,6 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
};
}, [backendNetworks, balanceSortedChainList, output]);

const onShowActionSheet = useCallback(() => {
const chainTitles = menuConfig.menuItems.map(chain => chain.actionTitle);

showActionSheetWithOptions(
{
options: chainTitles,
showSeparators: true,
},
(index: number | undefined) => {
// NOTE: When they click away from the menu, the index is undefined
if (typeof index === 'undefined') return;
handleSelectChain({
nativeEvent: { actionKey: menuConfig.menuItems[index].actionKey, actionTitle: '' },
});
}
);
}, [handleSelectChain, menuConfig.menuItems]);

return (
<Box as={Animated.View} paddingBottom={output ? '8px' : { custom: 14 }} paddingHorizontal="20px" paddingTop="20px">
<Inline alignHorizontal="justify" alignVertical="center">
Expand Down Expand Up @@ -166,16 +148,8 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
</Inline>
)}

<ContextMenuButton
hitSlop={20}
menuItems={menuConfig.menuItems}
menuTitle=""
onPressMenuItem={handleSelectChain}
onPressAndroid={onShowActionSheet}
testID={`chain-selection-${output ? 'output' : 'input'}`}
>
<DropdownMenu menuConfig={menuConfig} onPressMenuItem={handleSelectChain} testID={`chain-selection-${output ? 'output' : 'input'}`}>
<Inline alignVertical="center" space="6px" wrap={false}>
{/* TODO: We need to add some ethereum utils to handle worklet functions */}
<ChainButtonIcon output={output} />
<AnimatedText color={isDarkMode ? 'labelSecondary' : 'label'} size="15pt" weight="heavy">
{chainName}
Expand All @@ -184,7 +158,7 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
􀆏
</Text>
</Inline>
</ContextMenuButton>
</DropdownMenu>
</Inline>
</Box>
);
Expand Down
53 changes: 45 additions & 8 deletions src/components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
import React, { useCallback } from 'react';
import React, { ComponentProps, useCallback } from 'react';
import * as DropdownMenuPrimitive from 'zeego/dropdown-menu';
import styled from 'styled-components';
import { IconConfig, MenuActionConfig, MenuConfig as _MenuConfig } from 'react-native-ios-context-menu';
import { ImageSystemSymbolConfiguration } from 'react-native-ios-context-menu/lib/typescript/types/ImageItemConfig';
import { ImageSourcePropType } from 'react-native';
import { ImageSourcePropType, ImageURISource } from 'react-native';
import type { SFSymbols5_0 } from 'sf-symbols-typescript';
import type { DropdownMenuContentProps } from '@radix-ui/react-dropdown-menu';
import { ButtonPressAnimation } from './animations';
import { DebugLayout, HitSlop } from '@/design-system';

type ExtendedDropdownMenuTriggerProps = ComponentProps<typeof DropdownMenuPrimitive.Trigger> & {
hitSlop?: number;
testID?: string;
};

export const DropdownMenuRoot = DropdownMenuPrimitive.Root;
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
export const DropdownMenuTrigger = DropdownMenuPrimitive.create<ExtendedDropdownMenuTriggerProps>(
(props: ExtendedDropdownMenuTriggerProps) => {
// TODO: This hitslop isn't working properly...
return (
<DropdownMenuPrimitive.Trigger {...props} style={[props.style, { padding: props.hitSlop ?? 0 }]}>
<DebugLayout>
<ButtonPressAnimation testID={props.testID}>
<HitSlop space={{ custom: props.hitSlop ?? 0 }}>{props.children}</HitSlop>
</ButtonPressAnimation>
</DebugLayout>
</DropdownMenuPrimitive.Trigger>
);
},
'Trigger'
);
export const DropdownMenuContent = DropdownMenuPrimitive.Content;
export const DropdownMenuItem = DropdownMenuPrimitive.create(
styled(DropdownMenuPrimitive.CheckboxItem)({
Expand All @@ -30,12 +51,18 @@ export type MenuItemAssetImage = {
iconValue: ImageSourcePropType;
};

export type MenuItemIcon = Omit<IconConfig, 'iconValue' | 'iconType'> & (MenuItemSystemImage | MenuItemAssetImage);
export type MenuItemRemoteAssetImage = {
iconType: 'REMOTE';
iconValue: ImageURISource;
};

export type MenuItemIcon = Omit<IconConfig, 'iconValue' | 'iconType'> &
(MenuItemSystemImage | MenuItemAssetImage | MenuItemRemoteAssetImage);

export type MenuItem<T> = Omit<MenuActionConfig, 'icon'> & {
actionKey: T;
actionTitle: string;
icon?: MenuItemIcon | { iconType: string; iconValue: string };
icon?: MenuItemIcon;
};

export type MenuConfig<T extends string> = Omit<_MenuConfig, 'menuItems' | 'menuTitle'> & {
Expand All @@ -47,18 +74,24 @@ type DropDownMenuProps<T extends string> = {
children: React.ReactElement;
menuConfig: MenuConfig<T>;
onPressMenuItem: (actionKey: T) => void;
hitSlop?: number;
testID?: string;
} & DropdownMenuContentProps;

const buildIconConfig = (icon?: MenuItemIcon) => {
if (!icon) return null;

if (icon.iconType === 'SYSTEM' && typeof icon.iconValue === 'string') {
if (icon.iconType === 'SYSTEM') {
const ios = { name: icon.iconValue };

return <DropdownMenuItemIcon ios={ios} />;
}

if (icon.iconType === 'ASSET' && typeof icon.iconValue === 'object') {
if (icon.iconType === 'ASSET') {
return <DropdownMenuItemImage source={icon.iconValue} />;
}

if (icon.iconType === 'REMOTE') {
return <DropdownMenuItemImage source={icon.iconValue} />;
}

Expand All @@ -75,6 +108,8 @@ export function DropdownMenu<T extends string>({
side = 'right',
alignOffset = 5,
avoidCollisions = true,
hitSlop = 20,
testID,
}: DropDownMenuProps<T>) {
const handleSelectItem = useCallback(
(actionKey: T) => {
Expand All @@ -85,7 +120,9 @@ export function DropdownMenu<T extends string>({

return (
<DropdownMenuRoot>
<DropdownMenuTrigger>{children}</DropdownMenuTrigger>
<DropdownMenuTrigger asChild testID={testID} hitSlop={hitSlop}>
{children}
</DropdownMenuTrigger>
<DropdownMenuContent
loop={loop}
side={side}
Expand Down
Loading

0 comments on commit e093c7a

Please sign in to comment.