mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-21 08:17:10 +08:00
@@ -1,18 +1,35 @@
|
||||
import type { SurfaceBlockComponent } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
addNote,
|
||||
DEFAULT_NOTE_OFFSET_X,
|
||||
DEFAULT_NOTE_OFFSET_Y,
|
||||
DefaultTool,
|
||||
EdgelessCRUDIdentifier,
|
||||
EXCLUDING_MOUSE_OUT_CLASS_LIST,
|
||||
type SurfaceBlockComponent,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
DEFAULT_NOTE_HEIGHT,
|
||||
DEFAULT_NOTE_WIDTH,
|
||||
NOTE_MIN_HEIGHT,
|
||||
type NoteBlockModel,
|
||||
NoteDisplayMode,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { EditPropsStore } from '@blocksuite/affine-shared/services';
|
||||
import { focusTextModel } from '@blocksuite/affine-rich-text';
|
||||
import {
|
||||
EditPropsStore,
|
||||
TelemetryProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
|
||||
import { hasClassNameInList } from '@blocksuite/affine-shared/utils';
|
||||
import { Point } from '@blocksuite/global/gfx';
|
||||
import type { PointerEventState } from '@blocksuite/std';
|
||||
import { BaseTool } from '@blocksuite/std/gfx';
|
||||
import {
|
||||
handleNativeRangeAtPoint,
|
||||
hasClassNameInList,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { type IPoint, Point, serializeXYWH } from '@blocksuite/global/gfx';
|
||||
import type { BlockStdScope, PointerEventState } from '@blocksuite/std';
|
||||
import {
|
||||
BaseTool,
|
||||
type GfxBlockElementModel,
|
||||
GfxControllerIdentifier,
|
||||
} from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
|
||||
import { DraggingNoteOverlay, NoteOverlay } from './overlay';
|
||||
@@ -210,3 +227,116 @@ declare module '@blocksuite/std/gfx' {
|
||||
'affine:note': NoteToolOption;
|
||||
}
|
||||
}
|
||||
|
||||
type NoteOptions = {
|
||||
childFlavour: NoteChildrenFlavour;
|
||||
childType: string | null;
|
||||
collapse: boolean;
|
||||
};
|
||||
function addNote(
|
||||
std: BlockStdScope,
|
||||
point: Point,
|
||||
options: NoteOptions,
|
||||
width = DEFAULT_NOTE_WIDTH,
|
||||
height = DEFAULT_NOTE_HEIGHT
|
||||
) {
|
||||
const noteId = addNoteAtPoint(std, point, {
|
||||
width,
|
||||
height,
|
||||
});
|
||||
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
const doc = std.store;
|
||||
|
||||
const blockId = doc.addBlock(
|
||||
options.childFlavour,
|
||||
{ type: options.childType },
|
||||
noteId
|
||||
);
|
||||
if (options.collapse && height > NOTE_MIN_HEIGHT) {
|
||||
const note = doc.getModelById(noteId) as NoteBlockModel;
|
||||
doc.updateBlock(note, () => {
|
||||
note.props.edgeless.collapse = true;
|
||||
note.props.edgeless.collapsedHeight = height;
|
||||
});
|
||||
}
|
||||
gfx.tool.setTool(DefaultTool);
|
||||
|
||||
// Wait for edgelessTool updated
|
||||
requestAnimationFrame(() => {
|
||||
const blocks =
|
||||
(doc.root?.children.filter(
|
||||
child => child.flavour === 'affine:note'
|
||||
) as GfxBlockElementModel[]) ?? [];
|
||||
const element = blocks.find(b => b.id === noteId);
|
||||
if (element) {
|
||||
gfx.selection.set({
|
||||
elements: [element.id],
|
||||
editing: true,
|
||||
});
|
||||
|
||||
// Waiting dom updated, `note mask` is removed
|
||||
if (blockId) {
|
||||
focusTextModel(gfx.std, blockId);
|
||||
} else {
|
||||
// Cannot reuse `handleNativeRangeClick` directly here,
|
||||
// since `retargetClick` will re-target to pervious editor
|
||||
handleNativeRangeAtPoint(point.x, point.y);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addNoteAtPoint(
|
||||
std: BlockStdScope,
|
||||
/**
|
||||
* The point is in browser coordinate
|
||||
*/
|
||||
point: IPoint,
|
||||
options: {
|
||||
width?: number;
|
||||
height?: number;
|
||||
parentId?: string;
|
||||
noteIndex?: number;
|
||||
offsetX?: number;
|
||||
offsetY?: number;
|
||||
scale?: number;
|
||||
} = {}
|
||||
) {
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
const crud = std.get(EdgelessCRUDIdentifier);
|
||||
const {
|
||||
width = DEFAULT_NOTE_WIDTH,
|
||||
height = DEFAULT_NOTE_HEIGHT,
|
||||
offsetX = DEFAULT_NOTE_OFFSET_X,
|
||||
offsetY = DEFAULT_NOTE_OFFSET_Y,
|
||||
parentId = gfx.doc.root?.id,
|
||||
noteIndex,
|
||||
scale = 1,
|
||||
} = options;
|
||||
const [x, y] = gfx.viewport.toModelCoord(point.x, point.y);
|
||||
const blockId = crud.addBlock(
|
||||
'affine:note',
|
||||
{
|
||||
xywh: serializeXYWH(
|
||||
x - offsetX * scale,
|
||||
y - offsetY * scale,
|
||||
width,
|
||||
height
|
||||
),
|
||||
displayMode: NoteDisplayMode.EdgelessOnly,
|
||||
},
|
||||
parentId,
|
||||
noteIndex
|
||||
);
|
||||
|
||||
std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
|
||||
control: 'canvas:draw',
|
||||
page: 'whiteboard editor',
|
||||
module: 'toolbar',
|
||||
segment: 'toolbar',
|
||||
type: 'note',
|
||||
});
|
||||
|
||||
return blockId;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ import {
|
||||
import { type Color, DefaultTheme } from '@blocksuite/affine-model';
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
import type { XYWH } from '@blocksuite/global/gfx';
|
||||
import type { GfxController, GfxToolsMap } from '@blocksuite/std/gfx';
|
||||
import type { GfxController } from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
import type { NoteTool } from '../note-tool';
|
||||
import {
|
||||
NOTE_OVERLAY_CORNER_RADIUS,
|
||||
NOTE_OVERLAY_HEIGHT,
|
||||
@@ -33,8 +34,7 @@ export class NoteOverlay extends ToolOverlay {
|
||||
effect(() => {
|
||||
// when change note child type, update overlay text
|
||||
if (this.gfx.tool.currentToolName$.value !== 'affine:note') return;
|
||||
const tool =
|
||||
this.gfx.tool.currentTool$.peek() as GfxToolsMap['affine:note'];
|
||||
const tool = this.gfx.tool.currentTool$.peek() as NoteTool;
|
||||
this.text = this._getOverlayText(tool.activatedOption.tip);
|
||||
(this.gfx.surfaceComponent as SurfaceBlockComponent).refresh();
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { addAttachments } from '@blocksuite/affine-block-attachment';
|
||||
import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark';
|
||||
import { addImages } from '@blocksuite/affine-block-image';
|
||||
import { DefaultTool } from '@blocksuite/affine-block-surface';
|
||||
import { MAX_IMAGE_WIDTH } from '@blocksuite/affine-model';
|
||||
import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
||||
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
|
||||
@@ -10,13 +11,13 @@ import {
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
|
||||
import { AttachmentIcon, ImageIcon, LinkIcon } from '@blocksuite/icons/lit';
|
||||
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
|
||||
import type { ToolOptions } from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { property, state } from 'lit/decorators.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
|
||||
import type { NoteToolOption } from '../note-tool.js';
|
||||
import { NoteTool, type NoteToolOption } from '../note-tool.js';
|
||||
import { NOTE_MENU_ITEMS } from './note-menu-config.js';
|
||||
|
||||
export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
|
||||
@@ -51,7 +52,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
|
||||
}
|
||||
`;
|
||||
|
||||
override type: GfxToolsFullOptionValue['type'] = 'affine:note';
|
||||
override type = NoteTool;
|
||||
|
||||
private async _addImages() {
|
||||
this._imageLoading = true;
|
||||
@@ -60,8 +61,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.tool.setTool(DefaultTool);
|
||||
this.gfx.selection.set({ elements: ids });
|
||||
}
|
||||
|
||||
@@ -96,10 +96,11 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
|
||||
effect(() => {
|
||||
const tool = this.gfx.tool.currentToolOption$.value;
|
||||
|
||||
if (tool?.type !== 'affine:note') return;
|
||||
this.childFlavour = tool.childFlavour;
|
||||
this.childType = tool.childType;
|
||||
this.tip = tool.tip;
|
||||
if (tool?.toolType !== NoteTool) return;
|
||||
const options = tool.options as ToolOptions<NoteTool>;
|
||||
this.childFlavour = options.childFlavour;
|
||||
this.childType = options.childType;
|
||||
this.tip = options.tip;
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -141,8 +142,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.gfx.tool.setTool(DefaultTool);
|
||||
this.edgeless.std
|
||||
.getOptional(TelemetryProvider)
|
||||
?.track('CanvasElementAdded', {
|
||||
|
||||
@@ -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 '../note-tool.js';
|
||||
import { NoteTool, type NoteToolOption } from '../note-tool.js';
|
||||
import { toShapeNotToAdapt } from './icon.js';
|
||||
|
||||
export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
|
||||
@@ -138,15 +138,14 @@ export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
|
||||
|
||||
override enableActiveBackground = true;
|
||||
|
||||
override type = 'affine:note' as const;
|
||||
override type = NoteTool;
|
||||
|
||||
private _toggleNoteMenu() {
|
||||
if (this.tryDisposePopper()) return;
|
||||
|
||||
const { edgeless, childFlavour, childType, tip } = this;
|
||||
|
||||
this.setEdgelessTool({
|
||||
type: 'affine:note',
|
||||
this.setEdgelessTool(NoteTool, {
|
||||
childFlavour,
|
||||
childType,
|
||||
tip,
|
||||
@@ -171,8 +170,7 @@ export class EdgelessNoteSeniorButton extends EdgelessToolbarToolMixin(
|
||||
Object.assign(this, { [key]: props[key] });
|
||||
}
|
||||
});
|
||||
this.setEdgelessTool({
|
||||
type: 'affine:note',
|
||||
this.setEdgelessTool(NoteTool, {
|
||||
childFlavour: this.childFlavour,
|
||||
childType: this.childType,
|
||||
tip: this.tip,
|
||||
|
||||
@@ -4,12 +4,11 @@ import {
|
||||
QuickToolMixin,
|
||||
} from '@blocksuite/affine-widget-edgeless-toolbar';
|
||||
import { PageIcon } from '@blocksuite/icons/lit';
|
||||
import type { GfxToolsFullOptionValue } from '@blocksuite/std/gfx';
|
||||
import { effect } from '@preact/signals-core';
|
||||
import { css, html, LitElement } from 'lit';
|
||||
import { state } from 'lit/decorators.js';
|
||||
|
||||
import type { NoteToolOption } from '../note-tool.js';
|
||||
import { NoteTool, type NoteToolOption } from '../note-tool.js';
|
||||
import type { EdgelessNoteMenu } from './note-menu.js';
|
||||
|
||||
export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
|
||||
@@ -23,7 +22,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
|
||||
|
||||
private readonly _states = ['childFlavour', 'childType', 'tip'] as const;
|
||||
|
||||
override type: GfxToolsFullOptionValue['type'] = 'affine:note';
|
||||
override type = NoteTool;
|
||||
|
||||
private _disposeMenu() {
|
||||
this._noteMenu?.dispose();
|
||||
@@ -35,7 +34,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
|
||||
this._disposeMenu();
|
||||
this.requestUpdate();
|
||||
} else {
|
||||
this.gfx.tool.setTool('affine:note', {
|
||||
this.gfx.tool.setTool(NoteTool, {
|
||||
childFlavour: this.childFlavour,
|
||||
childType: this.childType,
|
||||
tip: this.tip,
|
||||
@@ -59,7 +58,7 @@ export class EdgelessNoteToolButton extends QuickToolMixin(LitElement) {
|
||||
Object.assign(this, { [key]: props[key] });
|
||||
}
|
||||
});
|
||||
this.gfx.tool.setTool('affine:note', {
|
||||
this.gfx.tool.setTool(NoteTool, {
|
||||
childFlavour: this.childFlavour,
|
||||
childType: this.childType,
|
||||
tip: this.tip,
|
||||
|
||||
Reference in New Issue
Block a user