diff --git a/packages/blocks/src/root-block/edgeless/edgeless-keyboard.ts b/packages/blocks/src/root-block/edgeless/edgeless-keyboard.ts
index 429b451dcbcb..a22f94fcd1b3 100644
--- a/packages/blocks/src/root-block/edgeless/edgeless-keyboard.ts
+++ b/packages/blocks/src/root-block/edgeless/edgeless-keyboard.ts
@@ -2,8 +2,11 @@ import { IS_MAC } from '@blocksuite/global/env';
import { type EdgelessTool, LassoMode } from '../../_common/types.js';
import { matchFlavours } from '../../_common/utils/model.js';
-import type { MindmapElementModel } from '../../surface-block/element-model/mindmap.js';
-import type { ShapeElementModel } from '../../surface-block/index.js';
+import { MindmapElementModel } from '../../surface-block/element-model/mindmap.js';
+import type {
+ ElementModel,
+ ShapeElementModel,
+} from '../../surface-block/index.js';
import {
Bound,
ConnectorElementModel,
@@ -471,6 +474,44 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager {
const { elements } = edgeless.service.selection;
const inc = shift ? 10 : 1;
+ const mindmapNodes = elements.filter(
+ el => el.group instanceof MindmapElementModel
+ );
+
+ if (mindmapNodes.length > 0) {
+ const node = mindmapNodes[0];
+ const mindmap = node.group as MindmapElementModel;
+ let targetNode: ElementModel | null = null;
+
+ switch (key) {
+ case 'ArrowUp':
+ case 'ArrowDown':
+ targetNode = mindmap.getSiblingNode(
+ node.id,
+ key === 'ArrowDown' ? 'next' : 'prev'
+ );
+ break;
+ case 'ArrowLeft':
+ targetNode = mindmap.getParentNode(node.id);
+ break;
+ case 'ArrowRight':
+ {
+ const children = mindmap.getChildNodes(node.id);
+
+ targetNode = children[0] ?? null;
+ }
+ break;
+ }
+
+ if (targetNode) {
+ edgeless.service.selection.set({
+ elements: [targetNode.id],
+ editing: false,
+ });
+ }
+
+ return;
+ }
elements.forEach(element => {
const bound = Bound.deserialize(element.xywh).clone();
diff --git a/packages/blocks/src/root-block/widgets/element-toolbar/change-mindmap-button.ts b/packages/blocks/src/root-block/widgets/element-toolbar/change-mindmap-button.ts
index 6fbd539326ee..1e6697428731 100644
--- a/packages/blocks/src/root-block/widgets/element-toolbar/change-mindmap-button.ts
+++ b/packages/blocks/src/root-block/widgets/element-toolbar/change-mindmap-button.ts
@@ -126,7 +126,7 @@ export class EdgelessChangeMindmapButton extends WithDisposable(LitElement) {
return html`
{
@@ -153,7 +153,7 @@ export class EdgelessChangeMindmapButton extends WithDisposable(LitElement) {
{
@@ -276,9 +276,9 @@ class EdgelessChangeMindmapLayoutPanel extends LitElement {
`;
static mindmapLayouts = [
- [LayoutType.LEFT, MindmapLeftLayoutIcon, 'Left layout'],
- [LayoutType.RIGHT, MindmapRightLayoutIcon, 'Right layout'],
- [LayoutType.BALANCE, MindmapBalanceLayoutIcon, 'Balance layout'],
+ [LayoutType.LEFT, MindmapLeftLayoutIcon, 'Left'],
+ [LayoutType.RIGHT, MindmapRightLayoutIcon, 'Right'],
+ [LayoutType.BALANCE, MindmapBalanceLayoutIcon, 'Radial'],
];
@property({ attribute: false })
diff --git a/packages/blocks/src/surface-block/element-model/mindmap.ts b/packages/blocks/src/surface-block/element-model/mindmap.ts
index b46f13e1a1cd..8772efd950f6 100644
--- a/packages/blocks/src/surface-block/element-model/mindmap.ts
+++ b/packages/blocks/src/surface-block/element-model/mindmap.ts
@@ -261,6 +261,18 @@ export class MindmapElementModel extends GroupLikeModel {
return node?.parent ? this.surface.getElementById(node.parent) : null;
}
+ /**
+ * Path is an array of indexes that represent the path from the root node to the target node.
+ * The first element of the array is always 0, which represents the root node.
+ * @param element
+ * @returns
+ *
+ * @example
+ * ```ts
+ * const path = mindmap.getPath('nodeId');
+ * // [0, 1, 2]
+ * ```
+ */
getPath(element: string | MindmapNode) {
let node = this._nodeMap.get(
typeof element === 'string' ? element : element.id
@@ -563,4 +575,38 @@ export class MindmapElementModel extends GroupLikeModel {
});
});
}
+
+ getSiblingNode(id: string, direction: 'prev' | 'next' = 'next') {
+ const node = this._nodeMap.get(id);
+
+ if (!node) {
+ return null;
+ }
+
+ const parent = this._nodeMap.get(node.detail.parent!);
+
+ if (!parent) {
+ return null;
+ }
+
+ const idx = parent.children.indexOf(node);
+ if (idx === -1) {
+ return null;
+ }
+
+ return (
+ parent?.children[direction === 'next' ? idx + 1 : idx - 1]?.element ??
+ null
+ );
+ }
+
+ getChildNodes(id: string) {
+ const node = this._nodeMap.get(id);
+
+ if (!node) {
+ return [];
+ }
+
+ return node.children.map(child => child.element);
+ }
}
diff --git a/packages/blocks/src/surface-block/utils/math-utils.ts b/packages/blocks/src/surface-block/utils/math-utils.ts
index e3a1db73657f..daf1c7408361 100644
--- a/packages/blocks/src/surface-block/utils/math-utils.ts
+++ b/packages/blocks/src/surface-block/utils/math-utils.ts
@@ -148,7 +148,7 @@ export function getBoundsFromPoints(points: IVec[], rotation = 0): TLBounds {
let maxX = -Infinity;
let maxY = -Infinity;
- if (points.length < 2) {
+ if (points.length < 1) {
minX = 0;
minY = 0;
maxX = 1;