Skip to content

feat(apollo-wind): default lucide icon stroke to 1.4 - #1085

Draft
BenGSchulz wants to merge 1 commit into
mainfrom
feat/MST-14019-lucide-icon-stroke-default
Draft

feat(apollo-wind): default lucide icon stroke to 1.4#1085
BenGSchulz wants to merge 1 commit into
mainfrom
feat/MST-14019-lucide-icon-stroke-default

Conversation

@BenGSchulz

@BenGSchulz BenGSchulz commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Sets lucide's icon stroke to 1.4 for every consumer of the apollo-wind styles, and moves lucide-react to a peer dependency so consumers share a single copy.

Design confirmed 1.4 as the system-wide default. Filed from the Flow UX Audit (MST-14019), but the fix belongs here rather than in a consumer: apollo-wind renders its own lucide icons (accordion chevrons, select carets), which a downstream rule can't reach cleanly.

Why CSS, and why the selector looks like that

On the version range we support today, lucide has no theming APIIcon hard-codes strokeWidth = 2 as a default parameter and spreads it onto the SVG. So CSS is the only lever. (1.x changes this — see the last section.)

The catch is that a stylesheet outranks the presentation attribute the prop compiles to, so a blanket svg.lucide { stroke-width: 1.4 } would silently break every strokeWidth prop in every consumer. I verified this in Chromium rather than trusting the spec — cascade layers do not change it; a layered rule still beat stroke-width="3" and stroke-width="0".

So the rule matches lucide's default value only:

svg.lucide[stroke-width="2"] { stroke-width: 1.4; }
call site result
default icon 1.4 ✅
strokeWidth={0} (filled glyphs) 0 ✅
strokeWidth={3} 3 ✅
className="stroke-2" 2 ✅

Only the value 2 is indistinguishable from "no opinion", so a strokeWidth={2} meaning keep this bold is the one case that would be silently thinned. stroke-2 is the documented opt-out — it lands in the utilities layer, which the cascade resolves after base regardless of specificity, so it wins.

@source inline("stroke-2") safelists it. Tailwind only emits utilities it finds while scanning source, and nothing in apollo-wind writes stroke-2 — without the safelist the escape hatch would be missing from the prebuilt styles.css for consumers who ship that file instead of building from tailwind.css. Verified against the real built artifact, both before and after.

lucide-react as a peer dependency

lucide-react was a hard dependency of apollo-wind and apollo-react, so consumers ended up with a second copy. It's also already part of the public type surface — NodeOutputModeIcon is a LucideIcon, as is LockableValueField's icon prop — so a consumer passing its own icon is passing a type from a different module instance.

Range is >=0.577.0 <2 — deliberately spanning both current majors, since everything apollo uses (Icon, createLucideIcon, LucideIcon, LucideProps, the named icons) is present in both. Both packages keep it as a devDependency. Released as a minor, not a major: the range is permissive and auto-install-peers is the default in npm 7+, pnpm 8+, and yarn berry.

Follow-up: LucideProvider should eventually replace this rule

Worth recording, since it changes how the CSS above should be maintained rather than merely extended.

