1import { css } from '@emotion/react'; 2import { 3 borderRadius, 4 iconSize, 5 theme, 6 typography, 7 ErrorIcon, 8 InfoIcon, 9 WarningIcon, 10} from '@expo/styleguide'; 11import { IconProps } from '@expo/styleguide/dist/types'; 12import React, { ComponentType, PropsWithChildren } from 'react'; 13 14type CalloutType = 'info' | 'warning' | 'error'; 15 16type CalloutProps = PropsWithChildren<{ 17 type?: CalloutType; 18 icon?: ComponentType<IconProps> | string; 19}>; 20 21export const Callout = ({ type = 'info', icon, children, ...rest }: CalloutProps) => { 22 const Icon = icon || getCalloutIcon(type); 23 return ( 24 <div css={[containerStyle, getCalloutColor(type)]} {...rest} data-testid="callout-container"> 25 <i css={iconStyle}>{typeof icon === 'string' ? icon : <Icon size={iconSize.small} />}</i> 26 <div css={contentStyle}>{children}</div> 27 </div> 28 ); 29}; 30 31function getCalloutColor(type: CalloutType) { 32 switch (type) { 33 case 'warning': 34 return warningColorStyle; 35 case 'error': 36 return errorColorStyle; 37 default: 38 return null; 39 } 40} 41 42function getCalloutIcon(type: CalloutType) { 43 switch (type) { 44 case 'warning': 45 return WarningIcon; 46 case 'error': 47 return ErrorIcon; 48 default: 49 return InfoIcon; 50 } 51} 52 53const containerStyle = css({ 54 backgroundColor: theme.background.secondary, 55 border: `1px solid ${theme.border.default}`, 56 borderRadius: borderRadius.medium, 57 display: 'flex', 58 padding: '1rem', 59}); 60 61const iconStyle = css({ 62 fontStyle: 'normal', 63 marginRight: '0.5rem', 64 userSelect: 'none', 65}); 66 67const contentStyle = css({ 68 ...typography.body.paragraph, 69 color: theme.text.default, 70 // Markdown adds paragraphs inside blockquotes, which is useful for multiline blockquotes. 71 // We need to forcefully remove the bottom margin on the last (or only) paragraph. 72 'p:last-child': { 73 marginBottom: '0 !important', // TODO(cedric): Find an alternative for important 74 }, 75}); 76 77const warningColorStyle = css({ 78 backgroundColor: theme.background.warning, 79 borderColor: theme.border.warning, 80}); 81 82const errorColorStyle = css({ 83 backgroundColor: theme.background.error, 84 borderColor: theme.border.error, 85}); 86