The project now has exactly one UI library. Every naive-ui component in
packages/client/src is replaced by its Arco equivalent across 24 views and
roughly 80 components, and naive-ui is dropped from package.json along with
its transitive vueuc / @css-render / vdirs / seemly dependencies.
The migration is rendering-layer only. No store logic, no API contract, and
no /chat-run payload was touched.
Three classes of leftover were invisible to `grep naive-ui` and are now
covered by tests/client/no-naive-ui.test.ts, which asserts all three:
- dead .n-* class names in style blocks
- dead --n-* custom properties
- naive-ui in package.json
Notable behavioural traps handled along the way, recorded in
docs/arco-migration-rules.md:
- a-input-password defaults to masked; passing default-visibility="false"
would have exposed API keys in clear text
- a-upload fires a real XHR unless auto-upload is false
- nested Trigger components fight over the first element child, so the
group-chat settings dropdown was flattened
- Arco renders tooltip default-slot text inline, which was silently
collapsing the chat and group-chat toolbars
4.1 KiB
date, pr, feature, impact
| date | pr | feature | impact |
|---|---|---|---|
| 2026-10-18 | pending | Phase 007 - full naive-ui to Arco Design Vue migration across all remaining views | Rendering-layer only. Every naive-ui component in packages/client/src is replaced by its Arco Design Vue equivalent across 24 views and roughly 80 components, and the naive-ui dependency is removed from package.json and package-lock.json. No chat store logic, no /chat-run payload, and no message rendering path is touched. Three chat-chain files changed as a consequence of that rendering-only sweep, listed below with the specific reason each needed a change. |
Phase 007 — full Arco migration
Phase 006 moved the chat page. Phase 007 finished the job: grep -rn "naive-ui\|vueuc\|@css-render" packages/client/src is now empty, and the project has exactly one UI library.
Batches 7a-7g each shipped independently per docs/phases/phase_007.md. docs/arco-migration-rules.md holds the component mapping table the whole sweep followed.
Why chat-chain files changed
Four files under the chat chain were caught by the sweep. None of the changes touch logic.
chat/ChatPanel.vue
- Three leftover naive CSS custom properties were still referenced:
--n-text-color-3(twice) and--n-color-hover(once). These were dead after Phase 006 — the variables no longer resolve, so the rules silently did nothing. Rewritten to the project's own tokens (--text-muted,--bg-card-hover). :native-scrollbar="false"on the workspace dropdown had no Arco counterpart and was dropped.
group-chat/GroupChatInput.vue
- Eighteen dead naive rules under
.tool-trace-toggle,.input-settings-buttonand.send-buttontargeted.n-button__content,.n-button__icon,.n-button__border,.n-button__state-border,.n-button__rippleand.n-base-wave. Arco'sa-buttonhas no content wrapper and none of the ripple internals, sogapnow lives on the button itself and the ripple rules were deleted rather than renamed. - The settings button was
NDropdown > NTooltip > NButton— a three-deep Trigger nest. Arco's Trigger components each claim the first element child viamergeFirstChild, so nested popups fight over it and the menu never opens. Flattened toa-dropdown > a-buttonwith the description moved to a native:title, which is the same approach Phase 006 already took inChatInput.vue. - The attach tooltip carried its label as trailing default-slot text. Arco renders the
default slot inline, so that text became a zero-width flex item in the toolbar. Moved to
the
contentprop.
group-chat/CreateRoomForm.vue
- Straight component swap.
InputLikeInstance = { focus: () => void }was kept because Arco'sa-inputstill exposesfocus()(es/input/input.js:315), so the existingnextTickfocus calls still work.
group-chat/GroupChatPanel.vue
- The room context menu was
NDropdownintrigger="manual"mode driven by:x/:y/:show/@clickoutside. Arco has no manual trigger, so it becamea-trigger trigger="contextMenu"with:popup-stylefor coordinates, matching the pattern already used byFileContextMenu.vueandWorkflowView.vue. Arco'sclickOutsideToClosedefaults to true, which replaces the hand-written clickoutside handler. NPopover'splacement="bottom-end"maps to Arcoposition="br"(bottom-right). Arco'sa-popoverhas nowidthprop and itsTriggersetsinheritAttrs: false, so a:widthwould be dropped silently; the width moved to:content-style.
Verification
packages/client/src has zero naive references by three independent checks — naive-ui
imports, .n-* class names in style blocks, and --n-* custom properties. The last two
matter because grep naive-ui cannot see them; tests/client/no-naive-ui.test.ts now
guards all three so the patterns cannot come back.
Behavior impact
Rendering-layer only. No chat store logic, no /chat-run payload, and no message rendering
path was touched. The group-chat message bubbles already used plain HTML and were left
untouched, so the "no Arco components inside bubbles" rule still holds — a-tree, a-select
and the other components appear only outside the bubble.