-
Notifications
You must be signed in to change notification settings - Fork 375
feat: multi-node right menu #1248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis set of changes introduces comprehensive multi-selection support across the canvas editing interface. The core logic for handling multiple selected nodes is refactored and expanded, including new methods for grouping, batch wrapping, and manipulating multiple nodes within the composables and container logic. The context menu is updated to provide multi-select-specific actions and UI adjustments, while the design canvas and container components integrate the new selection logic for improved interaction handling. Additionally, the node insertion and block creation logic are enhanced to accommodate multi-selection scenarios, ensuring consistent behavior throughout the editor. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DesignCanvas
participant useMultiSelect
participant CanvasMenu
participant Container
User->>DesignCanvas: Select multiple nodes
DesignCanvas->>useMultiSelect: Update multiSelectedStates
DesignCanvas->>DesignCanvas: Compute multiStateLength
DesignCanvas->>DesignCanvas: Set currentSchema (array if multi-selected)
User->>CanvasMenu: Right-click (open context menu)
CanvasMenu->>useMultiSelect: Determine isMultiSelect
CanvasMenu->>CanvasMenu: Show multi-select menu actions
User->>CanvasMenu: Choose "Group Wrap" or "Batch Wrap"
CanvasMenu->>useMultiSelect: groupAddParent()/batchAddParent()
useMultiSelect->>Container: insertNode (with REPLACE or parent wrap)
Container->>Container: Insert or wrap nodes accordingly
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
🔇 Additional comments (13)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
358e791
to
7a5941c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (7)
packages/canvas/DesignCanvas/src/api/useCanvas.ts (1)
350-354
: Implementreplace
operation for multi-node selection support.The new
replace
case in the switch statement provides a direct replacement operation without copying children, unlike theout
case which preserves the child nodes. This operation is essential for supporting the multi-node functionality introduced in this PR.This is a cleaner approach than reusing the existing
out
case with a flag parameter. Consider adding JSDoc comments to document the difference betweenout
andreplace
operations for future maintainers.packages/plugins/block/src/composable/useBlock.ts (1)
328-344
: Enhance schema handling for multi-node selection.This comprehensive refactoring of the schema handling logic now properly supports three scenarios:
- Null/undefined schema (returns empty array)
- Multiple schemas (when multiple nodes are selected)
- Single schema (traditional case)
The updated logic ensures blocks can be created from multiple selected nodes, supporting the multi-node right-click feature.
Consider adding a detailed comment explaining why
toRaw
is necessary here. It helps prevent reactivity-related issues when working with deep clones of reactive objects.packages/canvas/DesignCanvas/src/DesignCanvas.vue (1)
183-185
: Update schema handling for multi-node selection.Enhanced the
nodeSelected
function to work with multiple selected schemas:
- When multiple nodes are selected, sets current schema to the array of schemas
- Otherwise, falls back to the single selected node or page schema
This properly integrates with the new multi-node right menu feature.
Consider extracting the multi-selection handling logic into a named function for better readability and testability.
packages/canvas/container/src/components/CanvasMenu.vue (2)
215-223
:multiDel
/multiCopy
side‑effects may wipe selection mid‑loop
removeNodeById
andcopyNode
both end up callingclearSelect
, clearingmultiSelectedStates
during the first iteration. Subsequent IDs in the cached array are still processed, but the UI flickers and emits multipleselected
events.Consider batching:
const ids = [...multiSelectedStates.value.map(s => s.id)] closeMenu() ids.forEach(removeNodeById)and defer
clearSelect()
until all operations finish.
317-324
:actionDisabled
can be simplified & made future‑proofRather than hard‑coding two separate white‑lists, derive them from the current selection count:
const needSelection = isMultiSelect.value ? ['multiDel','multiCopy','multiAddParent'] : ['del','copy','addParent']; return needSelection.includes(actionItem.code) && (isMultiSelect.value ? !multiSelectedStates.value.length : !getCurrent().schema?.id)This removes duplication and scales when new actions are added.
packages/canvas/container/src/composables/useMultiSelect.ts (2)
85-117
:areSiblingNodes
does two passes over the tree and can be O(N²)You already obtain
nodesWithParent
; reuse that array to avoid a secondfindIndex
per node:const indices = nodesWithParent.map(({ parent, node }) => parent.children.findIndex((c) => c.id === node.id) )Minor, but helps when thousands of nodes are selected.
302-318
: Potential performance hit inbatchAddParent
Each
insertNode
triggersgetController().addHistory()
insidecontainer.ts
, resulting in n history entries and re‑renders. Consider wrapping the loop in a single history transaction or exposing a bulk API.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/canvas/DesignCanvas/src/DesignCanvas.vue
(4 hunks)packages/canvas/DesignCanvas/src/api/useCanvas.ts
(1 hunks)packages/canvas/container/src/CanvasContainer.vue
(1 hunks)packages/canvas/container/src/components/CanvasMenu.vue
(9 hunks)packages/canvas/container/src/composables/useMultiSelect.ts
(3 hunks)packages/canvas/container/src/container.ts
(4 hunks)packages/plugins/block/src/composable/useBlock.ts
(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: push-check
🔇 Additional comments (6)
packages/canvas/container/src/CanvasContainer.vue (1)
137-141
: Improve right-click handling for multi-selection support.Moving the right-click menu handling to the beginning of the function and immediately returning prevents selection logic from executing on right-click. This allows users to open the context menu on multiple selected nodes without disrupting the selection state.
packages/plugins/block/src/composable/useBlock.ts (1)
13-13
: Add toRaw import for better handling of reactive state.Added
toRaw
import from Vue to properly handle reactive state in thecreateBlock
function.packages/canvas/DesignCanvas/src/DesignCanvas.vue (2)
25-25
: Add imports for multi-selection support.Added necessary imports to support multi-node selection functionality.
Also applies to: 46-46
156-158
: Initialize multi-selection state tracking.Added state tracking for multiple selected nodes using the
useMultiSelect
composable, which is essential for the multi-node context menu functionality.packages/canvas/container/src/container.ts (1)
890-895
:insertNode
switch: newPOSITION.REPLACE
is fineAdding the branch keeps behaviour explicit and avoids falling through to
IN
; good job keeping the control‑flow readable.packages/canvas/container/src/components/CanvasMenu.vue (1)
122-162
: Good separation between single‑ and multi‑select menu definitionsDefining
multiSelectMenus
alongside the original list keeps concerns clean and avoids runtimeif/else
clutter inside templates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (2)
packages/canvas/container/src/components/CanvasMenu.vue (1)
73-78
:⚠️ Potential issueSub-menu placement condition is reversed.
The condition logic for submenu positioning is incorrect. When
right + 137 < canvasRect.right
, it means there is enough space on the right side of the screen, but the code sets the submenu to appear to the right of the parent menu withright: '-137px'
, which is counterintuitive.Apply this fix to correct the submenu positioning:
- if (right + 137 < canvasRect.right) { - subMenuStyles.value = { right: '-137px' } - } else { - subMenuStyles.value = { left: '-137px' } - } + if (right + 137 > canvasRect.right) { + subMenuStyles.value = { left: '-137px' } + } else { + subMenuStyles.value = { right: '-137px' } + }packages/canvas/container/src/composables/useMultiSelect.ts (1)
280-314
:⚠️ Potential issueFix the return value in
batchAddParent
.The
batchAddParent
function always returnsfalse
even when operations succeed. It should also refresh the selection state to update the visual selection rectangles.multiSelectedStates.value.forEach(({ schema, parent }) => { // ... existing implementation ... }) - return false + refreshSelectionState() + return true
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/canvas/container/src/components/CanvasMenu.vue
(9 hunks)packages/canvas/container/src/composables/useMultiSelect.ts
(3 hunks)packages/canvas/container/src/container.ts
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/canvas/container/src/container.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/canvas/container/src/composables/useMultiSelect.ts (3)
packages/canvas/types.ts (1)
Node
(1-6)packages/register/src/hooks.ts (2)
useCanvas
(77-77)useHistory
(79-79)packages/canvas/container/src/container.ts (3)
selectNode
(817-859)insertNode
(868-905)POSITION
(41-49)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: push-check
🔇 Additional comments (4)
packages/canvas/container/src/components/CanvasMenu.vue (1)
122-162
: Good implementation of multi-select menu items.The multi-select menu is well-structured with appropriate operations for deleting, copying, and adding parent containers to multiple selected nodes. The code also properly checks if nodes are siblings for operations that require contiguous node selection.
packages/canvas/container/src/composables/useMultiSelect.ts (3)
81-114
: Well-structured selection utility functions.The
getSelectedNodeIndices
andareSiblingNodes
functions are well-implemented. The code efficiently usesevery
to check for consecutive indices, which is a clean optimization over using a loop.
122-210
: Good implementation of group parent addition.The
groupAddParent
method effectively handles the grouping of sibling nodes with special handling for different component types likeTinyPopover
. The approach of deleting original nodes and inserting the new wrapper at the first selected node's position is sound.
219-272
: Well-implemented wrapper schema creation.The
createWrapperSchema
function cleanly handles the creation of wrapper components with special cases for components likeTinyPopover
. The function properly merges provided props with default ones.
English | 简体中文
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Background and solution
What is the current behavior?
目前不支持画布多选节点右键菜单
Issue Number: N/A
What is the new behavior?
支持画布多选节点右键菜单, 支持以下操作
删除
多选节点后右键点击删除,可以批量删除节点元素
复制
多选节点后右键点击复制,可以批量复制元素
添加父级:容器(批量)、容器(公共父级)、文字提示(公共父级)、弹出框(公共父级)
批量添加:可以给多选节点批量添加 div 容器
公共父级:可以给多选节点添加一个共同的父级容器、可以选择容器(div)、文字提示(Tooltip)、弹出框 (Popover)
备注:如果是兄弟节点(相同父级且为连续节点),既可以选择批量添加、也可以添加公共父级
如果是非兄弟节点,则只能选择批量添加
保存页面后,多选节点。右键选择新建区块,输入 区块名称 和 区块 ID 后,即可新建区块
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
Summary by CodeRabbit