Skip to content

feat(apollo-react): document the Wind chat setup and its delivery - #1399

Open
BenGSchulz wants to merge 1 commit into
feat/wind-chat-history-settingsfrom
feat/wind-chat-css-delivery-docs
Open

BenGSchulz wants to merge 1 commit into
feat/wind-chat-history-settingsfrom
feat/wind-chat-css-delivery-docs

Conversation

@BenGSchulz

@BenGSchulz BenGSchulz commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Eighth PR of the Wind chat renderer stack (MST-16569): CSS delivery, Wind for ap-chat hosts, and the docs for hosts.

CSS delivery

  • src/chat/styles/tailwind.chat.css already covered what Wind needs at runtime: the apollo-wind theme (Tailwind, the apollo-core theme variables, apollo-wind's own utilities such as scroll-fade-*), plus the utilities scanned from src/chat (stories and tests excluded) and apollo-wind's built components. No change to it.
    • No extra stylesheets are needed: math renders as MathML and code highlighting uses inline styles from CSS variables, so neither KaTeX nor Prism CSS is required.
    • Checked on a clean pnpm build: the built dist/chat/styles/tailwind.chat.css contains classes from every area, e.g. header min-h-16 and data-separator:border-b, message list mb-[var(--chat-message-group-gap)] and @container, markdown [&_math]:text-[1.15em], attachments max-w-[calc(50cqw-4px)] and justify-end-safe, composer [&_[data-slot=attachment]]:max-w-[calc(50%-4px)], history border-selection-indicator and [@media(hover:none)]:opacity-100, settings data-[state=closed]:translate-x-[calc(100%+1rem)] and motion-reduce:transition-none.
  • package.json: ./chat/styles/*.css was already exported and **/*.css is in sideEffects.
  • No utilities-only variant (decided). DOCS.md documents two setups: a host with its own Tailwind v4 build adds @source lines for apollo-wind and @uipath/apollo-react/dist/chat and imports no precompiled sheet; a host without one imports tailwind.chat.css, with its page-wide effects spelled out (below). Two precompiled sheets should never be combined: each brings its own utility order, so a repeated utility can override one the first sheet ordered after it.

Wind for ap-chat hosts

  • ApChat from @uipath/apollo-react/ap-chat registers Wind lazily, so a MUI host opts in with renderer: 'wind' (or setRenderer('wind')) without changing its imports. Before, renderer: 'wind' from ap-chat fell back to Material with a warning.
  • Registration order: both entries register their renderers with the new registerChatRendererIfAbsent, so whichever entry loads first keeps its registrations. An entry loaded later (for example in a code-split route) never swaps the component type under a mounted chat, which would remount it, and never downgrades a loaded renderer to a lazy one. The public registerChatRenderer / registerLazyChatRenderer still replace. ap-chat.tsx is now re-export only plus the Wind registration, so dist/material/components/ap-chat/ap-chat.{js,cjs} is added to sideEffects.
  • <ap-chat> stays Material: the element imports a new Material-only module (material/components/ap-chat/ap-chat-material) that never reaches Wind, and pins Material through a new internal ChatRoot renderer prop, warning once when the service asks for renderer: 'wind'. Documented in the web component README and DOCS.md.

Lucide icons

  • Wind's custom icon names (header actions, message actions, resource items, tree spans) resolve against the lucide-react namespace inside wind/common/lucide-icon.tsx, which ServiceIcon loads with React.lazy. Kebab-case and PascalCase names work, including lucide's deprecated aliases (alert-circle, AlertCircle, more-horizontal, edit, bar-chart, ...); unknown names show the neutral box; lucide's non-icon exports do not count.
  • Why not lucide-react/dynamic: lucide-react has no exports map and ships that subpath only as dynamic.mjs, which the web component's resolver (and webpack's defaults) did not probe; Storybook (Vite) does, so the playground never showed it. The web component build also resolves .mjs and .cjs now.
  • Bundle trade-off: the initial chunk carries no icon set. The first custom icon loads the namespace chunk once: the 1,703 icon modules plus the namespace's 5,842 export names (aliases, *Icon and Lucide* forms). Measured with esbuild: about 704 KB raw / 172 KB gzip, of which the alias names are about 126 KB raw / 27 KB gzip over the icons map alone. Before, DynamicIcon loaded one small chunk per icon used.

Web component dist (production rsbuild)

Before this round (c9deece) Now
JS files 154 87
All JS, raw 7.30 MB 4.42 MB
All JS, gzip (concatenated) 1.98 MB 1.25 MB
index.js 1,093 KB 1,044 KB
Total dist, fonts included 52.3 MB 49.3 MB

