refactor(spx-gui): replace naive-ui dropdown and tooltip popups#3032
refactor(spx-gui): replace naive-ui dropdown and tooltip popups#3032cn0809 wants to merge 6 commits intogoplus:devfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request replaces the Naive UI-based UIDropdown and UITooltip components with a custom implementation using @floating-ui/dom and a new internal popup management system. It includes updates to UIConfigProvider and UIModal to support this foundation, along with simplified class merging across multiple UI components. Review feedback identifies a logic error in the resolveMaybeRef utility and a functional issue where nested teleported popups may cause parent dropdowns to close prematurely.
There was a problem hiding this comment.
This is a well-architected replacement of naive-ui popup primitives with a custom @floating-ui/dom implementation. The popup stack management, trigger rendering, and floating-position logic are cleanly separated, and the comprehensive test coverage is a strong positive. A few correctness and performance issues are worth addressing before merge.
There was a problem hiding this comment.
Pull request overview
Refactors spx-gui popup primitives to remove Naive UI NPopover/NTooltip dependencies, introducing an internal popup stack + Floating UI–based positioning to better support nested popups and reduce library-specific workarounds (closes #3015).
Changes:
- Replaced
UIDropdownandUITooltipimplementations with internal popups built on@floating-ui/dom, plus a new popup stack/trigger helper layer. - Updated shared popup detection (
isInPopup) to rely on internal popup root attributes rather than Naive UI popover classes. - Standardized
cn(...)usage across UI components (allowingundefinedclass values) and added Vitest coverage for the new popup utilities/components.
Reviewed changes
Copilot reviewed 50 out of 51 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| spx-gui/src/components/ui/utils/index.ts | Switches popup detection to internal popup roots; imports popup helpers. |
| spx-gui/src/components/ui/utils/cn.ts | Allows undefined in ClassValue to simplify cn(..., props.class) usage. |
| spx-gui/src/components/ui/tab/UITabs.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/tab/UITab.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/select/UISelect.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/radio/UITabRadioGroup.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/radio/UITabRadio.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/radio/UIChipRadioGroup.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/popup/use-floating-popup.ts | New Floating UI positioning composable (placement/offset/arrow/virtual anchor). |
| spx-gui/src/components/ui/popup/use-floating-popup.test.ts | Unit tests for positioning helpers + composable behavior. |
| spx-gui/src/components/ui/popup/trigger.ts | New trigger rendering/flattening + trigger element resolution helpers. |
| spx-gui/src/components/ui/popup/stack.ts | New popup stack for registration, nesting, and root attribute tagging. |
| spx-gui/src/components/ui/popup/stack.test.ts | Unit tests for popup stack nesting/topmost tracking + root discovery. |
| spx-gui/src/components/ui/popup/index.ts | Popup barrel export + global popup animation CSS import. |
| spx-gui/src/components/ui/popup/animations.css | Adds scale/fade popup transition styles. |
| spx-gui/src/components/ui/modal/UIModalClose.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/modal/UIModal.vue | Provides popup container inside modal root for correct teleport targeting. |
| spx-gui/src/components/ui/modal/UIFullScreenModalHeader.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/modal/UIDropdownModal.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/menu/UIMenuItem.vue | Updates useDropdown import to .vue; uses cn(..., props.class). |
| spx-gui/src/components/ui/menu/UIMenuGroup.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/menu/UIMenu.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/loading/UILoading.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/loading/UIDetailedLoading.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/index.ts | Switches UIDropdown export to .vue. |
| spx-gui/src/components/ui/icons/UIIcon.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/error/UIError.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/empty/UIEmpty.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/collapse/UICollapseItem.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/collapse/UICollapse.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/block-items/UICornerIcon.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/block-items/UIBlockItemTitle.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UITooltip.vue | Replaces Naive UI tooltip with internal Floating UI + popup stack implementation. |
| spx-gui/src/components/ui/UITooltip.test.ts | Component tests for tooltip hover delay and hover-to-content behavior. |
| spx-gui/src/components/ui/UITag.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIPagination.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIImg.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIDropdownWithTooltip.test.ts | Integration tests ensuring tooltip/dropdown interplay and modal container support. |
| spx-gui/src/components/ui/UIDropdown.vue | New internal dropdown implementation with popup stack, outside click/Escape handling. |
| spx-gui/src/components/ui/UIDropdown.ts | Removes old NPopover-based dropdown implementation. |
| spx-gui/src/components/ui/UIDropdown.test.ts | Component tests for hover/click behavior, outside click, and nested dropdown topmost logic. |
| spx-gui/src/components/ui/UIConfigProvider.vue | Removes Naive UI Popover/Tooltip theme overrides; provides popup stack globally. |
| spx-gui/src/components/ui/UICode.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIChip.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UICard.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIButtonGroupItem.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIButtonGroup.vue | Uses cn(..., props.class) with updated ClassValue. |
| spx-gui/src/components/ui/UIButton.vue | Uses classes.value.root(props.class) with updated ClassValue. |
| spx-gui/src/components/ui/README.md | Updates guidance to prefer cn(..., props.class) (no ?? null). |
| spx-gui/package.json | Adds @floating-ui/dom dependency. |
| spx-gui/package-lock.json | Locks @floating-ui/* dependency versions. |
Files not reviewed (1)
- spx-gui/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
close: #3015