VAIcon
- Properties
 - Example
 - Source Code
 - Accessibility
 
This component does not have props defined
How to use the VAIcon component
<VAIcon name={'Logo'} />
 
Full code for the VAIcon component
import React, { FC, useEffect } from 'react'
import { AppState, AppStateStatus } from 'react-native'
import { SvgProps } from 'react-native-svg'
import { useSelector } from 'react-redux'
import { Box, BoxProps } from 'components'
import FlagIconSvgs from 'components/VAIcon/flags'
// See VAIcon function documentation below for guidance on adding new SVGs
import Add from 'components/VAIcon/svgs/Add.svg'
import Building from 'components/VAIcon/svgs/Building.svg'
import CheckMark from 'components/VAIcon/svgs/CheckMark.svg'
import CircleCheckMark from 'components/VAIcon/svgs/CircleCheckMark.svg'
import Compose from 'components/VAIcon/svgs/Compose.svg'
import ExclamationTriangle from 'components/VAIcon/svgs/ExclamationTriangle.svg'
import ExternalLink from 'components/VAIcon/svgs/ExternalLink.svg'
import Folder from 'components/VAIcon/svgs/Folder.svg'
import Inbox from 'components/VAIcon/svgs/Inbox.svg'
import Info from 'components/VAIcon/svgs/Info.svg'
import Lock from 'components/VAIcon/svgs/Lock.svg'
import Minus from 'components/VAIcon/svgs/Minus.svg'
import PaperClip from 'components/VAIcon/svgs/PaperClip.svg'
import Phone from 'components/VAIcon/svgs/Phone.svg'
import QuestionMark from 'components/VAIcon/svgs/QuestionMark.svg'
import Redo from 'components/VAIcon/svgs/Redo.svg'
import Remove from 'components/VAIcon/svgs/Remove.svg'
import Reply from 'components/VAIcon/svgs/Reply.svg'
import Trash from 'components/VAIcon/svgs/Trash.svg'
import Unread from 'components/VAIcon/svgs/Unread.svg'
import UploadPhoto from 'components/VAIcon/svgs/UploadPhoto.svg'
import VASeal from 'components/VAIcon/svgs/VASeal.svg'
import VideoCamera from 'components/VAIcon/svgs/VideoCamera.svg'
// VASelector
import CheckBoxEmpty from 'components/VAIcon/svgs/checkbox/CheckBoxEmpty.svg'
import CheckBoxError from 'components/VAIcon/svgs/checkbox/CheckBoxError.svg'
import CheckBoxFilled from 'components/VAIcon/svgs/checkbox/CheckBoxFilled.svg'
import CheckBoxIntermediate from 'components/VAIcon/svgs/checkbox/CheckBoxIntermediate.svg'
// Links
import Calendar from 'components/VAIcon/svgs/links/Calendar.svg'
import Chat from 'components/VAIcon/svgs/links/Chat.svg'
import CircleExternalLink from 'components/VAIcon/svgs/links/CircleExternalLink.svg'
import CirclePhone from 'components/VAIcon/svgs/links/CirclePhone.svg'
import Directions from 'components/VAIcon/svgs/links/Directions.svg'
import PhoneTTY from 'components/VAIcon/svgs/links/PhoneTTY.svg'
import Text from 'components/VAIcon/svgs/links/Text.svg'
import RightArrowInCircle from 'components/VAIcon/svgs/links/right-arrow-blue-circle.svg'
// Navigation
import RadioEmpty from 'components/VAIcon/svgs/radio/RadioEmpty.svg'
import RadioFilled from 'components/VAIcon/svgs/radio/RadioFilled.svg'
import { RootState } from 'store'
import { AccessibilityState } from 'store/slices'
import { VAIconColors, VATextColors } from 'styles/theme'
import { updateFontScale } from 'utils/accessibility'
import { useAppDispatch, useFontScale, useTheme } from 'utils/hooks'
export const VA_ICON_MAP = {
  Add,
  Building,
  Calendar,
  Chat,
  CheckBoxEmpty,
  CheckBoxError,
  CheckBoxFilled,
  CheckBoxIntermediate,
  CheckMark,
  CircleCheckMark,
  CircleExternalLink,
  CirclePhone,
  Compose,
  Directions,
  ExclamationTriangle,
  ExternalLink,
  Folder,
  Inbox,
  Info,
  Lock,
  Minus,
  PaperClip,
  Phone,
  PhoneTTY,
  QuestionMark,
  RadioEmpty, // Also used for RadioDisabled content--same icon, different colors
  RadioFilled,
  Redo,
  Remove,
  Reply,
  RightArrowInCircle, // TODO: Ticket 3402 (or separate implementation ticket) to remove this icon
  Text,
  Trash,
  Unread,
  UploadPhoto,
  VASeal,
  VideoCamera,
  ...FlagIconSvgs,
}
export type VAIcons = keyof typeof VA_ICON_MAP
/**
 *  Props that need to be passed in to {@link VAIcon}
 */
