PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / lib-onboarding-wizard / Wizard / Onboarding / src / utils / Icon.tsx

Icon.tsx in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/team-updraft/lib-onboarding-wizard/Wizard/Onboarding/src/utils/Icon.tsx

123 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { memo, type ComponentType, type KeyboardEvent, type ReactNode } from 'react';
2 import customIcons from './customIcons';
3 import materialIcons from './materialIcons';
4
5 // Color mapping from our custom colors to CSS variables
6 const iconColors = {
7 black: 'var(--teamupdraft-black)',
8 green: 'var(--teamupdraft-green)',
9 yellow: 'var(--teamupdraft-yellow)',
10 red: 'var(--teamupdraft-red)',
11 blue: 'var(--teamupdraft-blue)',
12 gray: 'var(--teamupdraft-grey-400)',
13 gray500: 'var(--teamupdraft-grey-500)',
14 white: 'var(--teamupdraft-white)',
15 };
16
17 export type IconName = keyof typeof materialIcons | keyof typeof customIcons | string;
18 export type ColorName = keyof typeof iconColors | string;
19
20 export interface IconProps {
21 name?: IconName;
22 color?: ColorName;
23 size?: number;
24 strokeWidth?: number;
25 onClick?: () => void;
26 className?: string;
27 stroke?: string;
28 fill?: string;
29 type?: 'material' | 'custom';
30 }
31
32 const Icon = memo((
33 {
34 name,
35 color = 'var(--teamupdraft-orange-dark)',
36 fill = 'var(--teamupdraft-orange-dark)',
37 size = 18,
38 stroke = 'none',
39 strokeWidth = 1.5,
40 onClick,
41 className,
42 type
43 }: IconProps) => {
44 // resolved color (CSS var or raw color)
45 const colorVal = (iconColors[color as keyof typeof iconColors] || color) as string;
46
47 // try to resolve components from both maps (may be undefined)
48 const MaterialIcon = (materialIcons as Record<string, ComponentType<any>>)[String(name)];
49 const CustomIcon = (customIcons as Record<string, ComponentType<any>>)[String(name)];
50
51 // click handler (keyboard accessible)
52 const handleClick = () => {
53 if (onClick) onClick();
54 };
55
56 const handleKeyDown = (e: KeyboardEvent) => {
57 if (!onClick) return;
58 if (e.key === 'Enter' || e.key === ' ') {
59 e.preventDefault();
60 onClick();
61 }
62 };
63
64 // choose which icon to render based on `type` prop or availability
65 let inner: ReactNode = null;
66
67 // Check if 'name' is a URL
68 const isExternalUrl = typeof name === 'string' && (name.startsWith('http://') || name.startsWith('https://'));
69
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 }
94 }
95
96 // fallback: small filled circle (keeps layout predictable) if a name was provided but no icon found
97 if (!inner && name) {
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;
101 }
102
103
104 const animateCss = String(name) === 'loading-circle' ? ' animate-spin' : '';
105 const finalClass = `${className ?? ''} icon-${String(name)} flex items-center justify-center${animateCss}`.trim();
106
107 const iconElement = inner ? ( // Only render div if there's an inner element
108 <div
109 role={onClick ? 'button' : undefined}
110 tabIndex={onClick ? 0 : undefined}
111 onClick={handleClick}
112 onKeyDown={handleKeyDown}
113 className={finalClass}
114 aria-hidden={onClick ? undefined : true}
115 >
116 {inner}
117 </div>
118 ) : null; // If no inner, render nothing
119
120 return iconElement;
121 });
122
123 export default Icon;