lucide 1.x (latest is 1.34.0; we're on 0.577.0) adds LucideProvider, and Icon now resolves strokeWidth ?? contextStrokeWidth. Nullish coalescing means strokeWidth={0} survives and strokeWidth={2} is genuinely honored — it makes 1.4 a real React default and removes the ambiguity this PR works around, with no selector and no safelist.

Important: the two mechanisms don't compose. Under a provider a deliberate strokeWidth={2} renders as 2 and this rule would thin it all over again. Replace the rule with the provider; don't run both. The CSS comment says the same thing in-place.

Why this isn't bundled here

Adopting the provider means a peer floor of >=1, which is a genuinely breaking change for every consumer — and a provider only covers the React tree it wraps. apollo-wind has no root provider to host it, so each consuming app would mount its own, and consumers with multiple React roots (flow-workbench's <ui-flow-canvas> web components, Studio Web's module federation) would need per-root coverage verified. The CSS rule needs zero consumer code and works on 0.x and 1.x alike.

What a >=1 floor would actually force

The icon set loses 29 keys from the runtime icons map (1703 → 1777; +103, −29). They split into three tiers with very different consequences:

tier count import { X } icons['X'] lookup
Brand logos — Github, Figma, Slack, Twitter, Youtube, Gitlab, Linkedin, Instagram, Facebook, Trello, Twitch, Framer, Dribbble, Codepen, Codesandbox, Pocket, Chromium, RailSymbol 18 ❌ gone ❌ gone
Canonically renamed, alias retained 11 ✅ still works silently gone
Everything else, plus 103 new 1777

The renamed 11: History→RotateCcwClock, Waves→WavesHorizontal, Smile→FaceSlightlySmiling, Frown→FaceSlightlyFrowning, Meh→FaceNeutral, Angry→FaceAngry, Annoyed→FaceExpressionless, Laugh→FaceGrinning, SmilePlus→FaceSlightlySmilingPlus, Podcast→MicSignal, TextSelect→SquareDashedText.

The compile-time surface is small — 18 brand icons, and neither apollo-ui nor flow-workbench imports any of them. LucideIcon/LucideProps are intact, aliases like AlertTriangle → TriangleAlert are preserved, and 1.x still emits class="lucide", so this PR's rule stays valid either way.

The hazard is the data-driven path. The icons map holds canonical names only, so icons['History'] is now undefined for all 29. apollo-react/src/canvas/utils/icon-registry.tsx does exactly that lookup and falls back to Box — no error, no crash, no log. flow-workbench feeds it display.icon, typed z.string().optional() and resolved from server-fetched connector manifests. A Slack or GitHub connector icon would silently render as a generic box in production, and because the data isn't in the repo, no grep can clear it.

Cheap mitigation, worth landing ahead of any upgrade: a ~30-line alias map in icon-registry.tsx translating the 29 legacy ids to their new canonical names before the Box fallback. That turns the silent tier into a non-event and is harmless on 0.x.

Packaging changes in 1.x

  • ESM entry dist/esm/lucide-react.js.mjs. Neither repo deep-imports, so it's a non-issue here; it breaks anyone who does.
  • unpkg and main:umd removed — no UMD/CDN build.
  • "use client" added to Icon and context. Benign for Vite/rsbuild; relevant for RSC consumers and may surface directive warnings in some Rollup setups.
  • React peer unchanged (^16.5.1 || ^17 || ^18 || ^19).

Net: the cost isn't "fix 18 imports", it's "audit runtime manifest data across every consumer, including connector icons we don't control" — a coordination problem with Studio Web and the connector teams, not an apollo-local change.

Scope notes for review

  • One redundant prop removed<Sparkles strokeWidth={2}> in ideas-AnimatedGradientText.tsx. I swept all 43 strokeWidth=2 sites in the repo and classified each by enclosing tag; this is the only one on a lucide icon. The rest are recharts (Line/Pie/Radar), raw SVG primitives, and hand-authored icon components — all of which would drop to 1, not 1.4, if the prop were removed. They're untouched.
  • token-icon-markup.ts thins, correctly — it hand-builds markup carrying class="lucide" precisely to mirror lucide's output. The strokeWidth={2} in tree-view.tsx and TokenPill.tsx are hand-rolled <svg><path> with no lucide class and are unaffected.
  • apollo-vertex is deliberately untouched. It has no dependency on apollo-wind — not in package.json, not in globals.css — so it never receives this rule, and DESIGN-CONTEXT.md documents it as a distinct design system. Its icon catalogue hard-codes 1.5; whether Vertex tracks 1.4 is a Vertex design call, not this PR's.

Testing

typecheck, build, lint, format:check green; 1409 (wind) + 2585 (react) unit tests pass.

New coverage in src/styles/tailwind.consumer.test.ts, following the file's existing pattern of parsing the selector out of the stylesheet so the cases can't drift from what ships: the rule is brace-matched to be inside @layer base, the safelist is asserted, and the selector is exercised against real elements — a default lucide icon matches, while stroke-width 0 / 1 / 1.5 / 2.5 / 3 and non-lucide svgs (recharts series, edge handles, hand-authored icons) do not.

Mutation-checked rather than assumed — each guard was confirmed to fail when the CSS is broken:

mutation tests failed
drop @source inline("stroke-2") 1
blanket svg.lucide selector 6
rule hoisted out of @layer base 1
weight changed to 1.5 1

⚠️ test:visual snapshots will need a wholesale update — this moves nearly every icon in the system by design. I deliberately have not run or approved them; that's a reviewer/design judgement.

Copilot AI lite review requested due to automatic review settings August 26, 2026 00:23
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Apollo Coded App preview deployments are ready.

Project Status Preview Updated (PT)
apollo-design Ready Preview · Logs Aug 25, 2026, 06:01:15 PM
apollo-docs Ready Preview · Logs Aug 25, 2026, 06:01:15 PM
apollo-landing Ready Preview · Logs Aug 25, 2026, 06:01:15 PM
apollo-vertex Ready Preview · Logs Aug 25, 2026, 06:01:15 PM

@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • 1951 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1722
ISC 88
Apache-2.0 55
BSD-3-Clause 27
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.2 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

@BenGSchulz
BenGSchulz marked this pull request as draft August 26, 2026 00:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates Apollo Wind’s default Lucide icon stroke weight to 1.4 via a narrowly-scoped CSS rule (only affecting Lucide’s default stroke-width="2"), and moves lucide-react from a direct dependency to a peer dependency in both apollo-wind and apollo-react to ensure consumers share a single module instance (avoiding duplicated types/instances).

Changes:

  • Add a base-layer CSS rule to default Lucide’s stroke-width from 21.4, while preserving non-default strokeWidth values.
  • Safelist the stroke-2 utility so consumers of the prebuilt CSS have a documented opt-out.
  • Move lucide-react to peerDependencies (kept as devDependency for local build/test) in apollo-wind and apollo-react, with corresponding lockfile updates.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
pnpm-lock.yaml Reflects dependency graph changes from moving lucide-react to peers/dev deps and related resolution updates.
packages/apollo-wind/src/templates/Patterns/ideas-AnimatedGradientText.tsx Removes a redundant explicit strokeWidth={2} so the new default styling applies.
packages/apollo-wind/src/styles/tailwind.consumer.css Adds the svg.lucide[stroke-width="2"] { stroke-width: 1.4; } rule and safelists stroke-2 for the prebuilt CSS output.
packages/apollo-wind/package.json Moves lucide-react to peerDependencies (and keeps it in devDependencies for build/test).
packages/apollo-react/package.json Moves lucide-react to peerDependencies (and keeps it in devDependencies for build/test).
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@BenGSchulz
BenGSchulz force-pushed the feat/MST-14019-lucide-icon-stroke-default branch from f78dac5 to 71d8ace Compare August 26, 2026 00:34
Copilot AI review requested due to automatic review settings August 26, 2026 00:34
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Storybook visual diff

⚠️ Visual changes detected: 2 changed (of 4 compared, 2 unchanged). View report

Baseline is the deployed main Storybook, so changes merged to main after this branch was last updated can also appear here. Logs

Updated (PT): Aug 25, 2026, 06:03:56 PM

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package bundle size on this PR (no JS/TS source changes detected under packages/* or web-packages/*).

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core 41.59 MB 49.70 MB ±0
@uipath/apollo-react 40.0% 7.56 MB 29.11 MB +22 B
@uipath/apollo-ui-icons 2.85 MB 6.91 MB ±0
@uipath/apollo-wind 64.8% 422.6 KB 2.72 MB +911 B
@uipath/ap-chat 85.8% 43.46 MB 56.09 MB ±0

"Coverage" is each package's own coverage.include scope (e.g. apollo-core instruments only scripts/). "Packed"/"Unpacked" come from npm pack --dry-run and only cover built packages — "—" means not measured this run (package not affected / not built). "vs main" is the packed (gzipped) delta against the last successful main build (the package-sizes artifact from the Release workflow); "—" there means no main baseline was available this run. The baseline is main's latest build, not this PR's exact merge-base, so it includes any drift since the branch diverged. Packages with no vitest config are omitted.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/apollo-wind/src/styles/tailwind.consumer.css
lucide's 2px stroke reads too heavy against Apollo's type; design confirmed 1.4
system-wide.

lucide has no theming API, so CSS is the only lever, and a stylesheet outranks
the presentation attribute the prop compiles to (cascade layers included). The
rule therefore matches lucide's default value only, leaving deliberate weights
like strokeWidth={0} intact. Only 2 is ambiguous, so `stroke-2` is the
documented opt-out, safelisted so it exists in the prebuilt styles.css too.

Also moves lucide-react to peerDependencies in apollo-wind and apollo-react so
consumers share one copy — LucideIcon is already public API, so passing your own
icon means passing a type from a different module instance.

Refs: MST-14019
Copilot AI review requested due to automatic review settings August 26, 2026 00:55
@BenGSchulz
BenGSchulz force-pushed the feat/MST-14019-lucide-icon-stroke-default branch from 71d8ace to 524c08c Compare August 26, 2026 00:55
@github-actions github-actions Bot added size:L 100-499 changed lines. and removed size:M 30-99 changed lines. labels Aug 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread packages/apollo-wind/src/styles/tailwind.consumer.test.ts
@BenGSchulz BenGSchulz added the dev-packages Adds dev package publishing on pushes to this PR label Aug 26, 2026
@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

📦 Dev Packages

Package Status Updated (PT)
@uipath/apollo-react@6.31.1-pr1085.a949ae3 🟢 Published Aug 26, 2026, 09:57:47 AM
@uipath/apollo-wind@2.36.2-pr1085.a949ae3 🟢 Published Aug 26, 2026, 09:57:07 AM

@BenGSchulz BenGSchulz added the do-not-close Prevent closing stale PR's label Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-packages Adds dev package publishing on pushes to this PR do-not-close Prevent closing stale PR's pkg:apollo-react pkg:apollo-wind size:L 100-499 changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants