refactor(spx-gui): rebuild modal infrastructure & remove the naive-ui dependency#3037
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the UI library by replacing Naive UI dependencies for UIDropdown, UITooltip, and UIModal with custom implementations using @floating-ui/dom and internal stack management. Feedback suggests toggling visibility on dropdown clicks, resolving z-index conflicts between dropdowns and modals, and unifying ESC key handling across stack managers. Additionally, suggestions were made to add exit transitions to dropdowns and remove redundant nextTick() calls in the modal focus logic.
There was a problem hiding this comment.
Pull request overview
Refactors spx-gui’s popup/modal infrastructure to remove remaining Naive UI modal coupling by introducing shared internal layer-stack primitives and rebuilding UIModal/modal stack behavior around them (issue #3016).
Changes:
- Added a shared
createLayerStack()+findLayerRoot()utility and refactored popup stack to use it. - Introduced a modal stack +
useModalSurface()composable, and rebuiltUIModal/UIFullScreenModalaround Teleport + internal transitions (noNModal). - Updated provider wiring/tests and migrated editor dropdown-modals to
UIDropdownForm.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| spx-gui/src/components/ui/utils/layer-stack.ts | New shared layer stack primitive (registration/topmost/root attrs + DOM root lookup). |
| spx-gui/src/components/ui/utils/layer-stack.test.ts | Unit tests for the shared layer stack + DOM root lookup. |
| spx-gui/src/components/ui/utils/index.ts | isInPopup now detects modal roots via modal stack markers (removed Naive UI selector logic). |
| spx-gui/src/components/ui/popup/stack.ts | Refactored popup stack to reuse shared layer stack. |
| spx-gui/src/components/ui/popup/stack.test.ts | Removed popup stack test file (coverage now primarily via shared layer-stack tests + component tests). |
| spx-gui/src/components/ui/modal/stack.ts | New modal stack built on shared layer stack. |
| spx-gui/src/components/ui/modal/use-modal-surface.ts | New composable to wire modal surfaces to stack, transform-origin, and modal-local popup container. |
| spx-gui/src/components/ui/modal/use-modal-surface.test.ts | Tests for modal surface wiring (root attrs, popup container, transform-origin behavior). |
| spx-gui/src/components/ui/modal/UIModal.vue | Rebuilt modal as internal Teleport + Transition implementation (no Naive UI NModal). |
| spx-gui/src/components/ui/modal/UIModal.test.ts | New tests for UIModal rendering, attrs, interaction, animation origin, and focus behavior. |
| spx-gui/src/components/ui/modal/UIModalProvider.vue | Updated ESC handling logic to respect modal scope and ignore nested popup ESC events. |
| spx-gui/src/components/ui/modal/UIModalProvider.test.ts | New provider tests for programmatic modals, active/topmost behavior, and ESC filtering. |
| spx-gui/src/components/ui/modal/UIFullScreenModal.vue | Refactored fullscreen modal to use shared useModalSurface() + stack attrs. |
| spx-gui/src/components/ui/modal/UIFullScreenModalHeader.vue | Minor simplification: inline cn(...) usage (remove computed). |
| spx-gui/src/components/ui/modal/UIModalClose.vue | Minor simplification: inline icon size class (remove computed). |
| spx-gui/src/components/ui/modal/index.ts | Updated modal exports to reflect new structure (removes dropdown-modal export, keeps UIModal). |
| spx-gui/src/components/ui/UIConfigProvider.vue | Provides the new modal stack at the UI root (alongside popup stack). |
| spx-gui/src/components/ui/index.ts | Exports UIDropdownForm. |
| spx-gui/src/components/ui/UIDropdownForm.vue | Updated radar text + adjusted imports to match new structure. |
| spx-gui/src/components/ui/README.md | Documentation update describing modal wrapper root-class/attr behavior. |
| spx-gui/src/components/editor/sprite/animation/state/BoundStateEditor.vue | Migrated from UIDropdownModal to UIDropdownForm. |
| spx-gui/src/components/editor/sprite/animation/SoundEditor.vue | Migrated from UIDropdownModal to UIDropdownForm. |
| spx-gui/src/components/editor/sprite/animation/DurationEditor.vue | Migrated from UIDropdownModal to UIDropdownForm. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This is a well-structured refactor. The
|
| // the resolved origin changes. The measured CSS value must be relative to the modal | ||
| // surface itself rather than viewport coordinates. | ||
| watch( | ||
| [visible, containerRef, resolvedTransformOrigin], |
There was a problem hiding this comment.
总感觉 transform origin 的逻辑还有简化空间,再看看?
nighca
left a comment
There was a problem hiding this comment.
总感觉 transform origin 的逻辑还有简化空间,再看看?
感觉还是有点复杂,不过不影响外部使用,先 merge
| const modalContainer = ref<HTMLElement>() | ||
| const currentModals = shallowReactive<ModalInfo[]>([]) | ||
| const emitter: ModalEvents = new Emitter() | ||
| let nextModalId = 0 |
There was a problem hiding this comment.
发现这个其实不是 next modal ID,而是 next modal ID 减 1..
close: #3016
close: #3014