refactor(ui-core): the frontend draws lucide again - #777
Merged
Conversation
Swaps the declared icon library back: `lucide-react` in, `@tabler/icons-react` out, in both manifests and the lockfile. The lockfile is resolved from the manifests and a frozen install runs from an empty tree, so the two agree rather than being asserted to. Tabler goes out in the same change rather than being left declared. Nothing imports it once the sources move, and an icon library nobody draws from is the dependency the previous cleanup removed for exactly this reason.
One hundred and ninety-six references over thirty-nine files - the primitives, the screens, the patterns, the annotation workspace, the shell and the styleguide - move from `@tabler/icons-react` back to `lucide-react`. All seventy-two distinct glyphs were resolved against the installed package before anything was rewritten, and every one has an equivalent. The rewrite is keyed on the mapped names rather than on an `Icon*` prefix, which matters in one place: the demo's tool strip has a local component called `IconButton`, and a prefix rewrite would have renamed a component that belongs to neither library. `ProjectNav` needed a second edit the mapping could not carry. It imports the icon *component type*, and the two libraries spell it differently - Tabler's `Icon` against lucide's `LucideIcon` - so the name moved with the import while the local `icon: Icon` destructuring, which is a value and not the type, stayed as it was. The geometry glyphs return to the spelling they had before: `Spline` for the polygon and `Waypoints` for the lane. `GeometryIcon`'s own note argues that pairing and is coherent again as written.
The rule the gate holds is "one icon library", not "this particular library" - what costs a reader is two sets on one screen, where the same idea arrives at two weights and two grids. So the guarded name is the only thing that changes when the choice does, and it now names Tabler. Both halves were re-proved by breaking them: a manifest that declares it fails, and a source that imports it fails naming the file. `components.json` says `iconLibrary: lucide`, which the strict shadcn schema accepts - checked with `rawConfigSchema.safeParse` rather than assumed, since that schema rejects a field it does not define rather than ignoring it. `projectNav`'s assertion was written to prove the migration *away* from lucide and would have passed for a file that stopped drawing icons at all. It asserts both directions now: the set the file draws, and the one it must not reach back for.
…ce is written down Four surfaces said Tabler was the set. They say lucide now, and the anti-pattern states the rule as *one* set rather than one particular set, so the next swap updates a name instead of an argument. One line deliberately still says `tabler`, and it is the one that decodes the preset: `b3bXyyPdWj` really does decode `iconLibrary: tabler`, and falsifying that to match the product would make the document lie about the CLI's own output. What changed is that `components.json` now diverges from the preset on this one property - a decision the schema accepts - so both `DESIGN.md`'s Source of Truth and the architecture note record the divergence in the place built for exactly this distinction. Nobody should have to find it by diffing the two.
Every reference image holds icons, so all ten change. They were regenerated in the canonical container, opened and read rather than accepted from a green run, and the suite passes three consecutive times against them with no further update. The baselines going red on an icon swap is the gate working. Regenerating them is the answer only because the change was intended.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The frontend draws
lucide-reactagain. One hundred and ninety-six references overthirty-nine files, both manifests, the lockfile, the configuration, the gate that
holds it, the documentation that describes it, and the ten reference images that
photograph it.
This reverses the icon half of #771 and #774. Those changes were sound when they
were made; this is a product decision to draw a different set, not a defect being
corrected, and everything that recorded the old choice moves with it rather than
being left to contradict the code.
The migration
Seventy-two distinct glyphs, every one resolved against the installed
lucide-reactbefore anything was rewritten — the same discipline the migration inthe other direction used, and for the same reason: icon names are not guessable
between libraries. None was missing.
Two details the mapping alone could not carry.
The rewrite is keyed on names, not on a prefix. The demo's tool strip has a
local component called
IconButton. A blanketIcon*rewrite would have renamed acomponent belonging to neither library.
ProjectNavimports the icon component type, and the libraries spell itdifferently — Tabler's
Iconagainst lucide'sLucideIcon. That surfaced as acompile error rather than as anything subtler, and the fix moved the type while
leaving the local
icon: Icondestructuring alone, which is a value.The geometry glyphs return to the spelling they had before:
Splinefor the polygonand
Waypointsfor the lane. Worth one note, since the migration the other way madea point of this:
GeometryIconargues that a lane must read as an open path andthat
Splineis the closed shape above it. That reasoning is the original code's andis coherent again as written — but lucide's
Splinedoes render as an open curve, soif the closed/open distinction matters more than the restoration does, that is a
separate and much smaller change to make deliberately.
The configuration, and one honest divergence
components.jsonsaysiconLibrary: lucide. The strict shadcn schema accepts thevalue — checked with
rawConfigSchema.safeParserather than assumed, since thatschema rejects a field it does not define rather than ignoring it.
The preset does not.
b3bXyyPdWjdecodesiconLibrary: tabler, andDESIGN.mdstill says so on the line that reports the decode, because falsifying that to match
the product would make the document lie about the CLI's own output. What changed is
that the configuration now diverges from the preset on this one property, and both
DESIGN.md's Source of Truth and the architecture note record the divergence inthe section built for exactly this distinction. It is the only place where reading
the preset and reading the configuration give different answers, and nobody should
have to discover that by diffing them.
The gate
It guarded lucide; it guards Tabler now. The rule it holds is one icon library
rather than one particular library — what costs a reader is two sets on a screen,
where the same idea arrives at two weights and two grids — so the guarded name is
the only thing that changes when the choice does, and the docstring says that.
Both halves were re-proved by breaking them: a manifest that declares the other set
fails, and a source that imports it fails naming the file.
projectNav's own assertion was written to prove the migration away from lucide,and as written it would have passed for a file that stopped drawing icons at all. It
asserts both directions now.
The baselines
All ten reference images hold icons, so all ten changed. They were regenerated in
the canonical container, opened and read rather than accepted from a green run, and
the suite passes three consecutive runs against them with no further update.
Them going red on an icon swap is the gate working. Regenerating was the answer only
because the change was intended.
Test plan
Every command ran inside Docker/Linux; no repository validation ran natively on the
host.
Overlap
DEPENDENCY OVERLAP with #775. It edits
frontend/app/package.json,frontend/ui-core/package.jsonandpnpm-lock.yaml— the same three files, and itraises
lucide-reactto 1.33.0, which is the version this branch resolves toanyway. Whichever lands second wants a rebase rather than a merge resolution.
#775 also raises
shadcnfrom 4.18.0 to 4.19.0, and that package is a runtime CSSdependency here. If the bump moves base styles, the visual suite goes red on merge —
which is the gate working, and wants the diff images read rather than a blind
regeneration.
Scope
Nothing about the product's behaviour changes here. What changes is which set the
glyphs come from, and every record of that choice.