No chunk contains Wind or the lucide icon set: the element cannot reach either.

Docs

  • material/components/ap-chat/DOCS.md moved to src/chat/DOCS.md, with a one-line pointer left at the old path for published links. Links updated in the apollo-react README, src/chat/README.md, the web component README and the playground's docs page.
  • New DOCS.md sections:
    • Renderers and setup: the two entries and their defaults, Wind in a new host, Wind in an existing MUI host (opt-in, styles, theme class behaviour, enableInternalThemeProvider being Material-only, the configuration Wind ignores: theming.scrollBar, theming.chatMenu.groupItemTooltipPlacement, and in spacing everything but compactMode, promptBox, messageSpacing and messageGroupGap), <ap-chat> staying Material.
    • Styles: the two setups. For the precompiled sheet it states the page-wide effects: un-layered global rules (theme variables on :root, :host and the theme classes; scrollbar styling under .dark, .dark-hc and .future-dark, so in a MUI host with body.dark every scrollbar on the page is restyled; .wireframe resets; the sonner toaster; .mat-typography resets), Tailwind's preflight in @layer base resetting unstyled host elements, and utilities that lose to un-layered host rules on the same elements. The host accepts these or uses its own Tailwind build.
    • Renderer differences: what Wind does not have yet, and the intended differences decided in R-1 to R-7 (collected from the seven PR descriptions).
    • Icons: the lucide icon-name contract for Wind (aliases included) against Material Icons names in Material, and that the first custom icon loads the icon set on demand.
    • setRenderer in the API table, renderer and the future themes in the configuration type, and the ApChat examples' service prop corrected to chatServiceInstance.
    • The src/chat import boundary: lint-enforced by Biome noRestrictedImports; indirect reach through shared modules such as src/i18n is left to review.
  • material/components/ap-chat/CLAUDE.md rewritten for the two-renderer layout: where things live, the rules (hoisting, the MUI boundary, apollo-wind only in Wind, Material for fixes, en.json only), and testing.
  • material/components/ap-chat/readme.md (Stencil leftover) deleted.

Decided

  1. Docs-only CSS guidance, no utilities-only variant.
  2. Keep the Wind opt-in from ap-chat.
  3. No bundle boundary script for now: the Biome rule plus review.
  4. Alias support in the icon lookup, at about 27 KB gzip on the on-demand icon chunk.

