@idealyst/components 1.0.83 → 1.0.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/CLAUDE.md +199 -232
  2. package/README.md +5 -5
  3. package/package.json +20 -2
  4. package/plugin/README.md +272 -0
  5. package/plugin/test-cases.jsx +112 -0
  6. package/plugin/web-legacy.js +320 -0
  7. package/plugin/web.js +422 -124
  8. package/src/Accordion/Accordion.native.tsx +182 -0
  9. package/src/Accordion/Accordion.styles.tsx +260 -0
  10. package/src/Accordion/Accordion.web.tsx +147 -0
  11. package/src/Accordion/index.native.tsx +3 -0
  12. package/src/Accordion/index.ts +3 -0
  13. package/src/Accordion/index.web.tsx +3 -0
  14. package/src/Accordion/types.ts +23 -0
  15. package/src/ActivityIndicator/ActivityIndicator.native.tsx +17 -12
  16. package/src/ActivityIndicator/ActivityIndicator.styles.tsx +83 -109
  17. package/src/ActivityIndicator/ActivityIndicator.web.tsx +23 -17
  18. package/src/ActivityIndicator/index.ts +5 -2
  19. package/src/ActivityIndicator/index.web.ts +5 -2
  20. package/src/ActivityIndicator/types.ts +15 -10
  21. package/src/Alert/Alert.native.tsx +113 -0
  22. package/src/Alert/Alert.styles.tsx +304 -0
  23. package/src/Alert/Alert.web.tsx +123 -0
  24. package/src/Alert/index.native.ts +5 -0
  25. package/src/Alert/index.ts +5 -0
  26. package/src/Alert/index.web.ts +5 -0
  27. package/src/Alert/types.ts +21 -0
  28. package/src/Avatar/Avatar.native.tsx +8 -6
  29. package/src/Avatar/Avatar.styles.tsx +64 -58
  30. package/src/Avatar/Avatar.web.tsx +13 -8
  31. package/src/Avatar/index.ts +5 -2
  32. package/src/Avatar/index.web.ts +5 -2
  33. package/src/Avatar/types.ts +19 -13
  34. package/src/Badge/Badge.native.tsx +59 -14
  35. package/src/Badge/Badge.styles.tsx +125 -139
  36. package/src/Badge/Badge.web.tsx +72 -16
  37. package/src/Badge/index.ts +5 -2
  38. package/src/Badge/index.web.ts +5 -2
  39. package/src/Badge/types.ts +23 -11
  40. package/src/Breadcrumb/Breadcrumb.native.tsx +225 -0
  41. package/src/Breadcrumb/Breadcrumb.styles.tsx +234 -0
  42. package/src/Breadcrumb/Breadcrumb.web.tsx +268 -0
  43. package/src/Breadcrumb/index.native.ts +5 -0
  44. package/src/Breadcrumb/index.ts +5 -0
  45. package/src/Breadcrumb/index.web.ts +5 -0
  46. package/src/Breadcrumb/types.ts +56 -0
  47. package/src/Button/Button.native.tsx +75 -24
  48. package/src/Button/Button.styles.tsx +248 -205
  49. package/src/Button/Button.web.tsx +82 -25
  50. package/src/Button/index.ts +5 -5
  51. package/src/Button/index.web.ts +5 -3
  52. package/src/Button/types.ts +32 -15
  53. package/src/Card/Card.native.tsx +14 -11
  54. package/src/Card/Card.styles.tsx +146 -220
  55. package/src/Card/Card.web.tsx +20 -21
  56. package/src/Card/index.ts +5 -5
  57. package/src/Card/index.web.ts +5 -3
  58. package/src/Card/types.ts +24 -17
  59. package/src/Checkbox/Checkbox.native.tsx +24 -34
  60. package/src/Checkbox/Checkbox.styles.tsx +223 -275
  61. package/src/Checkbox/Checkbox.web.tsx +30 -37
  62. package/src/Checkbox/index.ts +5 -5
  63. package/src/Checkbox/index.web.ts +5 -3
  64. package/src/Checkbox/types.ts +26 -20
  65. package/src/Chip/Chip.native.tsx +126 -0
  66. package/src/Chip/Chip.styles.tsx +138 -0
  67. package/src/Chip/Chip.web.tsx +154 -0
  68. package/src/Chip/index.native.ts +5 -0
  69. package/src/Chip/index.ts +5 -0
  70. package/src/Chip/index.web.ts +5 -0
  71. package/src/Chip/types.ts +51 -0
  72. package/src/Dialog/Dialog.native.tsx +65 -12
  73. package/src/Dialog/Dialog.styles.tsx +154 -136
  74. package/src/Dialog/Dialog.web.tsx +16 -11
  75. package/src/Dialog/index.ts +5 -2
  76. package/src/Dialog/index.web.ts +5 -2
  77. package/src/Dialog/types.ts +22 -16
  78. package/src/Divider/Divider.native.tsx +19 -14
  79. package/src/Divider/Divider.styles.tsx +273 -595
  80. package/src/Divider/Divider.web.tsx +19 -12
  81. package/src/Divider/index.ts +5 -5
  82. package/src/Divider/index.web.ts +5 -3
  83. package/src/Divider/types.ts +28 -19
  84. package/src/Icon/Icon.native.tsx +17 -24
  85. package/src/Icon/Icon.styles.tsx +64 -48
  86. package/src/Icon/Icon.web.tsx +14 -11
  87. package/src/Icon/IconSvg/IconSvg.native.tsx +42 -0
  88. package/src/Icon/IconSvg/IconSvg.web.tsx +40 -0
  89. package/src/Icon/IconSvg/index.native.ts +1 -0
  90. package/src/Icon/IconSvg/index.ts +1 -0
  91. package/src/Icon/icon-resolver.native.ts +27 -0
  92. package/src/Icon/icon-resolver.ts +70 -0
  93. package/src/Icon/index.ts +5 -5
  94. package/src/Icon/index.web.ts +5 -3
  95. package/src/Icon/types.ts +17 -11
  96. package/src/Image/Image.native.tsx +86 -0
  97. package/src/Image/Image.styles.tsx +57 -0
  98. package/src/Image/Image.web.tsx +92 -0
  99. package/src/Image/index.native.ts +5 -0
  100. package/src/Image/index.ts +5 -0
  101. package/src/Image/types.ts +21 -0
  102. package/src/Input/Input.native.tsx +103 -26
  103. package/src/Input/Input.styles.tsx +240 -177
  104. package/src/Input/Input.web.tsx +141 -38
  105. package/src/Input/index.ts +5 -5
  106. package/src/Input/index.web.ts +5 -3
  107. package/src/Input/types.ts +43 -20
  108. package/src/List/List.native.tsx +56 -0
  109. package/src/List/List.styles.tsx +257 -0
  110. package/src/List/List.web.tsx +43 -0
  111. package/src/List/ListContext.tsx +16 -0
  112. package/src/List/ListItem.native.tsx +111 -0
  113. package/src/List/ListItem.web.tsx +110 -0
  114. package/src/List/ListSection.native.tsx +31 -0
  115. package/src/List/ListSection.web.tsx +33 -0
  116. package/src/List/index.native.tsx +5 -0
  117. package/src/List/index.ts +5 -0
  118. package/src/List/index.web.tsx +5 -0
  119. package/src/List/types.ts +42 -0
  120. package/src/Menu/Menu.native.tsx +150 -0
  121. package/src/Menu/Menu.styles.tsx +185 -0
  122. package/src/Menu/Menu.web.tsx +99 -0
  123. package/src/Menu/MenuItem.native.tsx +66 -0
  124. package/src/Menu/MenuItem.styles.tsx +119 -0
  125. package/src/Menu/MenuItem.web.tsx +67 -0
  126. package/src/Menu/index.native.ts +3 -0
  127. package/src/Menu/index.ts +3 -0
  128. package/src/Menu/index.web.ts +3 -0
  129. package/src/Menu/types.ts +30 -0
  130. package/src/Popover/Popover.native.tsx +102 -32
  131. package/src/Popover/Popover.styles.tsx +100 -67
  132. package/src/Popover/Popover.web.tsx +36 -260
  133. package/src/Popover/index.ts +5 -2
  134. package/src/Popover/index.web.ts +5 -2
  135. package/src/Popover/types.ts +14 -13
  136. package/src/Pressable/Pressable.native.tsx +7 -6
  137. package/src/Pressable/Pressable.web.tsx +8 -6
  138. package/src/Pressable/index.ts +5 -2
  139. package/src/Pressable/index.web.ts +5 -2
  140. package/src/Pressable/types.ts +11 -10
  141. package/src/Progress/Progress.native.tsx +179 -0
  142. package/src/Progress/Progress.styles.tsx +164 -0
  143. package/src/Progress/Progress.web.tsx +144 -0
  144. package/src/Progress/index.native.ts +1 -0
  145. package/src/Progress/index.ts +5 -0
  146. package/src/Progress/index.web.ts +5 -0
  147. package/src/Progress/types.ts +21 -0
  148. package/src/RadioButton/RadioButton.native.tsx +88 -0
  149. package/src/RadioButton/RadioButton.styles.tsx +163 -0
  150. package/src/RadioButton/RadioButton.web.tsx +85 -0
  151. package/src/RadioButton/RadioGroup.native.tsx +43 -0
  152. package/src/RadioButton/RadioGroup.web.tsx +49 -0
  153. package/src/RadioButton/index.native.ts +2 -0
  154. package/src/RadioButton/index.ts +2 -0
  155. package/src/RadioButton/index.web.ts +2 -0
  156. package/src/RadioButton/types.ts +29 -0
  157. package/src/SVGImage/SVGImage.native.tsx +9 -7
  158. package/src/SVGImage/SVGImage.styles.tsx +63 -55
  159. package/src/SVGImage/SVGImage.web.tsx +16 -13
  160. package/src/SVGImage/index.ts +5 -5
  161. package/src/SVGImage/index.web.ts +5 -2
  162. package/src/SVGImage/types.ts +7 -3
  163. package/src/Screen/Screen.native.tsx +43 -17
  164. package/src/Screen/Screen.styles.tsx +58 -54
  165. package/src/Screen/Screen.web.tsx +11 -5
  166. package/src/Screen/index.ts +5 -2
  167. package/src/Screen/index.web.ts +5 -2
  168. package/src/Screen/types.ts +23 -9
  169. package/src/Select/Select.native.tsx +140 -63
  170. package/src/Select/Select.styles.tsx +312 -302
  171. package/src/Select/Select.web.tsx +156 -316
  172. package/src/Select/index.ts +5 -2
  173. package/src/Select/index.web.ts +5 -2
  174. package/src/Select/types.ts +13 -7
  175. package/src/Skeleton/Skeleton.native.tsx +139 -0
  176. package/src/Skeleton/Skeleton.styles.tsx +59 -0
  177. package/src/Skeleton/Skeleton.web.tsx +112 -0
  178. package/src/Skeleton/index.native.ts +4 -0
  179. package/src/Skeleton/index.ts +5 -0
  180. package/src/Skeleton/index.web.ts +5 -0
  181. package/src/Skeleton/types.ts +75 -0
  182. package/src/Slider/Slider.native.tsx +248 -0
  183. package/src/Slider/Slider.styles.tsx +241 -0
  184. package/src/Slider/Slider.web.tsx +226 -0
  185. package/src/Slider/index.native.ts +3 -0
  186. package/src/Slider/index.ts +5 -0
  187. package/src/Slider/index.web.ts +5 -0
  188. package/src/Slider/types.ts +31 -0
  189. package/src/Switch/Switch.native.tsx +131 -0
  190. package/src/Switch/Switch.styles.tsx +169 -0
  191. package/src/Switch/Switch.web.tsx +121 -0
  192. package/src/Switch/index.native.ts +3 -0
  193. package/src/Switch/index.ts +5 -0
  194. package/src/Switch/index.web.ts +5 -0
  195. package/src/Switch/types.ts +21 -0
  196. package/src/TabBar/TabBar.native.tsx +142 -0
  197. package/src/TabBar/TabBar.styles.tsx +399 -0
  198. package/src/TabBar/TabBar.web.tsx +205 -0
  199. package/src/TabBar/index.native.tsx +3 -0
  200. package/src/TabBar/index.ts +3 -0
  201. package/src/TabBar/index.web.tsx +3 -0
  202. package/src/TabBar/types.ts +26 -0
  203. package/src/Table/Table.native.tsx +122 -0
  204. package/src/Table/Table.styles.tsx +283 -0
  205. package/src/Table/Table.web.tsx +112 -0
  206. package/src/Table/index.native.tsx +3 -0
  207. package/src/Table/index.ts +3 -0
  208. package/src/Table/index.web.tsx +3 -0
  209. package/src/Table/types.ts +28 -0
  210. package/src/Text/Text.native.tsx +12 -11
  211. package/src/Text/Text.styles.tsx +76 -64
  212. package/src/Text/Text.web.tsx +14 -9
  213. package/src/Text/index.ts +5 -5
  214. package/src/Text/index.web.ts +5 -3
  215. package/src/Text/types.ts +20 -13
  216. package/src/TextArea/TextArea.native.tsx +134 -0
  217. package/src/TextArea/TextArea.styles.tsx +175 -0
  218. package/src/TextArea/TextArea.web.tsx +156 -0
  219. package/src/TextArea/index.native.ts +3 -0
  220. package/src/TextArea/index.ts +3 -0
  221. package/src/TextArea/index.web.ts +3 -0
  222. package/src/TextArea/types.ts +30 -0
  223. package/src/Tooltip/Tooltip.native.tsx +165 -0
  224. package/src/Tooltip/Tooltip.styles.tsx +73 -0
  225. package/src/Tooltip/Tooltip.web.tsx +87 -0
  226. package/src/Tooltip/index.native.ts +3 -0
  227. package/src/Tooltip/index.ts +3 -0
  228. package/src/Tooltip/types.ts +18 -0
  229. package/src/Video/Video.native.tsx +105 -0
  230. package/src/Video/Video.styles.tsx +39 -0
  231. package/src/Video/Video.web.tsx +115 -0
  232. package/src/Video/index.native.ts +5 -0
  233. package/src/Video/index.ts +5 -0
  234. package/src/Video/types.ts +29 -0
  235. package/src/View/View.native.tsx +9 -14
  236. package/src/View/View.styles.tsx +101 -93
  237. package/src/View/View.web.tsx +16 -17
  238. package/src/View/index.ts +5 -5
  239. package/src/View/index.web.ts +5 -3
  240. package/src/View/types.ts +29 -21
  241. package/src/examples/AccordionExamples.tsx +126 -0
  242. package/src/examples/AlertExamples.tsx +280 -0
  243. package/src/examples/AvatarExamples.tsx +23 -23
  244. package/src/examples/BadgeExamples.tsx +109 -41
  245. package/src/examples/BreadcrumbExamples.tsx +312 -0
  246. package/src/examples/ButtonExamples.tsx +160 -33
  247. package/src/examples/CardExamples.tsx +40 -40
  248. package/src/examples/CheckboxExamples.tsx +12 -12
  249. package/src/examples/ChipExamples.tsx +197 -0
  250. package/src/examples/DialogExamples.tsx +22 -22
  251. package/src/examples/DividerExamples.tsx +49 -49
  252. package/src/examples/IconExamples.tsx +270 -54
  253. package/src/examples/ImageExamples.tsx +174 -0
  254. package/src/examples/InputExamples.tsx +75 -17
  255. package/src/examples/ListExamples.tsx +288 -0
  256. package/src/examples/MenuExamples.tsx +144 -0
  257. package/src/examples/PopoverExamples.tsx +69 -73
  258. package/src/examples/ProgressExamples.tsx +137 -0
  259. package/src/examples/RadioButtonExamples.tsx +161 -0
  260. package/src/examples/SVGImageExamples.tsx +19 -17
  261. package/src/examples/ScreenExamples.tsx +31 -31
  262. package/src/examples/SelectExamples.tsx +67 -67
  263. package/src/examples/SkeletonExamples.tsx +206 -0
  264. package/src/examples/SliderExamples.tsx +200 -0
  265. package/src/examples/SwitchExamples.tsx +182 -0
  266. package/src/examples/TabBarExamples.tsx +143 -0
  267. package/src/examples/TableExamples.tsx +280 -0
  268. package/src/examples/TextAreaExamples.tsx +173 -0
  269. package/src/examples/TextExamples.tsx +28 -32
  270. package/src/examples/ThemeExtensionExamples.tsx +10 -10
  271. package/src/examples/TooltipExamples.tsx +126 -0
  272. package/src/examples/VideoExamples.tsx +144 -0
  273. package/src/examples/ViewExamples.tsx +64 -56
  274. package/src/examples/index.ts +17 -3
  275. package/src/hooks/useMergeRefs.ts +16 -0
  276. package/src/hooks/useSmartPosition.native.ts +169 -0
  277. package/src/index.native.ts +80 -9
  278. package/src/index.ts +71 -1
  279. package/src/internal/BoundedModalContent.native.tsx +58 -0
  280. package/src/internal/PositionedPortal.tsx +254 -0
  281. package/src/internal/SafeAreaDebugOverlay.native.tsx +173 -0
  282. package/src/unistyles.d.ts +6 -0
  283. package/src/utils/buildSizeVariants.ts +16 -0
  284. package/src/utils/deepMerge.ts +43 -0
  285. package/src/utils/positionUtils.native.ts +280 -0
  286. package/src/utils/styleHelpers.ts +48 -0
  287. package/LLM-ACCESS-GUIDE.md +0 -143
  288. package/src/ActivityIndicator/README.md +0 -132
  289. package/src/Avatar/README.md +0 -139
  290. package/src/Badge/README.md +0 -170
  291. package/src/Button/Button.types.ts +0 -12
  292. package/src/Button/README.md +0 -262
  293. package/src/Card/README.md +0 -258
  294. package/src/Checkbox/README.md +0 -102
  295. package/src/Dialog/README.md +0 -210
  296. package/src/Divider/README.md +0 -108
  297. package/src/Icon/README.md +0 -81
  298. package/src/Input/README.md +0 -100
  299. package/src/SVGImage/README.md +0 -209
  300. package/src/Screen/README.md +0 -86
  301. package/src/Select/README.md +0 -166
  302. package/src/Text/README.md +0 -94
  303. package/src/View/README.md +0 -107
  304. package/src/examples/AllExamples.tsx +0 -88
  305. package/src/examples/README.md +0 -136
  306. package/src/examples/ValidationExamples.tsx +0 -95
  307. package/src/examples/extendedTheme.ts +0 -329
  308. package/src/theme/breakpoints.ts +0 -8
  309. package/src/theme/colorResolver.ts +0 -218
  310. package/src/theme/colors.ts +0 -315
  311. package/src/theme/defaultThemes.ts +0 -326
  312. package/src/theme/index.ts +0 -188
  313. package/src/theme/themeBuilder.ts +0 -602
  314. package/src/theme/unistyles.d.ts +0 -6
  315. package/src/theme/variantHelpers.ts +0 -584
  316. package/src/theme/variants.ts +0 -56
package/plugin/web.js CHANGED
@@ -1,150 +1,305 @@
1
+ /**
2
+ * Enhanced MDI Auto-Import Babel Plugin v2.0
3
+ *
4
+ * Features:
5
+ * 1. Context-aware string replacement - only transforms strings used with Icon component
6
+ * 2. Namespace prefix support - "mdi:iconname" guarantees transformation
7
+ * 3. Variable tracking with scope analysis - follows variables back to their declarations
8
+ * 4. No false positives - only transforms Icon-related strings
9
+ * 5. Button/Badge/Breadcrumb/Menu icon prop transformation with path injection
10
+ */
11
+
1
12
  module.exports = function ({ types: t }, options = {}) {
2
13
  const debug = options.debug || false;
3
14
  const manifestPath = options.manifestPath || './icons.manifest.json';
4
-
15
+
5
16
  // Debug logging function that only logs when debug is enabled
6
17
  const debugLog = (...args) => {
7
18
  if (debug) {
8
19
  console.log(...args);
9
20
  }
10
21
  };
11
-
12
- debugLog('[mdi-auto-import] Plugin loaded');
13
-
22
+
23
+ debugLog('[mdi-auto-import-enhanced] Plugin loaded');
24
+
14
25
  const importedIcons = new Set();
15
26
  const iconImportIdentifiers = new Map();
16
27
  let hasIconImport = false;
17
28
  let manifestIcons = new Set();
18
-
29
+
30
+ // Track variables that are used with Icon component
31
+ const iconRelatedVariables = new Set();
32
+
19
33
  // Load icon manifest if it exists
20
34
  function loadIconManifest() {
21
35
  try {
22
36
  const fs = require('fs');
23
37
  const path = require('path');
24
-
25
- // Try to resolve the manifest path relative to the current working directory
38
+
26
39
  const fullPath = path.resolve(process.cwd(), manifestPath);
27
-
40
+
28
41
  if (fs.existsSync(fullPath)) {
29
42
  const manifestContent = fs.readFileSync(fullPath, 'utf8');
30
43
  const manifest = JSON.parse(manifestContent);
31
-
44
+
32
45
  if (manifest.icons && Array.isArray(manifest.icons)) {
33
46
  manifest.icons.forEach(iconName => {
34
47
  if (typeof iconName === 'string') {
35
48
  manifestIcons.add(iconName);
36
49
  }
37
50
  });
38
- debugLog(`[mdi-auto-import] Loaded ${manifestIcons.size} icons from manifest: ${fullPath}`);
39
- debugLog('[mdi-auto-import] Manifest icons:', Array.from(manifestIcons));
51
+ debugLog(`[mdi-auto-import-enhanced] Loaded ${manifestIcons.size} icons from manifest: ${fullPath}`);
40
52
  } else {
41
- console.warn(`[mdi-auto-import] Invalid manifest format in ${fullPath}. Expected { "icons": ["icon-name", ...] }`);
53
+ console.warn(`[mdi-auto-import-enhanced] Invalid manifest format in ${fullPath}. Expected { "icons": ["icon-name", ...] }`);
42
54
  }
43
- } else {
44
- debugLog(`[mdi-auto-import] No manifest found at ${fullPath}`);
45
55
  }
46
56
  } catch (error) {
47
- console.warn(`[mdi-auto-import] Error loading manifest from ${manifestPath}: ${error.message}`);
57
+ console.warn(`[mdi-auto-import-enhanced] Error loading manifest from ${manifestPath}: ${error.message}`);
48
58
  }
49
59
  }
50
-
60
+
51
61
  function formatIconName(name) {
52
- // Handle empty or invalid names
53
62
  if (!name || typeof name !== 'string') {
54
63
  throw new Error(`Invalid icon name: ${name}`);
55
64
  }
56
-
57
- const formatted = name
58
- // Convert kebab-case and snake_case to PascalCase
59
- .replace(/[-_]/g, ' ')
65
+
66
+ // Strip mdi: prefix if it exists (safety check, should already be stripped)
67
+ const cleanName = name.startsWith('mdi:') ? name.substring(4) : name;
68
+
69
+ // Check if the name contains only valid characters (letters, numbers, hyphens, underscores)
70
+ if (!/^[a-zA-Z0-9-_]+$/.test(cleanName)) {
71
+ debugLog(`[mdi-auto-import-enhanced] formatIconName: Invalid icon name "${name}" (contains special characters), using "help-circle" as fallback`);
72
+ return 'HelpCircle';
73
+ }
74
+
75
+ const formatted = cleanName
76
+ .replace(/[-_:]/g, ' ') // Also handle colons
60
77
  .replace(/([a-z])([A-Z])/g, '$1 $2')
61
78
  .split(' ')
62
79
  .filter(part => part.length > 0)
63
80
  .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())
64
81
  .join('');
65
-
66
- debugLog(`[mdi-auto-import] formatIconName: ${name} -> ${formatted}`);
82
+
83
+ debugLog(`[mdi-auto-import-enhanced] formatIconName: ${name} -> ${formatted}`);
67
84
  return formatted;
68
85
  }
69
-
86
+
70
87
  function getMdiIconName(name) {
71
- const mdiName = `mdi${formatIconName(name)}`;
72
- debugLog(`[mdi-auto-import] getMdiIconName: ${name} -> ${mdiName}`);
88
+ // First ensure the name has mdi: prefix stripped (safety check)
89
+ const cleanName = name.startsWith('mdi:') ? name.substring(4) : name;
90
+ const mdiName = `mdi${formatIconName(cleanName)}`;
91
+ debugLog(`[mdi-auto-import-enhanced] getMdiIconName: ${name} -> ${mdiName}`);
73
92
  return mdiName;
74
93
  }
75
-
94
+
76
95
  function getIconIdentifier(iconName) {
77
96
  if (!iconImportIdentifiers.has(iconName)) {
78
- iconImportIdentifiers.set(iconName, `_${iconName}`);
97
+ // Sanitize the icon name to create a valid JavaScript identifier
98
+ // Remove any characters that aren't valid in identifiers
99
+ const sanitized = iconName.replace(/[^a-zA-Z0-9_$]/g, '');
100
+ iconImportIdentifiers.set(iconName, `_${sanitized}`);
79
101
  }
80
102
  const identifier = iconImportIdentifiers.get(iconName);
81
- debugLog(`[mdi-auto-import] getIconIdentifier: ${iconName} -> ${identifier}`);
103
+ debugLog(`[mdi-auto-import-enhanced] getIconIdentifier: ${iconName} -> ${identifier}`);
82
104
  return identifier;
83
105
  }
84
106
 
85
- // Recursively extract all possible string literal values from an expression
107
+ /**
108
+ * Extract icon name from string, handling namespace prefix
109
+ * Returns null if not a valid icon string
110
+ */
111
+ function extractIconName(str) {
112
+ if (!str || typeof str !== 'string') return null;
113
+
114
+ // Handle namespace prefix: "mdi:home" -> "home"
115
+ if (str.startsWith('mdi:')) {
116
+ return str.substring(4);
117
+ }
118
+
119
+ return str;
120
+ }
121
+
122
+ /**
123
+ * Check if a string literal is icon-related based on context
124
+ */
125
+ function isIconRelatedString(path, stringValue) {
126
+ // Always transform if it has the mdi: prefix
127
+ if (stringValue.startsWith('mdi:')) {
128
+ debugLog(`[mdi-auto-import-enhanced] String "${stringValue}" has mdi: prefix - will transform`);
129
+ return true;
130
+ }
131
+
132
+ // Check if this string is in the manifest
133
+ if (manifestIcons.has(stringValue)) {
134
+ debugLog(`[mdi-auto-import-enhanced] String "${stringValue}" is in manifest - will transform`);
135
+ return true;
136
+ }
137
+
138
+ // Icon prop names to check
139
+ const iconPropNames = ['name', 'leftIcon', 'rightIcon', 'icon'];
140
+
141
+ // Walk up the tree to find context
142
+ let currentPath = path;
143
+ while (currentPath) {
144
+ const node = currentPath.node;
145
+
146
+ // Check if we're in a JSXAttribute with an icon-related prop name
147
+ if (t.isJSXAttribute(currentPath.parent)) {
148
+ const attr = currentPath.parent;
149
+ if (t.isJSXIdentifier(attr.name) && iconPropNames.includes(attr.name.name)) {
150
+ // Now check if the parent JSXOpeningElement is Icon, Button, Badge, etc.
151
+ const openingElement = currentPath.parentPath.parent;
152
+ if (t.isJSXOpeningElement(openingElement)) {
153
+ if (t.isJSXIdentifier(openingElement.name)) {
154
+ const componentName = openingElement.name.name;
155
+ debugLog(`[mdi-auto-import-enhanced] String "${stringValue}" is in ${componentName}.${attr.name.name} prop - will transform`);
156
+ return true;
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ // Check if we're assigned to a variable that's used with Icon
163
+ if (t.isVariableDeclarator(currentPath.parent)) {
164
+ const declarator = currentPath.parent;
165
+ if (t.isIdentifier(declarator.id)) {
166
+ const varName = declarator.id.name;
167
+ if (iconRelatedVariables.has(varName)) {
168
+ debugLog(`[mdi-auto-import-enhanced] String "${stringValue}" is in icon-related variable "${varName}" - will transform`);
169
+ return true;
170
+ }
171
+ }
172
+ }
173
+
174
+ currentPath = currentPath.parentPath;
175
+ }
176
+
177
+ return false;
178
+ }
179
+
180
+ /**
181
+ * Track variables that are used with Icon component
182
+ * This runs in a first pass to identify which variables are icon-related
183
+ */
184
+ function trackIconRelatedVariables(programPath) {
185
+ // Components that accept icon props
186
+ const componentsWithIconProps = {
187
+ 'Icon': ['name'],
188
+ 'Button': ['leftIcon', 'rightIcon'],
189
+ 'Badge': ['icon'],
190
+ 'Breadcrumb': ['icon'],
191
+ 'Menu': ['icon']
192
+ };
193
+
194
+ programPath.traverse({
195
+ JSXElement(path) {
196
+ const { node } = path;
197
+
198
+ if (t.isJSXIdentifier(node.openingElement.name)) {
199
+ const componentName = node.openingElement.name.name;
200
+ const iconProps = componentsWithIconProps[componentName];
201
+
202
+ if (iconProps) {
203
+ // Find all icon-related attributes
204
+ iconProps.forEach(propName => {
205
+ const attr = node.openingElement.attributes.find(attr =>
206
+ t.isJSXAttribute(attr) &&
207
+ t.isJSXIdentifier(attr.name) &&
208
+ attr.name.name === propName
209
+ );
210
+
211
+ if (attr && t.isJSXExpressionContainer(attr.value)) {
212
+ const expression = attr.value.expression;
213
+
214
+ // Track any identifiers used in the icon prop
215
+ if (t.isIdentifier(expression)) {
216
+ iconRelatedVariables.add(expression.name);
217
+ debugLog(`[mdi-auto-import-enhanced] Tracked icon-related variable: ${expression.name} (from ${componentName}.${propName})`);
218
+
219
+ // Follow the binding to find its declaration
220
+ const binding = path.scope.getBinding(expression.name);
221
+ if (binding && binding.path.isVariableDeclarator()) {
222
+ const init = binding.path.node.init;
223
+ if (t.isStringLiteral(init)) {
224
+ debugLog(`[mdi-auto-import-enhanced] Variable ${expression.name} = "${init.value}"`);
225
+ }
226
+ }
227
+ }
228
+
229
+ // Track variables in ternaries and logical expressions
230
+ path.traverse({
231
+ Identifier(idPath) {
232
+ // Only track top-level identifiers, not property accesses
233
+ if (!t.isMemberExpression(idPath.parent)) {
234
+ iconRelatedVariables.add(idPath.node.name);
235
+ debugLog(`[mdi-auto-import-enhanced] Tracked icon-related variable in expression: ${idPath.node.name} (from ${componentName}.${propName})`);
236
+ }
237
+ }
238
+ });
239
+ }
240
+ });
241
+ }
242
+ }
243
+ }
244
+ });
245
+ }
246
+
247
+ /**
248
+ * Extract all icon names from an expression, now with context awareness
249
+ */
86
250
  function extractIconNames(expression, path) {
87
251
  const iconNames = new Set();
88
-
89
- function traverse(node) {
252
+
253
+ function traverse(node, nodePath) {
90
254
  if (!node) return;
91
-
255
+
92
256
  if (t.isStringLiteral(node)) {
93
- iconNames.add(node.value);
94
- debugLog(`[mdi-auto-import] Found string literal: ${node.value}`);
95
- }
257
+ const iconName = extractIconName(node.value);
258
+ if (iconName) {
259
+ iconNames.add(iconName);
260
+ debugLog(`[mdi-auto-import-enhanced] Found icon name: ${iconName} (from "${node.value}")`);
261
+ }
262
+ }
96
263
  else if (t.isConditionalExpression(node)) {
97
- // Handle ternary: condition ? 'icon1' : 'icon2'
98
- debugLog('[mdi-auto-import] Processing conditional expression');
99
- traverse(node.consequent);
100
- traverse(node.alternate);
264
+ debugLog('[mdi-auto-import-enhanced] Processing conditional expression');
265
+ traverse(node.consequent, nodePath);
266
+ traverse(node.alternate, nodePath);
101
267
  }
102
268
  else if (t.isLogicalExpression(node)) {
103
- // Handle logical: condition && 'icon1' || 'icon2'
104
- debugLog('[mdi-auto-import] Processing logical expression');
105
- traverse(node.left);
106
- traverse(node.right);
269
+ debugLog('[mdi-auto-import-enhanced] Processing logical expression');
270
+ traverse(node.left, nodePath);
271
+ traverse(node.right, nodePath);
107
272
  }
108
273
  else if (t.isTemplateLiteral(node)) {
109
- // Handle template literals with no expressions (static strings)
110
274
  if (node.expressions.length === 0 && node.quasis.length === 1) {
111
275
  const value = node.quasis[0].value.cooked;
112
- iconNames.add(value);
113
- debugLog(`[mdi-auto-import] Found template literal: ${value}`);
114
- } else {
115
- debugLog('[mdi-auto-import] Skipping dynamic template literal');
116
- }
117
- }
118
- else if (t.isMemberExpression(node)) {
119
- // Handle object.property where object is static
120
- if (t.isIdentifier(node.object) && t.isIdentifier(node.property)) {
121
- debugLog(`[mdi-auto-import] Found member expression: ${node.object.name}.${node.property.name}`);
122
- // We could potentially resolve this if we track object declarations
123
- // For now, just warn that we found it but can't resolve it
276
+ const iconName = extractIconName(value);
277
+ if (iconName) {
278
+ iconNames.add(iconName);
279
+ debugLog(`[mdi-auto-import-enhanced] Found icon name in template literal: ${iconName}`);
280
+ }
124
281
  }
125
282
  }
126
- else if (t.isCallExpression(node)) {
127
- debugLog('[mdi-auto-import] Found function call - cannot statically analyze');
128
- console.warn(`[mdi-auto-import] Function call detected at ${path.node.loc ? `${path.node.loc.start.line}:${path.node.loc.start.column}` : 'unknown location'}. Consider adding icon names to manifest (${manifestPath}) for auto-import support.`);
129
- // For function calls, we can't statically determine the result
130
- // But we could potentially add runtime analysis or hints
131
- }
132
283
  else if (t.isIdentifier(node)) {
133
- debugLog(`[mdi-auto-import] Found identifier: ${node.name}`);
134
- // We could potentially trace variable declarations
135
- // For now, just note that we found it
136
- }
137
- else {
138
- debugLog(`[mdi-auto-import] Unhandled expression type: ${node.type}`);
284
+ debugLog(`[mdi-auto-import-enhanced] Following identifier: ${node.name}`);
285
+
286
+ // Try to resolve the identifier to its value
287
+ const binding = path.scope.getBinding(node.name);
288
+ if (binding && binding.path.isVariableDeclarator()) {
289
+ const init = binding.path.node.init;
290
+ if (init) {
291
+ traverse(init, binding.path);
292
+ }
293
+ }
139
294
  }
140
295
  }
141
-
142
- traverse(expression);
296
+
297
+ traverse(expression, path);
143
298
  return Array.from(iconNames);
144
299
  }
145
300
 
146
301
  return {
147
- name: 'mdi-auto-import',
302
+ name: 'mdi-auto-import-enhanced',
148
303
  visitor: {
149
304
  Program: {
150
305
  enter(path) {
@@ -153,30 +308,34 @@ module.exports = function ({ types: t }, options = {}) {
153
308
  iconImportIdentifiers.clear();
154
309
  hasIconImport = false;
155
310
  manifestIcons.clear();
156
-
311
+ iconRelatedVariables.clear();
312
+
157
313
  // Load icon manifest
158
314
  loadIconManifest();
159
-
315
+
160
316
  // Add all manifest icons to the import list
161
317
  manifestIcons.forEach(iconName => {
162
318
  try {
163
319
  const mdiIconName = getMdiIconName(iconName);
164
320
  importedIcons.add(mdiIconName);
165
- debugLog(`[mdi-auto-import] Added manifest icon to import list: ${mdiIconName}`);
321
+ debugLog(`[mdi-auto-import-enhanced] Added manifest icon to import list: ${mdiIconName}`);
166
322
  } catch (error) {
167
- console.error(`[mdi-auto-import] Error processing manifest icon "${iconName}": ${error.message}`);
323
+ console.error(`[mdi-auto-import-enhanced] Error processing manifest icon "${iconName}": ${error.message}`);
168
324
  }
169
325
  });
170
-
326
+
327
+ // First pass: track which variables are icon-related
328
+ trackIconRelatedVariables(path);
329
+
171
330
  // Check if Icon is already imported from @mdi/react
172
331
  path.node.body.forEach(node => {
173
332
  if (t.isImportDeclaration(node) && node.source.value === '@mdi/react') {
174
- debugLog('[mdi-auto-import] Found @mdi/react import');
175
- const hasIconSpecifier = node.specifiers.some(spec =>
333
+ debugLog('[mdi-auto-import-enhanced] Found @mdi/react import');
334
+ const hasIconSpecifier = node.specifiers.some(spec =>
176
335
  t.isImportDefaultSpecifier(spec) && spec.local.name === 'MdiIcon'
177
336
  );
178
337
  if (hasIconSpecifier) {
179
- debugLog('[mdi-auto-import] MdiIcon already imported');
338
+ debugLog('[mdi-auto-import-enhanced] MdiIcon already imported');
180
339
  hasIconImport = true;
181
340
  }
182
341
  }
@@ -186,12 +345,12 @@ module.exports = function ({ types: t }, options = {}) {
186
345
  if (importedIcons.size === 0) {
187
346
  return;
188
347
  }
189
- debugLog(`[mdi-auto-import] importedIcons.size: ${importedIcons.size}`);
190
-
348
+ debugLog(`[mdi-auto-import-enhanced] importedIcons.size: ${importedIcons.size}`);
349
+
191
350
  // Add imports at the top of the file if any icons were used
192
351
  if (importedIcons.size > 0) {
193
- debugLog('[mdi-auto-import] Adding imports for icons:', Array.from(importedIcons));
194
-
352
+ debugLog('[mdi-auto-import-enhanced] Adding imports for icons:', Array.from(importedIcons));
353
+
195
354
  // Import individual icons from @mdi/js
196
355
  const iconImportSpecifiers = Array.from(importedIcons).map(iconName => {
197
356
  const identifier = getIconIdentifier(iconName);
@@ -200,121 +359,260 @@ module.exports = function ({ types: t }, options = {}) {
200
359
  t.identifier(iconName)
201
360
  );
202
361
  });
203
-
362
+
204
363
  const iconImportDeclaration = t.importDeclaration(
205
364
  iconImportSpecifiers,
206
365
  t.stringLiteral('@mdi/js')
207
366
  );
208
-
367
+
209
368
  // Import Icon component from @mdi/react if not already imported
210
369
  if (!hasIconImport) {
211
- debugLog('[mdi-auto-import] Adding MdiIcon import from @mdi/react');
370
+ debugLog('[mdi-auto-import-enhanced] Adding MdiIcon import from @mdi/react');
212
371
  const iconComponentImport = t.importDeclaration(
213
372
  [t.importDefaultSpecifier(t.identifier('MdiIcon'))],
214
373
  t.stringLiteral('@mdi/react')
215
374
  );
216
375
  path.unshiftContainer('body', iconComponentImport);
217
376
  } else {
218
- debugLog('[mdi-auto-import] MdiIcon already imported, skipping');
377
+ debugLog('[mdi-auto-import-enhanced] MdiIcon already imported, skipping');
219
378
  }
220
-
379
+
221
380
  // Add icon imports
222
381
  path.unshiftContainer('body', iconImportDeclaration);
223
- debugLog('[mdi-auto-import] Imports added successfully');
382
+ debugLog('[mdi-auto-import-enhanced] Imports added successfully');
224
383
  } else {
225
- debugLog('[mdi-auto-import] No icons to import');
384
+ debugLog('[mdi-auto-import-enhanced] No icons to import');
226
385
  }
227
386
  }
228
387
  },
229
-
388
+
230
389
  JSXElement(path) {
231
390
  const { node } = path;
232
-
391
+
392
+ // Handle Badge, Button, Breadcrumb, Menu components with icon props
393
+ if (t.isJSXIdentifier(node.openingElement.name)) {
394
+ const componentName = node.openingElement.name.name;
395
+ const iconPropMapping = {
396
+ 'Button': { props: ['leftIcon', 'rightIcon'], pathProps: ['leftIconPath', 'rightIconPath'] },
397
+ 'Badge': { props: ['icon'], pathProps: ['iconPath'] },
398
+ 'Breadcrumb': { props: ['icon'], pathProps: ['iconPath'] },
399
+ 'Menu': { props: ['icon'], pathProps: ['iconPath'] }
400
+ };
401
+
402
+ const iconConfig = iconPropMapping[componentName];
403
+ if (iconConfig) {
404
+ debugLog(`[mdi-auto-import-enhanced] JSXElement visitor - Found ${componentName}`);
405
+
406
+ // Process each icon prop
407
+ iconConfig.props.forEach((propName, index) => {
408
+ const attr = node.openingElement.attributes.find(attr =>
409
+ t.isJSXAttribute(attr) &&
410
+ t.isJSXIdentifier(attr.name) &&
411
+ attr.name.name === propName
412
+ );
413
+
414
+ if (attr && t.isStringLiteral(attr.value)) {
415
+ const stringValue = attr.value.value;
416
+ const iconName = extractIconName(stringValue);
417
+
418
+ if (iconName) {
419
+ debugLog(`[mdi-auto-import-enhanced] - Found ${propName}="${stringValue}" (StringLiteral)`);
420
+
421
+ try {
422
+ const mdiIconName = getMdiIconName(iconName);
423
+ const iconIdentifier = getIconIdentifier(mdiIconName);
424
+ importedIcons.add(mdiIconName);
425
+ debugLog(`[mdi-auto-import-enhanced] - Added icon from ${componentName}.${propName}: ${mdiIconName}`);
426
+
427
+ // Add the corresponding path prop (e.g., leftIconPath, rightIconPath, iconPath)
428
+ const pathPropName = iconConfig.pathProps[index];
429
+ const pathAttr = t.jsxAttribute(
430
+ t.jsxIdentifier(pathPropName),
431
+ t.jsxExpressionContainer(t.identifier(iconIdentifier))
432
+ );
433
+
434
+ // Add the path attribute to the component
435
+ node.openingElement.attributes.push(pathAttr);
436
+ debugLog(`[mdi-auto-import-enhanced] - Added ${pathPropName}={${iconIdentifier}} to ${componentName}`);
437
+ } catch (error) {
438
+ console.error(`[mdi-auto-import-enhanced] Error processing icon "${iconName}" from ${componentName}.${propName}: ${error.message}`);
439
+ }
440
+ }
441
+ } else if (attr) {
442
+ const attrType = attr.value?.type || 'unknown';
443
+ debugLog(`[mdi-auto-import-enhanced] - Found ${propName} (${attrType})`);
444
+ }
445
+ });
446
+ }
447
+ }
448
+
233
449
  // Check if this is an Icon component from @idealyst/components
234
450
  if (
235
451
  t.isJSXIdentifier(node.openingElement.name) &&
236
452
  node.openingElement.name.name === 'Icon'
237
453
  ) {
238
-
454
+
239
455
  // Find the name attribute
240
- const nameAttr = node.openingElement.attributes.find(attr =>
241
- t.isJSXAttribute(attr) &&
242
- t.isJSXIdentifier(attr.name) &&
456
+ const nameAttr = node.openingElement.attributes.find(attr =>
457
+ t.isJSXAttribute(attr) &&
458
+ t.isJSXIdentifier(attr.name) &&
243
459
  attr.name.name === 'name'
244
460
  );
245
-
461
+
246
462
  if (!nameAttr) {
247
- debugLog('[mdi-auto-import] No name attribute found');
463
+ debugLog('[mdi-auto-import-enhanced] No name attribute found');
248
464
  return;
249
465
  }
250
-
466
+
251
467
  let iconNames = [];
252
-
468
+
253
469
  // Handle both string literals and JSX expressions
254
470
  if (nameAttr && t.isStringLiteral(nameAttr.value)) {
255
- iconNames = [nameAttr.value.value];
256
- debugLog(`[mdi-auto-import] Found direct string literal: ${nameAttr.value.value}`);
471
+ const iconName = extractIconName(nameAttr.value.value);
472
+ if (iconName) {
473
+ iconNames = [iconName];
474
+ debugLog(`[mdi-auto-import-enhanced] Found direct string literal: ${iconName}`);
475
+ }
257
476
  } else if (nameAttr && t.isJSXExpressionContainer(nameAttr.value)) {
258
477
  // Handle JSX expressions with enhanced detection
259
478
  const expression = nameAttr.value.expression;
260
479
  iconNames = extractIconNames(expression, path);
261
-
480
+
262
481
  if (iconNames.length === 0) {
263
- // For dynamic expressions we can't resolve, leave a helpful comment
264
- console.warn(`[mdi-auto-import] Cannot determine icon name (${nameAttr.value.expression}) for dynamic expression at ${path.node.loc ? `${path.node.loc.start.line}:${path.node.loc.start.column}` : 'unknown location'}. Consider adding icon names to manifest (${manifestPath}) for auto-import support.`);
482
+ debugLog(`[mdi-auto-import-enhanced] Cannot determine icon name for dynamic expression`);
265
483
  return;
266
484
  }
267
485
  }
268
-
486
+
269
487
  if (iconNames.length > 0) {
270
- debugLog(`[mdi-auto-import] Processing icons: ${iconNames.join(', ')}`);
271
-
488
+ debugLog(`[mdi-auto-import-enhanced] Processing icons: ${iconNames.join(', ')}`);
489
+
272
490
  // Process each icon name found
273
491
  const processedIcons = [];
274
492
  iconNames.forEach(iconName => {
275
493
  try {
276
494
  const mdiIconName = getMdiIconName(iconName);
277
495
  const iconIdentifier = getIconIdentifier(mdiIconName);
278
-
496
+
279
497
  // Track that we need to import this icon
280
498
  importedIcons.add(mdiIconName);
281
499
  processedIcons.push({ iconName, mdiIconName, iconIdentifier });
282
- debugLog(`[mdi-auto-import] Added icon to import list: ${mdiIconName}`);
500
+ debugLog(`[mdi-auto-import-enhanced] Added icon to import list: ${mdiIconName}`);
283
501
  } catch (error) {
284
- console.error(`[mdi-auto-import] Error processing icon "${iconName}": ${error.message}`);
502
+ console.error(`[mdi-auto-import-enhanced] Error processing icon "${iconName}": ${error.message}`);
285
503
  }
286
504
  });
287
-
505
+
288
506
  // If we have exactly one icon, we can transform the component
289
507
  if (processedIcons.length === 1) {
290
508
  const { iconIdentifier } = processedIcons[0];
291
-
509
+
292
510
  // Replace name="iconName" with path={iconIdentifier}
293
511
  const pathAttr = t.jsxAttribute(
294
512
  t.jsxIdentifier('path'),
295
513
  t.jsxExpressionContainer(t.identifier(iconIdentifier))
296
514
  );
297
-
515
+
298
516
  // Remove the name attribute and add the path attribute
299
517
  node.openingElement.attributes = node.openingElement.attributes
300
518
  .filter(attr => !(
301
- t.isJSXAttribute(attr) &&
302
- t.isJSXIdentifier(attr.name) &&
519
+ t.isJSXAttribute(attr) &&
520
+ t.isJSXIdentifier(attr.name) &&
303
521
  attr.name.name === 'name'
304
522
  ))
305
523
  .concat(pathAttr);
306
-
307
- debugLog(`[mdi-auto-import] Transformed Icon component: name="${processedIcons[0].iconName}" -> path={${iconIdentifier}}`);
524
+
525
+ debugLog(`[mdi-auto-import-enhanced] Transformed Icon component: name="${processedIcons[0].iconName}" -> path={${iconIdentifier}}`);
308
526
  } else if (processedIcons.length > 1) {
309
- // For multiple possible icons (like conditionals), we add all imports but don't transform
310
- debugLog(`[mdi-auto-import] Found multiple possible icons (${processedIcons.length}), adding imports but not transforming component`);
311
- console.warn(`[mdi-auto-import] Found conditional icon usage at ${path.node.loc ? `${path.node.loc.start.line}:${path.node.loc.start.column}` : 'unknown location'}. All possible icons will be imported, but the component will not be auto-transformed. Consider manual transformation if needed.`);
527
+ debugLog(`[mdi-auto-import-enhanced] Found multiple possible icons (${processedIcons.length}), adding imports but not transforming component`);
312
528
  }
313
529
  } else {
314
- debugLog('[mdi-auto-import] No icon names found');
530
+ debugLog('[mdi-auto-import-enhanced] No icon names found');
531
+ }
532
+ }
533
+ },
534
+
535
+ /**
536
+ * Handle JSX attributes with string values for icon props
537
+ * This handles: <Badge icon="information" />, <Button leftIcon="plus" />
538
+ */
539
+ JSXAttribute(path) {
540
+ const { node } = path;
541
+
542
+ debugLog(`[mdi-auto-import-enhanced] JSXAttribute visitor called for: ${node.name ? node.name.name || 'unknown' : 'no-name'}`);
543
+
544
+ // Check if this is an icon-related attribute
545
+ if (!t.isJSXIdentifier(node.name)) {
546
+ return;
547
+ }
548
+
549
+ const attrName = node.name.name;
550
+ const iconPropNames = ['name', 'leftIcon', 'rightIcon', 'icon'];
551
+
552
+ if (!iconPropNames.includes(attrName)) {
553
+ return;
554
+ }
555
+
556
+ // Check if the value is a string literal
557
+ if (!t.isStringLiteral(node.value)) {
558
+ return;
559
+ }
560
+
561
+ const stringValue = node.value.value;
562
+ const iconName = extractIconName(stringValue);
563
+
564
+ if (!iconName) {
565
+ return;
566
+ }
567
+
568
+ // Check if the parent element is a component that supports icons
569
+ const openingElement = path.parentPath.node;
570
+ if (!t.isJSXOpeningElement(openingElement) || !t.isJSXIdentifier(openingElement.name)) {
571
+ return;
572
+ }
573
+
574
+ const componentName = openingElement.name.name;
575
+ const supportedComponents = ['Icon', 'Button', 'Badge', 'Breadcrumb', 'Menu'];
576
+
577
+ if (!supportedComponents.includes(componentName)) {
578
+ return;
579
+ }
580
+
581
+ try {
582
+ const mdiIconName = getMdiIconName(iconName);
583
+ importedIcons.add(mdiIconName);
584
+ debugLog(`[mdi-auto-import-enhanced] Added icon from ${componentName}.${attrName}="${stringValue}": ${mdiIconName}`);
585
+ } catch (error) {
586
+ console.error(`[mdi-auto-import-enhanced] Error processing icon "${iconName}" from ${componentName}.${attrName}: ${error.message}`);
587
+ }
588
+ },
589
+
590
+ /**
591
+ * Second pass: Transform string literals that are icon-related
592
+ * This handles cases like: const iconName = "home"; <Icon name={iconName} />
593
+ */
594
+ StringLiteral(path) {
595
+ // Skip if we're already in a JSX attribute (handled above)
596
+ if (t.isJSXAttribute(path.parent)) {
597
+ return;
598
+ }
599
+
600
+ const stringValue = path.node.value;
601
+
602
+ // Check if this string is icon-related based on context
603
+ if (isIconRelatedString(path, stringValue)) {
604
+ const iconName = extractIconName(stringValue);
605
+ if (iconName) {
606
+ try {
607
+ const mdiIconName = getMdiIconName(iconName);
608
+ importedIcons.add(mdiIconName);
609
+ debugLog(`[mdi-auto-import-enhanced] Added icon from context-aware string: ${mdiIconName}`);
610
+ } catch (error) {
611
+ console.error(`[mdi-auto-import-enhanced] Error processing icon string "${iconName}": ${error.message}`);
612
+ }
315
613
  }
316
614
  }
317
615
  }
318
616
  }
319
617
  };
320
- };
618
+ };