IconBase.tsx131 lines · main
| 1 | 'use client' |
| 2 | |
| 3 | import React from 'react' |
| 4 | |
| 5 | import styleHandler from '../../lib/theme/styleHandler' |
| 6 | import { cn } from '../../lib/utils/cn' |
| 7 | import { IconContext } from './IconContext' |
| 8 | |
| 9 | // @ts-ignore |
| 10 | // import IconStyles from './Icon.module.css' |
| 11 | |
| 12 | interface Props { |
| 13 | className?: string |
| 14 | size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge' | 'xxlarge' | 'xxxlarge' | number |
| 15 | type?: string |
| 16 | color?: string |
| 17 | strokeWidth?: number |
| 18 | fill?: string |
| 19 | stroke?: string |
| 20 | background?: 'brand' | 'gray' | 'red' | 'yellow' | 'green' | 'blue' | 'indigo' | 'purple' | 'pink' |
| 21 | src?: React.ReactNode |
| 22 | icon?: any |
| 23 | viewBox?: string |
| 24 | } |
| 25 | |
| 26 | interface StringMap { |
| 27 | [key: string]: number |
| 28 | } |
| 29 | |
| 30 | function IconBase({ |
| 31 | className, |
| 32 | size, |
| 33 | type = 'Mail', |
| 34 | color, |
| 35 | strokeWidth, |
| 36 | fill = undefined, |
| 37 | stroke = undefined, |
| 38 | background, |
| 39 | src, |
| 40 | icon, |
| 41 | ...props |
| 42 | }: Props) { |
| 43 | const __styles = styleHandler('icon') |
| 44 | |
| 45 | return ( |
| 46 | <IconContext.Consumer> |
| 47 | {({ contextSize, className: contextClassName }) => { |
| 48 | const defaultSizes: StringMap = { |
| 49 | tiny: 14, |
| 50 | small: 18, |
| 51 | medium: 20, |
| 52 | large: 20, |
| 53 | xlarge: 24, |
| 54 | xxlarge: 30, |
| 55 | xxxlarge: 42, |
| 56 | } |
| 57 | |
| 58 | const defaultSize = defaultSizes['large'] |
| 59 | // @ts-ignore |
| 60 | |
| 61 | const FeatherIcon = icon |
| 62 | |
| 63 | // const iconSize = typeof size === 'string' ? defaultSizes[contextSize] : 21 |
| 64 | let iconSize: any = 21 |
| 65 | |
| 66 | // use contextSize of parent (via context hook) if one exists |
| 67 | if (contextSize) { |
| 68 | iconSize = contextSize |
| 69 | ? typeof contextSize === 'string' |
| 70 | ? defaultSizes[contextSize] |
| 71 | : contextSize |
| 72 | : defaultSize |
| 73 | } |
| 74 | |
| 75 | // use size prop of this component if one exists |
| 76 | if (size) { |
| 77 | iconSize = size ? (typeof size === 'string' ? defaultSizes[size] : size) : defaultSize |
| 78 | } |
| 79 | |
| 80 | // confitional used for Icons with no color settings |
| 81 | // default these icons to use 'currentColor' ie, the text color |
| 82 | const noColor = !color && !fill && !stroke |
| 83 | |
| 84 | let classes = ['sbui-icon', className] |
| 85 | if (contextClassName) { |
| 86 | classes.push(contextClassName) |
| 87 | } |
| 88 | |
| 89 | const IconComponent = () => ( |
| 90 | <FeatherIcon |
| 91 | color={!noColor ? color : 'currentColor'} |
| 92 | stroke={!noColor ? stroke : 'currentColor'} |
| 93 | className={cn(classes)} |
| 94 | strokeWidth={strokeWidth} |
| 95 | size={iconSize} |
| 96 | fill={!noColor ? (fill ? fill : 'none') : 'none'} |
| 97 | {...props} |
| 98 | /> |
| 99 | ) |
| 100 | |
| 101 | const Icon = src ? ( |
| 102 | // custom SVG file |
| 103 | <div className="relative" style={{ width: iconSize + 'px', height: iconSize + 'px' }}> |
| 104 | <svg |
| 105 | xmlns="http://www.w3.org/2000/svg" |
| 106 | viewBox="0 0 16 16" |
| 107 | color={!noColor ? color : 'currentColor'} |
| 108 | fill={!noColor ? (fill ? fill : 'none') : 'none'} |
| 109 | stroke={!noColor ? stroke : 'currentColor'} |
| 110 | className={cn(classes)} |
| 111 | width="100%" |
| 112 | height="100%" |
| 113 | strokeWidth={strokeWidth ?? undefined} |
| 114 | {...props} |
| 115 | > |
| 116 | {/* Import custom icon path from svg with 16x16px viewport */} |
| 117 | {src} |
| 118 | </svg> |
| 119 | </div> |
| 120 | ) : ( |
| 121 | // feather icon |
| 122 | IconComponent() |
| 123 | ) |
| 124 | |
| 125 | return background ? <div className={__styles.container}>{Icon}</div> : Icon |
| 126 | }} |
| 127 | </IconContext.Consumer> |
| 128 | ) |
| 129 | } |
| 130 | |
| 131 | export default IconBase |