1- import React , { memo , useContext , useMemo } from 'react' ;
1+ import React , { memo , useMemo } from 'react' ;
22import { Animated , Text } from 'react-native' ;
33import type { StyleProp , TextStyle } from 'react-native' ;
44import type { IconName } from '@coinbase/cds-common/types/IconName' ;
@@ -8,7 +8,7 @@ import { isDevelopment } from '@coinbase/cds-utils';
88import { useTheme } from '../hooks/useTheme' ;
99
1010import type { IconProps } from './Icon' ;
11- import { DEFAULT_ICON_FONT_FAMILY , getIconSourceSize , IconGlyphSourceContext } from './createIcon' ;
11+ import { DEFAULT_ICON_FONT_FAMILY , getIconSourceSize , useResolvedGlyph } from './createIcon' ;
1212
1313export type TextIconProps = Pick < IconProps , 'color' | 'size' | 'testID' > & {
1414 name : IconName ;
@@ -23,6 +23,10 @@ export type TextIconProps = Pick<IconProps, 'color' | 'size' | 'testID'> & {
2323 style ?: StyleProp < TextStyle > ;
2424 }
2525 ) ;
26+
27+ /** Stable bound source so TextIcon participates in the same context resolution as Icon. */
28+ const cdsGlyphSource = { glyphMap, fontFamily : DEFAULT_ICON_FONT_FAMILY } ;
29+
2630/**
2731 *
2832 * This is a simplified, text-only version of the Icon component.
@@ -41,56 +45,39 @@ export const TextIcon = memo(function TextIcon({
4145 const theme = useTheme ( ) ;
4246 const Component = animated ? Animated . Text : Text ;
4347 const iconSize = theme . iconSize [ size ] ;
44- const sourceSize = getIconSourceSize ( iconSize ) ;
4548 const iconColor = theme . color [ color ] ;
4649
47- const contextSource = useContext ( IconGlyphSourceContext ) ;
48-
49- const iconKey = `${ name } -${ sourceSize } -${ active ? 'active' : 'inactive' } ` ;
50-
51- // Context source (e.g. retail-icons override) takes priority over the CDS glyphMap.
52- const contextGlyph = contextSource
53- ? contextSource . getGlyph
54- ? contextSource . getGlyph ( {
55- glyphMap : contextSource . glyphMap ,
56- name,
57- size,
58- pixelSize : iconSize ,
59- active : Boolean ( active ) ,
60- } )
61- : contextSource . glyphMap [ iconKey as keyof typeof contextSource . glyphMap ]
62- : undefined ;
63-
64- const glyph = contextGlyph ?? glyphMap [ iconKey as keyof typeof glyphMap ] ;
65- const fontFamily =
66- contextGlyph !== undefined
67- ? ( contextSource ?. fontFamily ?? DEFAULT_ICON_FONT_FAMILY )
68- : DEFAULT_ICON_FONT_FAMILY ;
50+ const resolved = useResolvedGlyph ( cdsGlyphSource , {
51+ name,
52+ size,
53+ pixelSize : iconSize ,
54+ active : Boolean ( active ) ,
55+ } ) ;
6956
7057 const styles = useMemo (
7158 ( ) =>
7259 [
7360 {
74- fontFamily,
61+ fontFamily : resolved ?. fontFamily ,
7562 fontSize : iconSize ,
7663 color : iconColor ,
7764 } ,
7865 style ,
7966 // TODO https://linear.app/coinbase/issue/CDS-1518/audit-potentially-harmful-reactnative-animated-pattern
8067 ] as StyleProp < TextStyle > ,
81- [ style , iconColor , iconSize , fontFamily ] ,
68+ [ style , iconColor , iconSize , resolved ?. fontFamily ] ,
8269 ) ;
8370
84- if ( glyph === undefined ) {
71+ if ( resolved === undefined ) {
8572 if ( isDevelopment ( ) ) {
86- console . error ( `Unable to find glyph for icon name "${ name } " with glyph key "${ iconKey } "` ) ;
73+ console . error ( `Unable to find glyph for icon name "${ name } " at size "${ size } "` ) ;
8774 }
8875 return null ;
8976 }
9077
9178 return (
9279 < Component accessibilityRole = "image" style = { styles } testID = { testID } >
93- { glyph }
80+ { resolved . char }
9481 </ Component >
9582 ) ;
9683} ) ;
0 commit comments