feat(editor): gfx note package (#11088)

This commit is contained in:
Saul-Mirone
2025-03-22 14:39:04 +00:00
parent 464e9e44eb
commit e3735f40b8
28 changed files with 205 additions and 53 deletions
+2
View File
@@ -33,6 +33,7 @@
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-fragment-frame-panel": "workspace:*",
"@blocksuite/affine-fragment-outline": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*",
@@ -116,6 +117,7 @@
"./fragments/outline": "./src/fragments/outline.ts",
"./gfx/text": "./src/gfx/text.ts",
"./gfx/shape": "./src/gfx/shape/index.ts",
"./gfx/note": "./src/gfx/note/index.ts",
"./gfx/turbo-renderer": "./src/gfx/turbo-renderer.ts",
"./components/block-selection": "./src/components/block-selection.ts",
"./components/block-zero-width": "./src/components/block-zero-width.ts",
+1
View File
@@ -0,0 +1 @@
export * from '@blocksuite/affine-gfx-note';
+1
View File
@@ -30,6 +30,7 @@
{ "path": "../fragments/fragment-doc-title" },
{ "path": "../fragments/fragment-frame-panel" },
{ "path": "../fragments/fragment-outline" },
{ "path": "../gfx/note" },
{ "path": "../gfx/shape" },
{ "path": "../gfx/text" },
{ "path": "../gfx/turbo-renderer" },
@@ -27,6 +27,7 @@
"@blocksuite/affine-block-table": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-fragment-doc-title": "workspace:*",
"@blocksuite/affine-gfx-note": "workspace:*",
"@blocksuite/affine-gfx-shape": "workspace:*",
"@blocksuite/affine-gfx-text": "workspace:*",
"@blocksuite/affine-inline-latex": "workspace:*",
@@ -1,5 +1,9 @@
import type { NoteBlockComponent } from '@blocksuite/affine-block-note';
import { isNoteBlock } from '@blocksuite/affine-block-surface';
import {
EdgelessLegacySlotIdentifier,
getSurfaceComponent,
isNoteBlock,
} from '@blocksuite/affine-block-surface';
import {
DEFAULT_NOTE_HEIGHT,
type NoteBlockModel,
@@ -18,7 +22,7 @@ import { state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { styleMap } from 'lit/directives/style-map.js';
import type { EdgelessRootBlockComponent } from '../../edgeless-root-block';
import type { EdgelessSelectedRectWidget } from '../rects/edgeless-selected-rect';
const DIVIDING_LINE_OFFSET = 4;
const NEW_NOTE_GAP = 40;
@@ -96,10 +100,7 @@ const styles = css`
export const NOTE_SLICER_WIDGET = 'note-slicer';
export class NoteSlicer extends WidgetComponent<
RootBlockModel,
EdgelessRootBlockComponent
> {
export class NoteSlicer extends WidgetComponent<RootBlockModel> {
static override styles = styles;
private _divingLinePositions: Point[] = [];
@@ -143,7 +144,10 @@ export class NoteSlicer extends WidgetComponent<
}
get selectedRectEle() {
return this.block?.selectedRectWidget;
return this.host.view.getWidget(
'edgeless-selected-rect',
this.host.id
) as EdgelessSelectedRectWidget | null;
}
private _sliceNote() {
@@ -262,22 +266,20 @@ export class NoteSlicer extends WidgetComponent<
override connectedCallback(): void {
super.connectedCallback();
const { disposables, std, block, gfx } = this;
const { disposables, std, gfx } = this;
this._updateDivingLineAndBlockIds();
if (!block) {
return;
}
const slots = std.get(EdgelessLegacySlotIdentifier);
disposables.add(
block.slots.elementResizeStart.subscribe(() => {
slots.elementResizeStart.subscribe(() => {
this._isResizing = true;
})
);
disposables.add(
block.slots.elementResizeEnd.subscribe(() => {
slots.elementResizeEnd.subscribe(() => {
this._isResizing = false;
})
);
@@ -311,7 +313,7 @@ export class NoteSlicer extends WidgetComponent<
);
disposables.add(
block.slots.toggleNoteSlicer.subscribe(() => {
slots.toggleNoteSlicer.subscribe(() => {
this._enableNoteSlicer = !this._enableNoteSlicer;
if (this.selectedRectEle && this._enableNoteSlicer) {
@@ -320,9 +322,9 @@ export class NoteSlicer extends WidgetComponent<
})
);
const { surface } = block;
requestAnimationFrame(() => {
if (surface.isConnected && std.event) {
const surface = getSurfaceComponent(std);
if (surface?.isConnected && std.event) {
disposables.add(
std.event.add('click', ctx => {
const event = ctx.get('pointerState');
@@ -1,4 +1,5 @@
import { frameQuickTool } from '@blocksuite/affine-block-frame';
import { noteSeniorTool } from '@blocksuite/affine-gfx-note';
import { shapeSeniorTool } from '@blocksuite/affine-gfx-shape';
import {
QuickToolExtension,
@@ -35,15 +36,6 @@ const linkQuickTool = QuickToolExtension('link', ({ block, gfx }) => {
};
});
const noteSeniorTool = SeniorToolExtension('note', ({ block }) => {
return {
name: 'Note',
content: html`<edgeless-note-senior-button
.edgeless=${block}
></edgeless-note-senior-button>`,
};
});
const penSeniorTool = SeniorToolExtension('pen', ({ block }) => {
return {
name: 'Pen',
@@ -4,6 +4,7 @@ import {
PresentTool,
} from '@blocksuite/affine-block-frame';
import { ConnectionOverlay } from '@blocksuite/affine-block-surface';
import { NoteTool } from '@blocksuite/affine-gfx-note';
import { ShapeTool } from '@blocksuite/affine-gfx-shape';
import { TextTool } from '@blocksuite/affine-gfx-text';
import {
@@ -24,7 +25,6 @@ import { DefaultTool } from './gfx-tool/default-tool.js';
import { EmptyTool } from './gfx-tool/empty-tool.js';
import { EraserTool } from './gfx-tool/eraser-tool.js';
import { LassoTool } from './gfx-tool/lasso-tool.js';
import { NoteTool } from './gfx-tool/note-tool.js';
import { PanTool } from './gfx-tool/pan-tool.js';
import { TemplateTool } from './gfx-tool/template-tool.js';
import { EditPropsMiddlewareBuilder } from './middlewares/base.js';
@@ -4,6 +4,5 @@ export { DefaultTool } from './default-tool.js';
export { EmptyTool } from './empty-tool.js';
export { EraserTool } from './eraser-tool.js';
export { LassoTool, type LassoToolOption } from './lasso-tool.js';
export { NoteTool, type NoteToolOption } from './note-tool.js';
export { PanTool, type PanToolOption } from './pan-tool.js';
export { TemplateTool } from './template-tool.js';
@@ -1,13 +1,3 @@
export const NOTE_OVERLAY_OFFSET_X = 6;
export const NOTE_OVERLAY_OFFSET_Y = 6;
export const NOTE_OVERLAY_WIDTH = 100;
export const NOTE_OVERLAY_HEIGHT = 50;
export const NOTE_OVERLAY_CORNER_RADIUS = 6;
export const NOTE_OVERLAY_STOKE_COLOR = '--affine-border-color';
export const NOTE_OVERLAY_TEXT_COLOR = '--affine-icon-color';
export const NOTE_OVERLAY_LIGHT_BACKGROUND_COLOR = 'rgba(252, 252, 253, 1)';
export const NOTE_OVERLAY_DARK_BACKGROUND_COLOR = 'rgb(32, 32, 32)';
export const DEFAULT_NOTE_CHILD_FLAVOUR = 'affine:paragraph';
export const DEFAULT_NOTE_CHILD_TYPE = 'text';
export const DEFAULT_NOTE_TIP = 'Text';
@@ -1,3 +1,4 @@
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';
import { effects as widgetEdgelessToolbarEffects } from '@blocksuite/affine-widget-edgeless-toolbar/effects';
@@ -41,9 +42,6 @@ import { EdgelessLinkToolButton } from './edgeless/components/toolbar/link/link-
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 { EdgelessNoteMenu } from './edgeless/components/toolbar/note/note-menu.js';
import { EdgelessNoteSeniorButton } from './edgeless/components/toolbar/note/note-senior-button.js';
import { EdgelessNoteToolButton } from './edgeless/components/toolbar/note/note-tool-button.js';
import { EdgelessFrameOrderButton } from './edgeless/components/toolbar/present/frame-order-button.js';
import { EdgelessFrameOrderMenu } from './edgeless/components/toolbar/present/frame-order-menu.js';
import { EdgelessNavigatorSettingButton } from './edgeless/components/toolbar/present/navigator-setting-button.js';
@@ -120,6 +118,7 @@ function registerRootComponents() {
function registerGfxEffects() {
gfxCanvasTextEffects();
gfxShapeEffects();
gfxNoteEffects();
}
function registerWidgets() {
@@ -161,14 +160,12 @@ function registerEdgelessToolbarComponents() {
'edgeless-mindmap-tool-button',
EdgelessMindmapToolButton
);
customElements.define('edgeless-note-tool-button', EdgelessNoteToolButton);
customElements.define('edgeless-template-button', EdgelessTemplateButton);
// Menus
customElements.define('edgeless-brush-menu', EdgelessBrushMenu);
customElements.define('edgeless-connector-menu', EdgelessConnectorMenu);
customElements.define('edgeless-mindmap-menu', EdgelessMindmapMenu);
customElements.define('edgeless-note-menu', EdgelessNoteMenu);
customElements.define('edgeless-slide-menu', EdgelessSlideMenu);
// Toolbar components
@@ -185,10 +182,6 @@ function registerEdgelessToolbarComponents() {
EdgelessNavigatorSettingButton
);
customElements.define('edgeless-present-button', EdgelessPresentButton);
customElements.define(
'edgeless-note-senior-button',
EdgelessNoteSeniorButton
);
}
function registerEdgelessPanelComponents() {
@@ -302,8 +295,6 @@ declare global {
'mindmap-import-placeholder': MindMapPlaceholder;
'edgeless-mindmap-menu': EdgelessMindmapMenu;
'edgeless-mindmap-tool-button': EdgelessMindmapToolButton;
'edgeless-note-menu': EdgelessNoteMenu;
'edgeless-note-tool-button': EdgelessNoteToolButton;
'edgeless-frame-order-menu': EdgelessFrameOrderMenu;
'edgeless-navigator-setting-button': EdgelessNavigatorSettingButton;
'edgeless-present-button': EdgelessPresentButton;
@@ -24,6 +24,7 @@
{ "path": "../block-table" },
{ "path": "../../components" },
{ "path": "../../fragments/fragment-doc-title" },
{ "path": "../../gfx/note" },
{ "path": "../../gfx/shape" },
{ "path": "../../gfx/text" },
{ "path": "../../inlines/latex" },
+48
View File
@@ -0,0 +1,48 @@
{
"name": "@blocksuite/affine-gfx-note",
"description": "Gfx note for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-attachment": "workspace:*",
"@blocksuite/affine-block-bookmark": "workspace:*",
"@blocksuite/affine-block-image": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "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",
"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"
}
+20
View File
@@ -0,0 +1,20 @@
import { EdgelessNoteMenu } from './toolbar/note-menu';
import { EdgelessNoteSeniorButton } from './toolbar/note-senior-button';
import { EdgelessNoteToolButton } from './toolbar/note-tool-button';
export function effects() {
customElements.define('edgeless-note-tool-button', EdgelessNoteToolButton);
customElements.define('edgeless-note-menu', EdgelessNoteMenu);
customElements.define(
'edgeless-note-senior-button',
EdgelessNoteSeniorButton
);
}
declare global {
interface HTMLElementTagNameMap {
'edgeless-note-tool-button': EdgelessNoteToolButton;
'edgeless-note-menu': EdgelessNoteMenu;
'edgeless-note-senior-button': EdgelessNoteSeniorButton;
}
}
+3
View File
@@ -0,0 +1,3 @@
export * from './note-tool';
export * from './overlay';
export * from './toolbar/senior-tool';
@@ -15,7 +15,7 @@ import { BaseTool } from '@blocksuite/block-std/gfx';
import { Point } from '@blocksuite/global/gfx';
import { effect } from '@preact/signals-core';
import { DraggingNoteOverlay, NoteOverlay } from '../utils/tool-overlay.js';
import { DraggingNoteOverlay, NoteOverlay } from './overlay';
export type NoteToolOption = {
childFlavour: NoteChildrenFlavour;
@@ -0,0 +1,9 @@
export const NOTE_OVERLAY_OFFSET_X = 6;
export const NOTE_OVERLAY_OFFSET_Y = 6;
export const NOTE_OVERLAY_WIDTH = 100;
export const NOTE_OVERLAY_HEIGHT = 50;
export const NOTE_OVERLAY_CORNER_RADIUS = 6;
export const NOTE_OVERLAY_STOKE_COLOR = '--affine-border-color';
export const NOTE_OVERLAY_TEXT_COLOR = '--affine-icon-color';
export const NOTE_OVERLAY_LIGHT_BACKGROUND_COLOR = 'rgba(252, 252, 253, 1)';
export const NOTE_OVERLAY_DARK_BACKGROUND_COLOR = 'rgb(32, 32, 32)';
@@ -0,0 +1,2 @@
export * from './consts';
export * from './overlay';
@@ -17,7 +17,7 @@ import {
NOTE_OVERLAY_STOKE_COLOR,
NOTE_OVERLAY_TEXT_COLOR,
NOTE_OVERLAY_WIDTH,
} from '../utils/consts.js';
} from './consts.js';
export class NoteOverlay extends ToolOverlay {
backgroundColor = 'transparent';
@@ -16,7 +16,7 @@ import { css, html, LitElement } from 'lit';
import { property, state } from 'lit/decorators.js';
import { repeat } from 'lit/directives/repeat.js';
import type { NoteToolOption } from '../../../gfx-tool/note-tool.js';
import type { NoteToolOption } from '../note-tool.js';
import { NOTE_MENU_ITEMS } from './note-menu-config.js';
export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
@@ -60,6 +60,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
maxWidth: MAX_IMAGE_WIDTH,
});
this._imageLoading = false;
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.gfx.tool.setTool('default');
this.gfx.selection.set({ elements: ids });
}
@@ -140,6 +141,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
const file = await openFileOrFiles();
if (!file) return;
await addAttachments(this.edgeless.std, [file]);
// @ts-expect-error FIXME: resolve after gfx tool refactor
this.gfx.tool.setTool('default');
this.edgeless.std
.getOptional(TelemetryProvider)
@@ -13,7 +13,7 @@ import { computed } from '@preact/signals-core';
import { css, html, LitElement } from 'lit';
import { state } from 'lit/decorators.js';
import type { NoteToolOption } from '../../../gfx-tool/note-tool.js';
import type { NoteToolOption } from '../note-tool.js';
import { toShapeNotToAdapt } from './icon.js';
export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
@@ -9,7 +9,7 @@ import { effect } from '@preact/signals-core';
import { css, html, LitElement } from 'lit';
import { state } from 'lit/decorators.js';
import type { NoteToolOption } from '../../../gfx-tool/note-tool.js';
import type { NoteToolOption } from '../note-tool.js';
import type { EdgelessNoteMenu } from './note-menu.js';
export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
@@ -0,0 +1,11 @@
import { SeniorToolExtension } from '@blocksuite/affine-widget-edgeless-toolbar';
import { html } from 'lit';
export const noteSeniorTool = SeniorToolExtension('note', ({ block }) => {
return {
name: 'Note',
content: html`<edgeless-note-senior-button
.edgeless=${block}
></edgeless-note-senior-button>`,
};
});
+23
View File
@@ -0,0 +1,23 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo"
},
"include": ["./src"],
"references": [
{ "path": "../../blocks/block-attachment" },
{ "path": "../../blocks/block-bookmark" },
{ "path": "../../blocks/block-image" },
{ "path": "../../blocks/block-surface" },
{ "path": "../../components" },
{ "path": "../../model" },
{ "path": "../../rich-text" },
{ "path": "../../shared" },
{ "path": "../../widgets/widget-edgeless-toolbar" },
{ "path": "../../../framework/block-std" },
{ "path": "../../../framework/global" },
{ "path": "../../../framework/store" }
]
}
+21
View File
@@ -28,6 +28,7 @@ export const PackageList = [
'blocksuite/affine/fragments/fragment-doc-title',
'blocksuite/affine/fragments/fragment-frame-panel',
'blocksuite/affine/fragments/fragment-outline',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
'blocksuite/affine/gfx/turbo-renderer',
@@ -307,6 +308,7 @@ export const PackageList = [
'blocksuite/affine/blocks/block-table',
'blocksuite/affine/components',
'blocksuite/affine/fragments/fragment-doc-title',
'blocksuite/affine/gfx/note',
'blocksuite/affine/gfx/shape',
'blocksuite/affine/gfx/text',
'blocksuite/affine/inlines/latex',
@@ -441,6 +443,24 @@ export const PackageList = [
'blocksuite/framework/store',
],
},
{
location: 'blocksuite/affine/gfx/note',
name: '@blocksuite/affine-gfx-note',
workspaceDependencies: [
'blocksuite/affine/blocks/block-attachment',
'blocksuite/affine/blocks/block-bookmark',
'blocksuite/affine/blocks/block-image',
'blocksuite/affine/blocks/block-surface',
'blocksuite/affine/components',
'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/shape',
name: '@blocksuite/affine-gfx-shape',
@@ -1055,6 +1075,7 @@ export type PackageName =
| '@blocksuite/affine-fragment-doc-title'
| '@blocksuite/affine-fragment-frame-panel'
| '@blocksuite/affine-fragment-outline'
| '@blocksuite/affine-gfx-note'
| '@blocksuite/affine-gfx-shape'
| '@blocksuite/affine-gfx-text'
| '@blocksuite/affine-gfx-turbo-renderer'
+1
View File
@@ -75,6 +75,7 @@
{ "path": "./blocksuite/affine/fragments/fragment-doc-title" },
{ "path": "./blocksuite/affine/fragments/fragment-frame-panel" },
{ "path": "./blocksuite/affine/fragments/fragment-outline" },
{ "path": "./blocksuite/affine/gfx/note" },
{ "path": "./blocksuite/affine/gfx/shape" },
{ "path": "./blocksuite/affine/gfx/text" },
{ "path": "./blocksuite/affine/gfx/turbo-renderer" },
+32
View File
@@ -2733,6 +2733,7 @@ __metadata:
"@blocksuite/affine-block-table": "workspace:*"
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-fragment-doc-title": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"
"@blocksuite/affine-inline-latex": "workspace:*"
@@ -2968,6 +2969,36 @@ __metadata:
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"
dependencies:
"@blocksuite/affine-block-attachment": "workspace:*"
"@blocksuite/affine-block-bookmark": "workspace:*"
"@blocksuite/affine-block-image": "workspace:*"
"@blocksuite/affine-block-surface": "workspace:*"
"@blocksuite/affine-components": "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"
yjs: "npm:^13.6.21"
zod: "npm:^3.23.8"
languageName: unknown
linkType: soft
"@blocksuite/affine-gfx-shape@workspace:*, @blocksuite/affine-gfx-shape@workspace:blocksuite/affine/gfx/shape":
version: 0.0.0-use.local
resolution: "@blocksuite/affine-gfx-shape@workspace:blocksuite/affine/gfx/shape"
@@ -3480,6 +3511,7 @@ __metadata:
"@blocksuite/affine-fragment-doc-title": "workspace:*"
"@blocksuite/affine-fragment-frame-panel": "workspace:*"
"@blocksuite/affine-fragment-outline": "workspace:*"
"@blocksuite/affine-gfx-note": "workspace:*"
"@blocksuite/affine-gfx-shape": "workspace:*"
"@blocksuite/affine-gfx-text": "workspace:*"
"@blocksuite/affine-gfx-turbo-renderer": "workspace:*"