export type VAIconProps = BoxProps & {
  /**  enum name of the icon to use {@link VA_ICON_MAP} **/
  name: VAIcons
  /** Fill color for the icon */
  fill?: keyof VAIconColors | keyof VATextColors | string
  /** Secondary fill color for duotone icons--fills icons inside main fill, defaults white */
  fill2?: keyof VAIconColors | keyof VATextColors | string
  /** Stroke color of the icon */
  stroke?: keyof VAIconColors | string
  /**  optional number use to set the width; otherwise defaults to svg's width */
  width?: number
  /**  optional number use to set the height; otherwise defaults to svg's height */
  height?: number
  /** optional maximum width when scaled (requires width and height props) */
  maxWidth?: number
  /** if true, prevents icon from being scaled (requires width and height props) */
  preventScaling?: boolean
  /** Optional TestID */
  testID?: string
}
/**
 * A common component to display assets (SVGs).
 *
 * For all icons in the SVG definitions, on the primary/only path:
 *    - Set `fill` to `#000` to inherit VAIcon's fill color prop
 * If the SVG icon is duotone, additionally:
 *    - Set `color` to `#fff` on the top level svg (not path)
 *    - Set `fill` to `currentColor` on the secondary path to inherit VAIcon's fill2 color prop
 * If the SVG icon uses stroke, additionally:
 *    - Set `stroke` to `#00F` to inherit VAIcon's stroke color prop
 *
 * Example icons of each classification:
 *    - One layer: HomeSelected.svg
 *    - Duotone: CircleCheckMark.svg
 *    - Stroke: RadioEmpty.svg
 *
 * @returns VAIcon component
 */
const VAIcon: FC<VAIconProps> = ({
  name,
  width,
  height,
  fill,
  fill2,
  stroke,
  maxWidth,
  preventScaling,
  testID,
  ...boxProps
}) => {
  const theme = useTheme()
  const fs: (val: number) => number = useFontScale()
  const dispatch = useAppDispatch()
  const { fontScale } = useSelector<RootState, AccessibilityState>((state) => state.accessibility)
  let iconProps = Object.create({ name, width, height, stroke, preventScaling, fill })
  useEffect(() => {
    // Listener for the current app state, updates the font scale when app state is active and the font scale has changed
    const sub = AppState.addEventListener('change', (newState: AppStateStatus): void =>
      updateFontScale(newState, fontScale, dispatch),
    )
    return (): void => sub?.remove()
  }, [dispatch, fontScale])
  if (fill) {
    iconProps = Object.assign({}, iconProps, {
      fill: theme.colors.icon[fill as keyof VAIconColors] || theme.colors.text[fill as keyof VATextColors] || fill,
    })
  }
  if (fill2) {
    iconProps = Object.assign({}, iconProps, {
      color: theme.colors.icon[fill2 as keyof VAIconColors] || theme.colors.text[fill2 as keyof VATextColors] || fill2,
    })
  }
  if (stroke) {
    iconProps = Object.assign({}, iconProps, { stroke: theme.colors.icon[stroke as keyof VAIconColors] || stroke })
  }
  const Icon: FC<SvgProps> | undefined = VA_ICON_MAP[name]
  if (!Icon) {
    return <></>
  }
  if (width && height) {
    if (preventScaling) {
      iconProps = { ...iconProps, width, height }
    } else if (maxWidth && fs(width) > maxWidth) {
      iconProps = { ...iconProps, width: maxWidth, height: (maxWidth / width) * height }
    } else {
      iconProps = { ...iconProps, width: fs(width), height: fs(height) }
    }
  }
  return (
    <Box testID={testID} {...boxProps}>
      <Icon {...iconProps} />
    </Box>
  )
}
export default VAIcon