import React, { forwardRef, useContext, HTMLAttributes } from "react"; import classNames from "classnames"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { library, FlipProp } from "@fortawesome/fontawesome-svg-core"; // far import { faFileAlt } from "@fortawesome/free-regular-svg-icons/faFileAlt"; import { faQuestionCircle as faQuestionCircleRegular } from "@fortawesome/free-regular-svg-icons/faQuestionCircle"; import { faUser as faUserRegular } from "@fortawesome/free-regular-svg-icons/faUser"; import { faCheckCircle as faCheckCircleRegular } from "@fortawesome/free-regular-svg-icons/faCheckCircle"; import { faTimesCircle } from "@fortawesome/free-regular-svg-icons/faTimesCircle"; import { faClock } from "@fortawesome/free-regular-svg-icons/faClock"; import { faKeyboard } from "@fortawesome/free-regular-svg-icons/faKeyboard"; import { faStar } from "@fortawesome/free-regular-svg-icons/faStar"; import { faThumbsDown } from "@fortawesome/free-regular-svg-icons/faThumbsDown"; import { faThumbsUp } from "@fortawesome/free-regular-svg-icons/faThumbsUp"; // fas import { faArchive } from "@fortawesome/free-solid-svg-icons/faArchive"; import { faArrowDown } from "@fortawesome/free-solid-svg-icons/faArrowDown"; import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft"; import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight"; import { faArrowUp } from "@fortawesome/free-solid-svg-icons/faArrowUp"; import { faBackward } from "@fortawesome/free-solid-svg-icons/faBackward"; import { faBan } from "@fortawesome/free-solid-svg-icons/faBan"; import { faBolt } from "@fortawesome/free-solid-svg-icons/faBolt"; import { faCalculator } from "@fortawesome/free-solid-svg-icons/faCalculator"; import { faCalendar } from "@fortawesome/free-solid-svg-icons/faCalendar"; import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown"; import { faCaretUp } from "@fortawesome/free-solid-svg-icons/faCaretUp"; import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck"; import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; import { faChevronLeft } from "@fortawesome/free-solid-svg-icons/faChevronLeft"; import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight"; import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; import { faCircle } from "@fortawesome/free-solid-svg-icons/faCircle"; import { faCircleNotch } from "@fortawesome/free-solid-svg-icons/faCircleNotch"; import { faClipboard } from "@fortawesome/free-solid-svg-icons/faClipboard"; import { faCog } from "@fortawesome/free-solid-svg-icons/faCog"; import { faColumns } from "@fortawesome/free-solid-svg-icons/faColumns"; import { faCommentAlt } from "@fortawesome/free-solid-svg-icons/faCommentAlt"; import { faCompress } from "@fortawesome/free-solid-svg-icons/faCompress"; import { faEllipsisH } from "@fortawesome/free-solid-svg-icons/faEllipsisH"; import { faEllipsisV } from "@fortawesome/free-solid-svg-icons/faEllipsisV"; import { faEnvelope } from "@fortawesome/free-solid-svg-icons/faEnvelope"; import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons/faExclamationTriangle"; import { faExpand } from "@fortawesome/free-solid-svg-icons/faExpand"; import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkAlt"; import { faExternalLinkSquareAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkSquareAlt"; import { faEye } from "@fortawesome/free-solid-svg-icons/faEye"; import { faEyeSlash } from "@fortawesome/free-solid-svg-icons/faEyeSlash"; import { faFastBackward } from "@fortawesome/free-solid-svg-icons/faFastBackward"; import { faFastForward } from "@fortawesome/free-solid-svg-icons/faFastForward"; import { faFileAlt as faFileAltSolid } from "@fortawesome/free-solid-svg-icons/faFileAlt"; import { faFileImport } from "@fortawesome/free-solid-svg-icons/faFileImport"; import { faFileSignature } from "@fortawesome/free-solid-svg-icons/faFileSignature"; import { faFilter } from "@fortawesome/free-solid-svg-icons/faFilter"; import { faFlag } from "@fortawesome/free-solid-svg-icons/faFlag"; import { faFolder } from "@fortawesome/free-solid-svg-icons/faFolder"; import { faForward } from "@fortawesome/free-solid-svg-icons/faForward"; import { faGripLines } from "@fortawesome/free-solid-svg-icons/faGripLines"; import { faGripLinesVertical } from "@fortawesome/free-solid-svg-icons/faGripLinesVertical"; import { faHashtag } from "@fortawesome/free-solid-svg-icons/faHashtag"; import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle"; import { faKey } from "@fortawesome/free-solid-svg-icons/faKey"; import { faLayerGroup } from "@fortawesome/free-solid-svg-icons/faLayerGroup"; import { faLevelUpAlt } from "@fortawesome/free-solid-svg-icons/faLevelUpAlt"; import { faListUl } from "@fortawesome/free-solid-svg-icons/faListUl"; import { faLock } from "@fortawesome/free-solid-svg-icons/faLock"; import { faLongArrowAltRight } from "@fortawesome/free-solid-svg-icons/faLongArrowAltRight"; import { faMagic } from "@fortawesome/free-solid-svg-icons/faMagic"; import { faMapSigns } from "@fortawesome/free-solid-svg-icons/faMapSigns"; import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus"; import { faPaperclip } from "@fortawesome/free-solid-svg-icons/faPaperclip"; import { faPause } from "@fortawesome/free-solid-svg-icons/faPause"; import { faPen } from "@fortawesome/free-solid-svg-icons/faPen"; import { faPlay } from "@fortawesome/free-solid-svg-icons/faPlay"; import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus"; import { faPlusCircle } from "@fortawesome/free-solid-svg-icons/faPlusCircle"; import { faPooStorm } from "@fortawesome/free-solid-svg-icons/faPooStorm"; import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons/faQuestionCircle"; import { faScroll } from "@fortawesome/free-solid-svg-icons/faScroll"; import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch"; import { faShieldAlt } from "@fortawesome/free-solid-svg-icons/faShieldAlt"; import { faSlidersH } from "@fortawesome/free-solid-svg-icons/faSlidersH"; import { faSort } from "@fortawesome/free-solid-svg-icons/faSort"; import { faSortDown } from "@fortawesome/free-solid-svg-icons/faSortDown"; import { faSortUp } from "@fortawesome/free-solid-svg-icons/faSortUp"; import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner"; import { faSquare } from "@fortawesome/free-solid-svg-icons/faSquare"; import { faStar as faStarSolid } from "@fortawesome/free-solid-svg-icons/faStar"; import { faSync } from "@fortawesome/free-solid-svg-icons/faSync"; import { faTasks } from "@fortawesome/free-solid-svg-icons/faTasks"; import { faThLarge } from "@fortawesome/free-solid-svg-icons/faThLarge"; import { faTicketAlt } from "@fortawesome/free-solid-svg-icons/faTicketAlt"; import { faTimes } from "@fortawesome/free-solid-svg-icons/faTimes"; import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash"; import { faUser } from "@fortawesome/free-solid-svg-icons/faUser"; import { faUserAstronaut } from "@fortawesome/free-solid-svg-icons/faUserAstronaut"; import { faUserPlus } from "@fortawesome/free-solid-svg-icons/faUserPlus"; import { faUsers } from "@fortawesome/free-solid-svg-icons/faUsers"; import { faUserFriends } from "@fortawesome/free-solid-svg-icons/faUserFriends"; // Custom icon SVGs import { DialogCheck, Scroll, Sparkle, TriangleDown, TriangleUp } from "./svg"; import { StatusContext } from "../../contexts/status"; import { STATUS_VARIANT } from "../../types"; import { bemHOF } from "../../utilities"; import { SvgProps } from "../Svg"; const cn = bemHOF("Icon"); library.add( faArchive, faArrowDown, faArrowLeft, faArrowRight, faArrowUp, faBackward, faBan, faBolt, faCalculator, faCalendar, faCaretDown, faCaretUp, faCheck, faCheckCircle, faCheckCircleRegular, faChevronDown, faChevronLeft, faChevronRight, faChevronUp, faCircle, faCircleNotch, faClipboard, faClock, faCog, faColumns, faCommentAlt, faCompress, faEllipsisH, faEllipsisV, faEnvelope, faExclamationTriangle, faExpand, faExternalLinkAlt, faExternalLinkSquareAlt, faEye, faEyeSlash, faFastBackward, faFastForward, faFileAlt, faFileAltSolid, faFileImport, faFileSignature, faFilter, faFlag, faFolder, faForward, faGripLines, faGripLinesVertical, faHashtag, faInfoCircle, faKey, faKeyboard, faLayerGroup, faLevelUpAlt, faListUl, faLock, faLongArrowAltRight, faMagic, faMapSigns, faMinus, faPaperclip, faPause, faPen, faPlay, faPlus, faPlusCircle, faPooStorm, faQuestionCircle, faQuestionCircleRegular, faScroll, faSearch, faShieldAlt, faSlidersH, faSort, faSortDown, faSortUp, faSpinner, faSquare, faStar, faStarSolid, faSync, faTasks, faThLarge, faThumbsDown, faThumbsUp, faTicketAlt, faTimes, faTimesCircle, faTrash, faUser, faUserAstronaut, faUserPlus, faUserRegular, faUsers, faUserFriends, ); export enum CUSTOM_ICON_TYPE { DIALOG_CHECK = "dialog-check", SCROLL = "scroll", SPARKLE = "sparkle", TRIANGLE_DOWN = "triangle-down", TRIANGLE_UP = "triangle-up", } type CustomIconPaths = Record< CUSTOM_ICON_TYPE, (props: SvgProps) => JSX.Element >; const CustomIcons: CustomIconPaths = { [CUSTOM_ICON_TYPE.DIALOG_CHECK]: DialogCheck, [CUSTOM_ICON_TYPE.SCROLL]: Scroll, [CUSTOM_ICON_TYPE.SPARKLE]: Sparkle, [CUSTOM_ICON_TYPE.TRIANGLE_DOWN]: TriangleDown, [CUSTOM_ICON_TYPE.TRIANGLE_UP]: TriangleUp, }; export enum ICON_TYPE { ARCHIVE = "archive", ARROW_DOWN = "arrow-down", ARROW_LEFT = "arrow-left", ARROW_RIGHT = "arrow-right", ARROW_UP = "arrow-up", BACKWARD = "backward", BAN = "ban", BOLT = "bolt", CALENDAR = "calendar", CALCULATOR = "calculator", CARET_DOWN = "caret-down", CARET_UP = "caret-up", CHECK = "check", CHECK_CIRCLE = "check-circle", CHEVRON_DOWN = "chevron-down", CHEVRON_LEFT = "chevron-left", CHEVRON_RIGHT = "chevron-right", CHEVRON_UP = "chevron-up", CIRCLE = "circle", CIRCLE_NOTCH = "circle-notch", CLOCK = "clock", CLIPBOARD = "clipboard", COG = "cog", COLUMNS = "columns", COMMENT_ALT = "comment-alt", COMPRESS = "compress", ELLIPSIS_H = "ellipsis-h", ELLIPSIS_V = "ellipsis-v", ENVELOPE = "envelope", EXCLAMATION_TRIANGLE = "exclamation-triangle", EXPAND = "expand", EXTERNAL_LINK_ALT = "external-link-alt", EXTERNAL_LINK_SQUARE_ALT = "external-link-square-alt", EYE = "eye", EYE_SLASH = "eye-slash", FAST_BACKWARD = "fast-backward", FAST_FORWARD = "fast-forward", FILE_ALT = "file-alt", FILE_IMPORT = "file-import", FILE_SIGNATURE = "file-signature", FILTER = "filter", FLAG = "flag", FOLDER = "folder", FORWARD = "forward", GRIP_LINES = "grip-lines", GRIP_LINES_VERTICAL = "grip-lines-vertical", HASHTAG = "hashtag", INFO_CIRCLE = "info-circle", KEY = "key", KEYBOARD = "keyboard", LAYER_GROUP = "layer-group", LEVEL_UP_ALT = "level-up-alt", LIST_UL = "list-ul", LOCK = "lock", LONG_ARROW_ALT_RIGHT = "long-arrow-alt-right", MAGIC = "magic", MAP_SIGNS = "map-signs", MINUS = "minus", PAPERCLIP = "paperclip", PAUSE = "pause", PEN = "pen", PLAY = "play", PLUS = "plus", PLUS_CIRCLE = "plus-circle", POO_STORM = "poo-storm", // Use in storybook examples QUESTION_CIRCLE = "question-circle", SCROLL = "scroll", SEARCH = "search", SHIELD_ALT = "shield-alt", SLIDERS_H = "sliders-h", SORT = "sort", SORT_DOWN = "sort-down", SORT_UP = "sort-up", SPINNER = "spinner", SQUARE = "square", STAR = "star", SYNC = "sync", TASKS = "tasks", TICKET_ALT = "ticket-alt", TIMES = "times", TIMES_CIRCLE = "times-circle", TH_LARGE = "th-large", THUMBS_DOWN = "thumbs-down", THUMBS_UP = "thumbs-up", TRASH = "trash", USER = "user", USER_ASTRONAUT = "user-astronaut", USER_PLUS = "user-plus", USERS = "users", USER_FRIENDS = "user-friends", } export enum ICON_STYLE_PREFIX { SOLID = "fas", REGULAR = "far", } interface BaseIconProps extends HTMLAttributes { color?: string; [key: string]: any; // Until comply is on typescript v4, this is needed to allow for data-testid attribute } export interface SharedFaIconProps extends BaseIconProps { spin?: boolean; prefix?: ICON_STYLE_PREFIX; flip?: FlipProp; } export interface FaIconProps extends SharedFaIconProps { icon: ICON_TYPE; } export interface CustomIconProps extends BaseIconProps { icon: CUSTOM_ICON_TYPE; } export type IconProps = FaIconProps | CustomIconProps; export interface StatusIconProps extends SharedFaIconProps { status?: STATUS_VARIANT; } const getIconClasses = ({ className, color, }: Pick) => classNames("inline-flex", className, color ? `text-${color}` : ""); export const Icon = forwardRef((props, ref) => { const isCustomIcon = Object.values(CUSTOM_ICON_TYPE).some( (i) => i === props.icon, ); if (isCustomIcon) { const { style, className, color, icon, ...rest } = props as CustomIconProps; const CustomIcon = CustomIcons[icon]; return ( ); } const { icon, style, className, spin = false, color, prefix: prefixProp, flip, ...rest } = props as FaIconProps; /** If no value is provided to the prefix prop, icons will revert to * default "fas" (solid) prefix unless otherwise set in this object. * * regular === "far" * */ const iconSetDefaults: { [key in ICON_TYPE]?: ICON_STYLE_PREFIX } = { [ICON_TYPE.FILE_ALT]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.TIMES_CIRCLE]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.CLOCK]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.KEYBOARD]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.STAR]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.THUMBS_DOWN]: ICON_STYLE_PREFIX.REGULAR, [ICON_TYPE.THUMBS_UP]: ICON_STYLE_PREFIX.REGULAR, }; const prefix: ICON_STYLE_PREFIX = prefixProp || iconSetDefaults[icon] || ICON_STYLE_PREFIX.SOLID; const faIcon: [ICON_STYLE_PREFIX, ICON_TYPE] = [prefix, icon]; return ( ); }); export const StatusIcon = forwardRef( ({ status: statusProp, ...rest }, ref) => { const context = useContext(StatusContext); let computedStatus = STATUS_VARIANT.DEFAULT; if (statusProp) { computedStatus = statusProp; } else if (context) { computedStatus = context; } let icon = ICON_TYPE.INFO_CIRCLE; switch (computedStatus) { case STATUS_VARIANT.SUCCESS: icon = ICON_TYPE.CHECK; break; case STATUS_VARIANT.WARNING: icon = ICON_TYPE.EXCLAMATION_TRIANGLE; break; case STATUS_VARIANT.DANGER: icon = ICON_TYPE.BAN; break; default: break; } return ; }, );