Found on the way (not changed)

  • apollo-wind's popovers, dialogs and tooltips use shadcn's animate-in, fade-in-0, zoom-in-95 and slide-in-from-* classes, but nothing defines them (no tw-animate-css), so those surfaces open without animation, in apollo-wind's own styles.css too. A W-10 gap.
  • The Material renderer logs a React "change in the order of Hooks" warning while a markdown reply streams. It reproduces with the pre-stack Material markdown files too, so it is not from this stack.
  • dist/chat/stories/*.d.ts is emitted by the type build (types only, as before this stack).
  • web-packages/ap-chat/rsbuild.config.ts has a Biome format error and a noUselessTernary info that predate this PR.

What to verify

  • Storybook: pnpm storybook:design, Apollo React / Chat / Playground, renderer: both, Embedded and FullScreen, light and dark. Message actions scenario with customHeaderActions on: the custom icons render (checked: kebab-case, PascalCase and aliases such as alert-circle; a Material icon name shows the neutral box).
  • Consumer-style check: pnpm --filter @uipath/apollo-react build, then grep dist/chat/styles/tailwind.chat.css for the classes listed above; NODE_ENV=production pnpm exec rsbuild build in web-packages/ap-chat.
  • DOCS.md read-through: Renderers and setup, Styles, Renderer differences, Icons.

Tests

  • apollo-react vitest --run src/chat src/material/components/ap-chat src/material/components/ap-tool-call: 63 files, 371 tests pass. New: the ap-chat entry renders Material by default and Wind on opt-in; both import orders of the two entries keep the first registrations; registerChatRendererIfAbsent; a pinned renderer with its single warning; the icon-name resolver with aliases.
  • Web component vitest: 43 tests pass, including the pinned Material renderer.
  • tsc --noEmit clean in both packages; biome check on touched files: no new diagnostics.
  • pnpm --filter @uipath/apollo-react build and the web component production build pass.

Stack

  1. R-1 Wind shell: feat(apollo-react): add the Wind chat renderer shell #1371
  2. R-2 message list: feat(apollo-react): add the Wind chat message list #1372
  3. R-3 markdown renderer: feat(apollo-react): add the Wind chat markdown renderer #1375
  4. R-4 tool-call and tree renderers: feat(apollo-react): add the Wind chat tool-call and tree renderers #1376
  5. R-5 composer: feat(apollo-react): add the Wind chat composer #1378
  6. R-6 first run, suggestions and thinking state: feat(apollo-react): add the Wind chat first run, suggestions and thinking state #1396
  7. R-7 history and settings: feat(apollo-react): add the Wind chat history and settings panels #1397
  8. R-8 CSS delivery and docs: feat(apollo-react): document the Wind chat setup and its delivery #1399 (this PR)

Jira: MST-16569

🤖 Generated with Claude Code

@github-actions
github-actions Bot temporarily deployed to preview/apollo-design October 16, 2026 23:16 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-vertex October 16, 2026 23:16 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-docs October 16, 2026 23:16 Destroyed
@github-actions
github-actions Bot temporarily deployed to preview/apollo-landing October 16, 2026 23:16 Destroyed
@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1947 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1713
ISC 91
Apache-2.0 56
BSD-3-Clause 28
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.4 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

Let hosts on @uipath/apollo-react/ap-chat opt in to the Wind renderer
with renderer: 'wind': the ap-chat entry registers Wind lazily, so a
host that never asks for it does not load it. Both ApChat entries now
register their renderers only when the name has none, so whichever
entry loads first keeps its registrations: a later entry never swaps
the component type under a mounted chat or downgrades a loaded
renderer to a lazy one.

The <ap-chat> web component stays Material in this release: it uses a
Material-only ApChat module that never reaches Wind, and pins Material
through a new internal ChatRoot renderer prop, warning once when the
service asks for Wind.

Resolve Wind's custom icon names against the lucide-react namespace,
loaded in its own chunk on first use, instead of the
lucide-react/dynamic subpath. lucide-react has no exports map and ships
that subpath only as dynamic.mjs, which webpack-style resolvers without
.mjs (including the <ap-chat> build) could not find. The namespace also
covers lucide's deprecated alias names. The web component build now
also resolves .mjs and .cjs.

Move the chat documentation to src/chat/DOCS.md, leaving a pointer at
the old path, and add the setup for both entries, the styles a host
imports (its own Tailwind build with an @source for dist/chat, or the
precompiled tailwind.chat.css with its page-wide effects, never two
precompiled sheets together), the configuration Wind ignores, the
renderer differences decided across the Wind stack and the icon-name
contract. Rewrite the Material renderer's CLAUDE.md for the
two-renderer layout, drop its Stencil readme, and note that <ap-chat>
stays Material. The src/chat import boundary stays lint-enforced.

MST-16569

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BenGSchulz
BenGSchulz force-pushed the feat/wind-chat-css-delivery-docs branch from c9deece to fdd9588 Compare October 17, 2026 00:26
@BenGSchulz BenGSchulz changed the title feat(apollo-react): document the Wind chat setup and guard its bundle feat(apollo-react): document the Wind chat setup and its delivery Oct 17, 2026
@BenGSchulz
BenGSchulz added this pull request to stack #1374 October 17, 2026 00:37
@github-actions

Copy link
Copy Markdown
Contributor

📊 Coverage + size by package

Per-package coverage and bundle size on this PR. New-line coverage = of the source lines this PR adds or changes, the % hit by tests.

Package Coverage New-line coverage Packed (gzip) Unpacked vs main
@uipath/apollo-core — — 42.02 MB 50.17 MB ±0
@uipath/apollo-react 57.7% 100.0% (34/34) 8.05 MB 31.72 MB +59.4 KB
@uipath/apollo-ui-icons — — 2.86 MB 6.97 MB ±0
@uipath/apollo-vertex — — — — —
@uipath/apollo-wind — — 785.2 KB 4.55 MB +12 B
@uipath/ap-chat 85.8% — (8 untracked) 40.37 MB 45.59 MB +3.7 KB

"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.

@BenGSchulz
BenGSchulz marked this pull request as ready for review October 17, 2026 00:54
Copilot AI balanced review requested due to automatic review settings October 17, 2026 00:54

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions github-actions Bot added the size:XXL 1,000+ changed lines. label Oct 17, 2026

This branch was successfully deployed

4 active deployments
preview/apollo-docs — fdd9588b Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-design — fdd9588b Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-vertex — fdd9588b Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-landing — fdd9588b Deployed Oct 17, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants