Add icon compatibility layer for Semantic UI → Lucide migration#1027
Add icon compatibility layer for Semantic UI → Lucide migration#1027
Conversation
Build the foundational icon compatibility layer that enables all subsequent Semantic UI → Lucide icon migration work: - Add `resolveIconName()` and `resolveIcon()` utilities in `frontend/src/utils/iconCompat.ts` with a tree-shakeable KNOWN_ICONS map (~98 explicit Lucide imports) and a SEMANTIC_TO_LUCIDE mapping table (122 entries covering all SUI icon names used in the codebase) - Add `<DynamicIcon>` component in `frontend/src/components/widgets/icon-picker/DynamicIcon.tsx` that accepts string-based icon names (SUI or Lucide) with aria-label/aria-hidden support - Add 20 Vitest unit tests covering mapping correctness, passthrough, fallback, alias consistency, whitespace handling, and case sensitivity - Add 6 Playwright component tests verifying rendering of SUI names, Lucide names, unknown names, and accessibility attributes https://claude.ai/code/session_01MVtcTrYsbeNnDpFoVbxgvm
Code ReviewOverall this is a clean, well-structured addition. The explicit-imports strategy for lucide-react is the right call for bundle size, and the test coverage is solid. A few things worth addressing before merge: Bugs / Semantic Issues1. The codebase uses American English throughout ( 2. Missing
"exclamation circle": "info", // shows i-circle, should show !-circle
"warning circle": "alert-triangle", // shows triangle, should show circle with !Lucide has import { AlertCircle, ... } from "lucide-react";
// In KNOWN_ICONS:
"alert-circle": AlertCircle,
// In SEMANTIC_TO_LUCIDE:
"exclamation circle": "alert-circle",
"warning circle": "alert-circle",3. SUI's import { ArrowLeftRight, ... } from "lucide-react";
// KNOWN_ICONS: "arrow-left-right": ArrowLeftRight,
// SEMANTIC_TO_LUCIDE: "exchange": "arrow-left-right",4.
Code Quality5. Misplaced comment in // Note: "spinner" SUI name maps to "loader" (Lucide's Loader icon)
loader: Loader,This comment lives inside spinner: "loader", // Lucide uses "Loader" for animated spinner6. Hardcoded const mapsToHelpCircle = new Set(["question circle outline"]);If new SUI names that intentionally map to const mapsToHelpCircle = new Set(
Object.entries(SEMANTIC_TO_LUCIDE)
.filter(([, v]) => v === "help-circle")
.map(([k]) => k)
);Accessibility7. Missing When an <IconComponent
role={ariaLabel ? "img" : undefined}
aria-label={ariaLabel}
aria-hidden={ariaHidden ?? !ariaLabel}
...
/>The component test for Minor8. Magic number for default size
9. No barrel export for the
What's Good
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
- Rename normalise→normalize for American English consistency - Import CircleAlert and ArrowLeftRight from lucide-react - Fix "exclamation circle" and "warning circle" to map to circle-alert - Fix "exchange" to map to arrow-left-right (bidirectional) - Add role="img" to SVG when aria-label is present for accessibility - Replace magic number 16 with DYNAMIC_ICON_DEFAULT_SIZE constant - Move spinner comment from KNOWN_ICONS to SEMANTIC_TO_LUCIDE - Add explanatory comment for upload→cloud-upload mapping choice - Replace hardcoded mapsToHelpCircle set with dynamic derivation - Create barrel export index.ts for icon-picker module - Fix alphabetical ordering in KNOWN_ICONS (loader before lock) - Update tests for new warning circle behavior and role="img"
Follow-up Review (Corrected Analysis)The previous review comment on this PR (also from this account) contained several inaccurate bug reports. Looking at the actual code, all of those alleged issues are already correctly implemented:
Sorry for the noise. Real Issues Found1. Dead
Fix options:
2. Misleading JSDoc on
3. Test gap: The component tests cover rendering and accessibility paths well, but do not assert that What Is Well Done
Overall this is solid, well-structured work. The dead |
Summary
Introduces a compatibility layer to support both legacy Semantic UI icon names and native Lucide icon names, enabling a gradual migration from Semantic UI to Lucide React. This allows existing code using SUI icon names to continue working while new code can use Lucide names directly.
Key Changes
iconCompat.ts: New utility module providing:SEMANTIC_TO_LUCIDEmapping of ~100 SUI icon names to their Lucide equivalentsresolveIconName()function to convert SUI names to Lucide kebab-case names with fallback tohelp-circleresolveIcon()function to resolve names directly to Lucide componentsDynamicIcon.tsx: New React component that:aria-label,aria-hidden)HelpCirclefor unknown namesiconCompat.test.ts: Comprehensive unit tests covering:DynamicIcon.ct.tsx: Component tests validating:Implementation Details
lucide-reactto ensure only referenced icons are bundledfile-text)aria-hiddenby default unless anaria-labelis providedhttps://claude.ai/code/session_01MVtcTrYsbeNnDpFoVbxgvm