← All changes
|
vendor/team-updraft/lib-onboarding-wizard/Wizard/Onboarding/src/utils/Icon.tsx
+36
-39
4.5.2
→
trunk
View file →
| @@ -1,7 +1,5 @@ | ||
| 1 | 1 | import { memo, type ComponentType, type KeyboardEvent, type ReactNode } from 'react'; |
| 2 | -import Tooltip from './Tooltip/Tooltip'; | |
| 3 | -import type { TooltipProps } from './Tooltip/Tooltip'; | |
| 4 | 2 | import customIcons from './customIcons'; |
| 5 | 3 | import materialIcons from './materialIcons'; |
| 6 | 4 | |
| 7 | 5 | // Color mapping from our custom colors to CSS variables |
| @@ -23,9 +21,8 @@ | ||
| 23 | 21 | name?: IconName; |
| 24 | 22 | color?: ColorName; |
| 25 | 23 | size?: number; |
| 26 | 24 | strokeWidth?: number; |
| 27 | - tooltip?: TooltipProps; | |
| 28 | 25 | onClick?: () => void; |
| 29 | 26 | className?: string; |
| 30 | 27 | stroke?: string; |
| 31 | 28 | fill?: string; |
| @@ -33,18 +30,17 @@ | ||
| 33 | 30 | } |
| 34 | 31 | |
| 35 | 32 | const Icon = memo(( |
| 36 | 33 | { |
| 37 | - name = 'bullet', | |
| 34 | + name, | |
| 38 | 35 | color = 'var(--teamupdraft-orange-dark)', |
| 39 | 36 | fill = 'var(--teamupdraft-orange-dark)', |
| 40 | 37 | size = 18, |
| 41 | 38 | stroke = 'none', |
| 42 | 39 | strokeWidth = 1.5, |
| 43 | - tooltip, | |
| 44 | 40 | onClick, |
| 45 | 41 | className, |
| 46 | - type = "material" | |
| 42 | + type | |
| 47 | 43 | }: IconProps) => { |
| 48 | 44 | // resolved color (CSS var or raw color) |
| 49 | 45 | const colorVal = (iconColors[color as keyof typeof iconColors] || color) as string; |
| 50 | 46 | |
| @@ -67,40 +63,49 @@ | ||
| 67 | 63 | |
| 68 | 64 | // choose which icon to render based on `type` prop or availability |
| 69 | 65 | let inner: ReactNode = null; |
| 70 | 66 | |
| 71 | - const customElement = CustomIcon ? ( | |
| 72 | - // custom SVG/React component: pass common props (your custom icons should accept these) | |
| 73 | - <CustomIcon width={size} height={size} stroke={stroke} strokeWidth={strokeWidth} color={colorVal} fill={fill} /> | |
| 74 | - ) : null; | |
| 67 | + // Check if 'name' is a URL | |
| 68 | + const isExternalUrl = typeof name === 'string' && (name.startsWith('http://') || name.startsWith('https://')); | |
| 75 | 69 | |
| 76 | - const materialElement = MaterialIcon ? ( | |
| 77 | - // MUI icons accept `sx` for size/color | |
| 78 | - <MaterialIcon sx={{ fontSize: size, color: colorVal,"& path": { | |
| 79 | - stroke: stroke, | |
| 80 | - strokeWidth: strokeWidth, | |
| 81 | - fill: fill, | |
| 82 | - }, }} /> | |
| 83 | - ) : null; | |
| 84 | - | |
| 85 | - if (type === 'custom') { | |
| 86 | - inner = customElement ?? materialElement; | |
| 87 | - } else if (type === 'material') { | |
| 88 | - inner = materialElement ?? customElement; | |
| 89 | - } else { | |
| 90 | - // no explicit type: prefer material if present, otherwise custom | |
| 91 | - inner = materialElement ?? customElement; | |
| 70 | + if (isExternalUrl) { | |
| 71 | + inner = <img src={name as string} alt="icon" style={{ width: size, height: size }} className="object-contain" />; | |
| 72 | + } else if (name) { // Only try to render if a name is provided and it's not a URL | |
| 73 | + if (type === 'custom') { | |
| 74 | + inner = CustomIcon ? ( | |
| 75 | + <CustomIcon width={size} height={size} stroke={stroke} strokeWidth={strokeWidth} color={colorVal} fill={fill} /> | |
| 76 | + ) : MaterialIcon ? ( | |
| 77 | + <MaterialIcon sx={{ fontSize: size, color: colorVal,"& path": { | |
| 78 | + stroke: stroke, | |
| 79 | + strokeWidth: strokeWidth, | |
| 80 | + fill: fill, | |
| 81 | + }, }} /> | |
| 82 | + ) : null; | |
| 83 | + } else { // Default to 'material' or if type is 'material' | |
| 84 | + inner = MaterialIcon ? ( | |
| 85 | + <MaterialIcon sx={{ fontSize: size, color: colorVal,"& path": { | |
| 86 | + stroke: stroke, | |
| 87 | + strokeWidth: strokeWidth, | |
| 88 | + fill: fill, | |
| 89 | + }, }} /> | |
| 90 | + ) : CustomIcon ? ( | |
| 91 | + <CustomIcon width={size} height={size} stroke={stroke} strokeWidth={strokeWidth} color={colorVal} fill={fill} /> | |
| 92 | + ) : null; | |
| 93 | + } | |
| 92 | 94 | } |
| 93 | 95 | |
| 94 | - // fallback: small filled circle (keeps layout predictable) | |
| 95 | - if (!inner) { | |
| 96 | + // fallback: small filled circle (keeps layout predictable) if a name was provided but no icon found | |
| 97 | + if (!inner && name) { | |
| 96 | 98 | inner = <span style={{ display: 'inline-block', width: size, height: size, borderRadius: '50%', background: colorVal }} />; |
| 99 | + } else if (!inner && !name) { // If no name is provided, render nothing | |
| 100 | + inner = null; | |
| 97 | 101 | } |
| 98 | 102 | |
| 103 | + | |
| 99 | 104 | const animateCss = String(name) === 'loading-circle' ? ' animate-spin' : ''; |
| 100 | 105 | const finalClass = `${className ?? ''} icon-${String(name)} flex items-center justify-center${animateCss}`.trim(); |
| 101 | 106 | |
| 102 | - const iconElement = ( | |
| 107 | + const iconElement = inner ? ( // Only render div if there's an inner element | |
| 103 | 108 | <div |
| 104 | 109 | role={onClick ? 'button' : undefined} |
| 105 | 110 | tabIndex={onClick ? 0 : undefined} |
| 106 | 111 | onClick={handleClick} |
| @@ -109,18 +114,10 @@ | ||
| 109 | 114 | aria-hidden={onClick ? undefined : true} |
| 110 | 115 | > |
| 111 | 116 | {inner} |
| 112 | 117 | </div> |
| 113 | - ); | |
| 118 | + ) : null; // If no inner, render nothing | |
| 114 | 119 | |
| 115 | - if (tooltip) { | |
| 116 | - return ( | |
| 117 | - <Tooltip tooltip={tooltip}> | |
| 118 | - {iconElement} | |
| 119 | - </Tooltip> | |
| 120 | - ); | |
| 121 | - } | |
| 122 | - | |
| 123 | 120 | return iconElement; |
| 124 | 121 | }); |
| 125 | 122 | |
| 126 | -export default Icon; | |
| 123 | +export default Icon; | |