feat(editor): create gfx mindmap package (#11100)

This commit is contained in:
Saul-Mirone
2025-03-24 03:14:22 +00:00
parent ed888d6507
commit 8e08b9000d
29 changed files with 292 additions and 135 deletions
+2
View File
@@ -34,6 +34,7 @@
"@blocksuite/affine-fragment-frame-panel": "workspace:*",
"@blocksuite/affine-fragment-outline": "workspace:*",
"@blocksuite/affine-gfx-connector": "workspace:*",
"@blocksuite/affine-gfx-mindmap": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
@@ -119,6 +120,7 @@
"./gfx/text": "./src/gfx/text.ts",
"./gfx/shape": "./src/gfx/shape.ts",
"./gfx/note": "./src/gfx/note.ts",
"./gfx/mindmap": "./src/gfx/mindmap.ts",
"./gfx/connector": "./src/gfx/connector.ts",
"./gfx/turbo-renderer": "./src/gfx/turbo-renderer.ts",
"./components/block-selection": "./src/components/block-selection.ts",
+1
View File
@@ -0,0 +1 @@
export * from '@blocksuite/affine-gfx-mindmap';
+1
View File
@@ -31,6 +31,7 @@
{ "path": "../fragments/fragment-frame-panel" },
{ "path": "../fragments/fragment-outline" },
{ "path": "../gfx/connector" },
{ "path": "../gfx/mindmap" },
{ "path": "../gfx/note" },
{ "path": "../gfx/shape" },
{ "path": "../gfx/text" },
@@ -1,6 +1,10 @@
import { EdgelessTextBlockModel } from '@blocksuite/affine-model';
import { type ToolbarModuleConfig } from '@blocksuite/affine-shared/services';
import {
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import { createTextActions } from '@blocksuite/affine-widget-edgeless-toolbar';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
export const edgelessTextToolbarConfig = {
// No need to adjust element bounds, which updates itself using ResizeObserver
@@ -8,3 +12,8 @@ export const edgelessTextToolbarConfig = {
when: ctx => ctx.getSurfaceModelsByType(EdgelessTextBlockModel).length > 0,
} as const satisfies ToolbarModuleConfig;
export const edgelessTextToolbarExtension = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:edgeless-text'),
config: edgelessTextToolbarConfig,
});
@@ -28,6 +28,7 @@
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-gfx-connector": "workspace:*",
"@blocksuite/affine-gfx-mindmap": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
@@ -1,16 +1,16 @@
import { edgelessTextToolbarConfig } from '@blocksuite/affine-block-edgeless-text';
import { edgelessTextToolbarExtension } from '@blocksuite/affine-block-edgeless-text';
import { frameToolbarExtension } from '@blocksuite/affine-block-frame';
import { connectorToolbarConfig } from '@blocksuite/affine-gfx-connector';
import { textToolbarConfig } from '@blocksuite/affine-gfx-text';
import { connectorToolbarExtension } from '@blocksuite/affine-gfx-connector';
import { mindmapToolbarExtension } from '@blocksuite/affine-gfx-mindmap';
import { shapeToolbarExtension } from '@blocksuite/affine-gfx-shape';
import { textToolbarExtension } from '@blocksuite/affine-gfx-text';
import { ToolbarModuleExtension } from '@blocksuite/affine-shared/services';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import type { ExtensionType } from '@blocksuite/store';
import { builtinBrushToolbarConfig } from './brush';
import { builtinGroupToolbarConfig } from './group';
import { builtinMindmapToolbarConfig } from './mindmap';
import { builtinLockedToolbarConfig, builtinMiscToolbarConfig } from './misc';
import { builtinShapeToolbarConfig } from './shape';
export const EdgelessElementToolbarExtension: ExtensionType[] = [
frameToolbarExtension,
@@ -25,30 +25,15 @@ export const EdgelessElementToolbarExtension: ExtensionType[] = [
config: builtinBrushToolbarConfig,
}),
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:connector'),
config: connectorToolbarConfig,
}),
connectorToolbarExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:mindmap'),
config: builtinMindmapToolbarConfig,
}),
mindmapToolbarExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:text'),
config: textToolbarConfig,
}),
textToolbarExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:edgeless-text'),
config: edgelessTextToolbarConfig,
}),
edgelessTextToolbarExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:shape'),
config: builtinShapeToolbarConfig,
}),
shapeToolbarExtension,
ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:*'),
@@ -1,73 +0,0 @@
import { shapeToolbarConfig } from '@blocksuite/affine-gfx-shape';
import {
MindmapElementModel,
ShapeElementModel,
} from '@blocksuite/affine-model';
import type { ToolbarActions } from '@blocksuite/affine-shared/services';
import {
createMindmapLayoutActionMenu,
createMindmapStyleActionMenu,
} from './mindmap';
const mindmapActions = [
{
id: 'a.mindmap-style',
when(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
return models.some(hasGrouped);
},
content(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
if (!models.length) return null;
let mindmaps = models
.map(model => model.group)
.filter(model => ctx.matchModel(model, MindmapElementModel));
if (!mindmaps.length) return null;
// Not displayed when there is both a normal shape and a mindmap shape.
if (models.length !== mindmaps.length) return null;
mindmaps = Array.from(new Set(mindmaps));
return createMindmapStyleActionMenu(ctx, mindmaps);
},
},
{
id: 'b.mindmap-layout',
when(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
return models.some(hasGrouped);
},
content(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
if (!models.length) return null;
let mindmaps = models
.map(model => model.group)
.filter(model => ctx.matchModel(model, MindmapElementModel));
if (!mindmaps.length) return null;
// Not displayed when there is both a normal shape and a mindmap shape.
if (models.length !== mindmaps.length) return null;
mindmaps = Array.from(new Set(mindmaps));
// It's a sub node.
if (models.length === 1 && mindmaps[0].tree.element !== models[0])
return null;
return createMindmapLayoutActionMenu(ctx, mindmaps);
},
},
] as const satisfies ToolbarActions;
export const builtinShapeToolbarConfig = {
...shapeToolbarConfig,
actions: [...mindmapActions, ...shapeToolbarConfig.actions],
};
function hasGrouped(model: ShapeElementModel) {
return model.group instanceof MindmapElementModel;
}
@@ -1,4 +1,5 @@
import { effects as gfxConnectorEffects } from '@blocksuite/affine-gfx-connector/effects';
import { effects as gfxMindmapEffects } from '@blocksuite/affine-gfx-mindmap/effects';
import { effects as gfxNoteEffects } from '@blocksuite/affine-gfx-note/effects';
import { effects as gfxShapeEffects } from '@blocksuite/affine-gfx-shape/effects';
import { effects as gfxCanvasTextEffects } from '@blocksuite/affine-gfx-text/effects';
@@ -32,9 +33,6 @@ import { EdgelessDefaultToolButton } from './edgeless/components/toolbar/default
import { EdgelessEraserToolButton } from './edgeless/components/toolbar/eraser/eraser-tool-button.js';
import { EdgelessLassoToolButton } from './edgeless/components/toolbar/lasso/lasso-tool-button.js';
import { EdgelessLinkToolButton } from './edgeless/components/toolbar/link/link-tool-button.js';
import { MindMapPlaceholder } from './edgeless/components/toolbar/mindmap/mindmap-importing-placeholder.js';
import { EdgelessMindmapMenu } from './edgeless/components/toolbar/mindmap/mindmap-menu.js';
import { EdgelessMindmapToolButton } from './edgeless/components/toolbar/mindmap/mindmap-tool-button.js';
import { OverlayScrollbar } from './edgeless/components/toolbar/template/overlay-scrollbar.js';
import { AffineTemplateLoading } from './edgeless/components/toolbar/template/template-loading.js';
import { EdgelessTemplatePanel } from './edgeless/components/toolbar/template/template-panel.js';
@@ -108,6 +106,7 @@ function registerGfxEffects() {
gfxShapeEffects();
gfxNoteEffects();
gfxConnectorEffects();
gfxMindmapEffects();
}
function registerWidgets() {
@@ -141,15 +140,10 @@ function registerEdgelessToolbarComponents() {
);
customElements.define('edgeless-link-tool-button', EdgelessLinkToolButton);
customElements.define('edgeless-lasso-tool-button', EdgelessLassoToolButton);
customElements.define(
'edgeless-mindmap-tool-button',
EdgelessMindmapToolButton
);
customElements.define('edgeless-template-button', EdgelessTemplateButton);
// Menus
customElements.define('edgeless-brush-menu', EdgelessBrushMenu);
customElements.define('edgeless-mindmap-menu', EdgelessMindmapMenu);
customElements.define('edgeless-slide-menu', EdgelessSlideMenu);
// Toolbar components
@@ -214,9 +208,6 @@ function registerMiscComponents() {
EDGELESS_SELECTED_RECT_WIDGET,
EdgelessSelectedRectWidget
);
// Mindmap components
customElements.define('mindmap-import-placeholder', MindMapPlaceholder);
}
declare global {
@@ -243,9 +234,6 @@ declare global {
'edgeless-eraser-tool-button': EdgelessEraserToolButton;
'edgeless-lasso-tool-button': EdgelessLassoToolButton;
'edgeless-link-tool-button': EdgelessLinkToolButton;
'mindmap-import-placeholder': MindMapPlaceholder;
'edgeless-mindmap-menu': EdgelessMindmapMenu;
'edgeless-mindmap-tool-button': EdgelessMindmapToolButton;
'overlay-scrollbar': OverlayScrollbar;
'affine-template-loading': AffineTemplateLoading;
'edgeless-templates-panel': EdgelessTemplatePanel;
@@ -25,6 +25,7 @@
{ "path": "../../components" },
{ "path": "../../fragments/fragment-doc-title" },
{ "path": "../../gfx/connector" },
{ "path": "../../gfx/mindmap" },
{ "path": "../../gfx/note" },
{ "path": "../../gfx/shape" },
{ "path": "../../gfx/text" },
@@ -21,10 +21,11 @@ import {
resolveColor,
StrokeStyle,
} from '@blocksuite/affine-model';
import type {
ToolbarContext,
ToolbarGenericAction,
ToolbarModuleConfig,
import {
type ToolbarContext,
type ToolbarGenericAction,
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import {
getMostCommonResolvedValue,
@@ -37,6 +38,7 @@ import {
LINE_STYLE_LIST,
renderMenu,
} from '@blocksuite/affine-widget-edgeless-toolbar';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx';
import {
AddTextIcon,
@@ -417,3 +419,8 @@ function updateModelsWith<
.updateElement(model.id, { [field]: value });
}
}
export const connectorToolbarExtension = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:connector'),
config: connectorToolbarConfig,
});
@@ -0,0 +1,50 @@
{
"name": "@blocksuite/affine-gfx-mindmap",
"description": "Gfx mindmap for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-attachment": "workspace:*",
"@blocksuite/affine-block-edgeless-text": "workspace:*",
"@blocksuite/affine-block-image": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/icons": "^2.2.6",
"@blocksuite/store": "workspace:*",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.12",
"@types/lodash-es": "^4.17.12",
"lit": "^3.2.0",
"lodash-es": "^4.17.21",
"minimatch": "^10.0.1",
"rxjs": "^7.8.1",
"simple-xml-to-json": "^1.2.2",
"yjs": "^13.6.21",
"zod": "^3.23.8"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.20.0"
}
@@ -0,0 +1,20 @@
import { MindMapPlaceholder } from './toolbar/mindmap-importing-placeholder';
import { EdgelessMindmapMenu } from './toolbar/mindmap-menu';
import { EdgelessMindmapToolButton } from './toolbar/mindmap-tool-button';
export function effects() {
customElements.define(
'edgeless-mindmap-tool-button',
EdgelessMindmapToolButton
);
customElements.define('edgeless-mindmap-menu', EdgelessMindmapMenu);
customElements.define('mindmap-import-placeholder', MindMapPlaceholder);
}
declare global {
interface HTMLElementTagNameMap {
'edgeless-mindmap-tool-button': EdgelessMindmapToolButton;
'edgeless-mindmap-menu': EdgelessMindmapMenu;
'mindmap-import-placeholder': MindMapPlaceholder;
}
}
@@ -0,0 +1 @@
export * from './toolbar/config';
@@ -9,15 +9,17 @@ import {
MindmapElementModel,
MindmapStyle,
} from '@blocksuite/affine-model';
import type {
ToolbarContext,
ToolbarModuleConfig,
import {
type ToolbarContext,
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import { getMostCommonValue } from '@blocksuite/affine-shared/utils';
import {
type MenuItem,
renderMenu,
} from '@blocksuite/affine-widget-edgeless-toolbar';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { RadiantIcon, RightLayoutIcon, StyleIcon } from '@blocksuite/icons/lit';
const MINDMAP_STYLE_LIST = [
@@ -102,7 +104,7 @@ export const createMindmapLayoutActionMenu = (
});
};
export const builtinMindmapToolbarConfig = {
export const mindmapToolbarConfig = {
actions: [
{
id: 'a.style',
@@ -126,3 +128,8 @@ export const builtinMindmapToolbarConfig = {
when: ctx => ctx.getSurfaceModelsByType(MindmapElementModel).length > 0,
} as const satisfies ToolbarModuleConfig;
export const mindmapToolbarExtension = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:mindmap'),
config: mindmapToolbarConfig,
});
@@ -21,7 +21,6 @@ import { css, html, LitElement, nothing, type TemplateResult } from 'lit';
import { property } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { EdgelessRootBlockComponent } from '../../../index.js';
import { getMindMaps, type ToolbarMindmapItem } from './assets.js';
import { mediaRender, textRender } from './basket-elements.js';
import { importMindMapIcon, mindmapMenuMediaIcon, textIcon } from './icons.js';
@@ -124,12 +123,9 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
ToolbarMindmapItem | TextItem | ImportItem | MediaItem
>;
// @ts-expect-error FIXME: resolve after gfx tool refactor
override type = 'empty' as const;
private get _rootBlock(): EdgelessRootBlockComponent {
return this.std.view.getBlock(this.model.id) as EdgelessRootBlockComponent;
}
get mindMaps() {
return getMindMaps(this.theme);
}
@@ -164,7 +160,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
}}
@click=${() => {
this.draggableController.cancel();
const viewportBound = this._rootBlock.service.viewport.viewportBounds;
const viewportBound = this.gfx.viewport.viewportBounds;
viewportBound.x += viewportBound.w / 2;
viewportBound.y += viewportBound.h / 2;
@@ -183,16 +179,13 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
}
private _onImportMindMap(bound: Bound) {
const edgelessBlock = this._rootBlock;
if (!edgelessBlock) return;
const placeholder = new MindMapPlaceholder();
placeholder.style.position = 'absolute';
placeholder.style.left = `${bound.x}px`;
placeholder.style.top = `${bound.y}px`;
edgelessBlock.gfxViewportElm.append(placeholder);
this.gfx.viewport.element?.append(placeholder);
this.onImportMindMap?.(bound)
.then(() => {
@@ -230,6 +223,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
this.onActiveStyleChange?.(element.data.style);
}
// a workaround to active mindmap, so that menu cannot be closed by `Escape`
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'empty' });
},
onDrop: (element, bound) => {
@@ -240,6 +234,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
if (!id) return;
if (element.data.type === 'mindmap') {
this.onActiveStyleChange?.(element.data.style);
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({
elements: [id],
@@ -249,6 +244,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin(
element.data.type === 'text' ||
element.data.type === 'media'
) {
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
}
})
@@ -150,6 +150,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
override enableActiveBackground = true;
// @ts-expect-error FIXME: resolve after gfx tool refactor
override type: GfxToolsFullOptionValue['type'][] = ['empty', 'text'];
get draggableTools(): DraggableTool[] {
@@ -191,6 +192,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
private _toggleMenu() {
if (this.tryDisposePopper()) return;
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
const menu = this.createPopper('edgeless-mindmap-menu', this);
@@ -211,6 +213,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
const element = this.crud.getElementById(id) as MindmapElementModel;
this.tryDisposePopper();
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({
elements: [element.tree.id],
@@ -271,12 +274,14 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
if (!id) return;
this.readyToDrop = false;
if (el.data.name === 'mindmap') {
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
this.gfx.selection.set({
elements: [id],
editing: false,
});
} else if (el.data.name === 'text') {
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'default' });
}
})
@@ -309,6 +314,7 @@ export class EdgelessMindmapToolButton extends EdgelessToolbarToolMixin(
});
return;
}
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.setEdgelessTool({ type: 'empty' });
const icon = this.mindmapElement;
const { x, y } = gfx.tool.lastMousePos$.peek();
@@ -0,0 +1,24 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
},
"include": ["./src"],
"references": [
{ "path": "../../blocks/block-attachment" },
{ "path": "../../blocks/block-edgeless-text" },
{ "path": "../../blocks/block-image" },
{ "path": "../../blocks/block-surface" },
{ "path": "../../components" },
{ "path": "../text" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },
{ "path": "../../widgets/widget-edgeless-toolbar" },
{ "path": "../../../framework/block-std" },
{ "path": "../../../framework/global" },
{ "path": "../../../framework/store" }
]
}
+1
View File
@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-gfx-mindmap": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
@@ -7,6 +7,10 @@ import {
type PickColorEvent,
} from '@blocksuite/affine-components/color-picker';
import type { LineDetailType } from '@blocksuite/affine-components/edgeless-line-styles-panel';
import {
createMindmapLayoutActionMenu,
createMindmapStyleActionMenu,
} from '@blocksuite/affine-gfx-mindmap';
import {
type Color,
DefaultTheme,
@@ -24,9 +28,10 @@ import {
ShapeType,
StrokeStyle,
} from '@blocksuite/affine-model';
import type {
ToolbarGenericAction,
ToolbarModuleConfig,
import {
type ToolbarGenericAction,
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import { getMostCommonValue } from '@blocksuite/affine-shared/utils';
import {
@@ -35,6 +40,7 @@ import {
LINE_STYLE_LIST,
renderMenu,
} from '@blocksuite/affine-widget-edgeless-toolbar';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx';
import { AddTextIcon, ShapeIcon } from '@blocksuite/icons/lit';
import { html } from 'lit';
@@ -46,6 +52,56 @@ import { ShapeComponentConfig } from './shape-menu-config';
export const shapeToolbarConfig = {
actions: [
{
id: 'a.mindmap-style',
when(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
return models.some(hasGrouped);
},
content(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
if (!models.length) return null;
let mindmaps = models
.map(model => model.group)
.filter(model => ctx.matchModel(model, MindmapElementModel));
if (!mindmaps.length) return null;
// Not displayed when there is both a normal shape and a mindmap shape.
if (models.length !== mindmaps.length) return null;
mindmaps = Array.from(new Set(mindmaps));
return createMindmapStyleActionMenu(ctx, mindmaps);
},
},
{
id: 'b.mindmap-layout',
when(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
return models.some(hasGrouped);
},
content(ctx) {
const models = ctx.getSurfaceModelsByType(ShapeElementModel);
if (!models.length) return null;
let mindmaps = models
.map(model => model.group)
.filter(model => ctx.matchModel(model, MindmapElementModel));
if (!mindmaps.length) return null;
// Not displayed when there is both a normal shape and a mindmap shape.
if (models.length !== mindmaps.length) return null;
mindmaps = Array.from(new Set(mindmaps));
// It's a sub node.
if (models.length === 1 && mindmaps[0].tree.element !== models[0])
return null;
return createMindmapLayoutActionMenu(ctx, mindmaps);
},
},
{
id: 'c.switch-type',
when(ctx) {
@@ -326,3 +382,8 @@ function getTextColor(fillColor: Color, isNotTransparent = false) {
function hasGrouped(model: ShapeElementModel) {
return model.group instanceof MindmapElementModel;
}
export const shapeToolbarExtension = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:shape'),
config: shapeToolbarConfig,
});
@@ -9,6 +9,7 @@
"references": [
{ "path": "../../blocks/block-surface" },
{ "path": "../../components" },
{ "path": "../mindmap" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },
@@ -3,8 +3,12 @@ import {
TextUtils,
} from '@blocksuite/affine-block-surface';
import { TextElementModel } from '@blocksuite/affine-model';
import { type ToolbarModuleConfig } from '@blocksuite/affine-shared/services';
import {
type ToolbarModuleConfig,
ToolbarModuleExtension,
} from '@blocksuite/affine-shared/services';
import { createTextActions } from '@blocksuite/affine-widget-edgeless-toolbar';
import { BlockFlavourIdentifier } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx';
export const textToolbarConfig = {
@@ -46,3 +50,8 @@ export const textToolbarConfig = {
when: ctx => ctx.getSurfaceModelsByType(TextElementModel).length > 0,
} as const satisfies ToolbarModuleConfig;
export const textToolbarExtension = ToolbarModuleExtension({
id: BlockFlavourIdentifier('affine:surface:text'),
config: textToolbarConfig,
});
+23
View File
@@ -29,6 +29,7 @@ export const PackageList = [
'blocksuite/affine/fragments/fragment-frame-panel',
'blocksuite/affine/fragments/fragment-outline',
'blocksuite/affine/gfx/connector',
'blocksuite/affine/gfx/mindmap',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
@@ -310,6 +311,7 @@ export const PackageList = [
'blocksuite/affine/components',
'blocksuite/affine/fragments/fragment-doc-title',
'blocksuite/affine/gfx/connector',
'blocksuite/affine/gfx/mindmap',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
@@ -460,6 +462,25 @@ export const PackageList = [
'blocksuite/framework/store',
],
},
{
location: 'blocksuite/affine/gfx/mindmap',
name: '@blocksuite/affine-gfx-mindmap',
workspaceDependencies: [
'blocksuite/affine/blocks/block-attachment',
'blocksuite/affine/blocks/block-edgeless-text',
'blocksuite/affine/blocks/block-image',
'blocksuite/affine/blocks/block-surface',
'blocksuite/affine/components',
'blocksuite/affine/gfx/text',
'blocksuite/affine/model',
'blocksuite/affine/rich-text',
'blocksuite/affine/shared',
'blocksuite/affine/widgets/widget-edgeless-toolbar',
'blocksuite/framework/block-std',
'blocksuite/framework/global',
'blocksuite/framework/store',
],
},
{
location: 'blocksuite/affine/gfx/note',
name: '@blocksuite/affine-gfx-note',
@@ -484,6 +505,7 @@ export const PackageList = [
workspaceDependencies: [
'blocksuite/affine/blocks/block-surface',
'blocksuite/affine/components',
'blocksuite/affine/gfx/mindmap',
'blocksuite/affine/model',
'blocksuite/affine/rich-text',
'blocksuite/affine/shared',
@@ -1093,6 +1115,7 @@ export type PackageName =
| '@blocksuite/affine-fragment-frame-panel'
| '@blocksuite/affine-fragment-outline'
| '@blocksuite/affine-gfx-connector'
| '@blocksuite/affine-gfx-mindmap'
| '@blocksuite/affine-gfx-note'
| '@blocksuite/affine-gfx-shape'
| '@blocksuite/affine-gfx-text'
+1
View File
@@ -76,6 +76,7 @@
{ "path": "./blocksuite/affine/fragments/fragment-frame-panel" },
{ "path": "./blocksuite/affine/fragments/fragment-outline" },
{ "path": "./blocksuite/affine/gfx/connector" },
{ "path": "./blocksuite/affine/gfx/mindmap" },
{ "path": "./blocksuite/affine/gfx/note" },
{ "path": "./blocksuite/affine/gfx/shape" },
{ "path": "./blocksuite/affine/gfx/text" },
+35
View File
@@ -2734,6 +2734,7 @@ __metadata:
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-fragment-doc-title": "workspace:*"
"@blocksuite/affine-gfx-connector": "workspace:*"
"@blocksuite/affine-gfx-mindmap": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"
@@ -2997,6 +2998,38 @@ __metadata:
languageName: unknown
linkType: soft
"@blocksuite/affine-gfx-mindmap@workspace:*, @blocksuite/affine-gfx-mindmap@workspace:blocksuite/affine/gfx/mindmap":
version: 0.0.0-use.local
resolution: "@blocksuite/affine-gfx-mindmap@workspace:blocksuite/affine/gfx/mindmap"
dependencies:
"@blocksuite/affine-block-attachment": "workspace:*"
"@blocksuite/affine-block-edgeless-text": "workspace:*"
"@blocksuite/affine-block-image": "workspace:*"
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"
"@blocksuite/affine-model": "workspace:*"
"@blocksuite/affine-rich-text": "workspace:*"
"@blocksuite/affine-shared": "workspace:*"
"@blocksuite/affine-widget-edgeless-toolbar": "workspace:*"
"@blocksuite/block-std": "workspace:*"
"@blocksuite/global": "workspace:*"
"@blocksuite/icons": "npm:^2.2.6"
"@blocksuite/store": "workspace:*"
"@lit/context": "npm:^1.1.2"
"@preact/signals-core": "npm:^1.8.0"
"@toeverything/theme": "npm:^1.1.12"
"@types/lodash-es": "npm:^4.17.12"
lit: "npm:^3.2.0"
lodash-es: "npm:^4.17.21"
minimatch: "npm:^10.0.1"
rxjs: "npm:^7.8.1"
simple-xml-to-json: "npm:^1.2.2"
yjs: "npm:^13.6.21"
zod: "npm:^3.23.8"
languageName: unknown
linkType: soft
"@blocksuite/affine-gfx-note@workspace:*, @blocksuite/affine-gfx-note@workspace:blocksuite/affine/gfx/note":
version: 0.0.0-use.local
resolution: "@blocksuite/affine-gfx-note@workspace:blocksuite/affine/gfx/note"
@@ -3033,6 +3066,7 @@ __metadata:
dependencies:
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-gfx-mindmap": "workspace:*"
"@blocksuite/affine-model": "workspace:*"
"@blocksuite/affine-rich-text": "workspace:*"
"@blocksuite/affine-shared": "workspace:*"
@@ -3540,6 +3574,7 @@ __metadata:
"@blocksuite/affine-fragment-frame-panel": "workspace:*"
"@blocksuite/affine-fragment-outline": "workspace:*"
"@blocksuite/affine-gfx-connector": "workspace:*"
"@blocksuite/affine-gfx-mindmap": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"