chore: merge blocksuite source code (#9213)

This commit is contained in:
Mirone
2024-12-20 15:38:06 +08:00
committed by GitHub
parent 2c9ef916f4
commit 30200ff86d
2031 changed files with 238888 additions and 229 deletions
@@ -0,0 +1,171 @@
import { matchFlavours } from '@blocksuite/affine-shared/utils';
import type { BlockComponent, BlockSelection } from '@blocksuite/block-std';
import { IS_MAC, IS_WINDOWS } from '@blocksuite/global/env';
import { assertExists } from '@blocksuite/global/utils';
import {
convertSelectedBlocksToLinkedDoc,
getTitleFromSelectedModels,
notifyDocCreated,
promptDocTitle,
} from '../../_common/utils/render-linked-doc.js';
export class PageKeyboardManager {
private _handleDelete = () => {
const blockSelections = this._currentSelection.filter(sel =>
sel.is('block')
);
if (blockSelections.length === 0) {
return;
}
this._doc.transact(() => {
const selection = this._replaceBlocksBySelection(
blockSelections,
'affine:paragraph',
{}
);
if (selection) {
this._selection.setGroup('note', [
this._selection.create('text', {
from: {
index: 0,
length: 0,
blockId: selection.blockId,
},
to: null,
}),
]);
}
});
};
private get _currentSelection() {
return this._selection.value;
}
private get _doc() {
return this.rootComponent.doc;
}
private get _selection() {
return this.rootComponent.host.selection;
}
constructor(public rootComponent: BlockComponent) {
this.rootComponent.bindHotKey(
{
'Mod-z': ctx => {
ctx.get('defaultState').event.preventDefault();
if (this._doc.canUndo) {
this._doc.undo();
}
},
'Shift-Mod-z': ctx => {
ctx.get('defaultState').event.preventDefault();
if (this._doc.canRedo) {
this._doc.redo();
}
},
'Control-y': ctx => {
if (!IS_WINDOWS) return;
ctx.get('defaultState').event.preventDefault();
if (this._doc.canRedo) {
this._doc.redo();
}
},
'Mod-Backspace': () => true,
Backspace: this._handleDelete,
Delete: this._handleDelete,
'Control-d': () => {
if (!IS_MAC) return;
this._handleDelete();
},
'Mod-Shift-l': () => {
this._createEmbedBlock();
},
},
{
global: true,
}
);
}
private _createEmbedBlock() {
const rootComponent = this.rootComponent;
const [_, ctx] = this.rootComponent.std.command
.chain()
.getSelectedModels({
types: ['block'],
mode: 'highest',
})
.draftSelectedModels()
.run();
const selectedModels = ctx.selectedModels?.filter(
block =>
!block.flavour.startsWith('affine:embed-') &&
matchFlavours(doc.getParent(block), ['affine:note'])
);
const draftedModels = ctx.draftedModels;
if (!selectedModels?.length || !draftedModels) {
return;
}
const doc = rootComponent.host.doc;
const autofill = getTitleFromSelectedModels(selectedModels);
void promptDocTitle(rootComponent.host, autofill).then(title => {
if (title === null) return;
convertSelectedBlocksToLinkedDoc(
this.rootComponent.std,
doc,
draftedModels,
title
).catch(console.error);
notifyDocCreated(rootComponent.host, doc);
});
}
private _deleteBlocksBySelection(selections: BlockSelection[]) {
selections.forEach(selection => {
const block = this._doc.getBlockById(selection.blockId);
if (block) {
this._doc.deleteBlock(block);
}
});
}
private _replaceBlocksBySelection(
selections: BlockSelection[],
flavour: string,
props: Record<string, unknown>
) {
const current = selections[0];
const first = this._doc.getBlockById(current.blockId);
const firstElement = this.rootComponent.host.view.getBlock(current.blockId);
assertExists(first, `Cannot find block ${current.blockId}`);
assertExists(firstElement, `Cannot find block view ${current.blockId}`);
const parent = this._doc.getParent(first);
const index = parent?.children.indexOf(first);
this._deleteBlocksBySelection(selections);
try {
this._doc.schema.validate(flavour, parent?.flavour);
} catch {
return null;
}
const blockId = this._doc.addBlock(flavour as never, props, parent, index);
return {
blockId,
path: blockId,
};
}
}