mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-24 05:07:06 +08:00
24448659a4
Fix #12284 Close [BS-3517](https://linear.app/affine-design/issue/BS-3517/微软新注音输入法无法使用markdown语法) This PR refactor the markdown transform during inputting, including: - Transfrom markdown syntax input in `inlineEditor.slots.inputting`, where we can detect the space character inputed by IME like Microsoft Bopomofo, but `keydown` event can't. - Remove `markdown-input.ts` which was used in `KeymapExtension` of paragraph, and refactor with `InlineMarkdownExtension` - Adjust existing `InlineMarkdownExtension` since the space is included in text. - Add two `InlineMarkdownExtension` for paragraph and list to impl Heading1-6, number, bullet, to-do list conversion. Other changes: - Improve type hint for parameter of `store.addBlock` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Added markdown shortcuts for creating code blocks and dividers in the rich text editor. - Introduced enhanced paragraph markdown support for headings and blockquotes with inline markdown patterns. - Integrated new list markdown extension supporting numbered, bulleted, and todo lists with checked states. - **Improvements** - Updated markdown formatting patterns to require trailing spaces for links, LaTeX, and inline styles, improving detection accuracy. - Markdown transformations now respond to input events instead of keydown for smoother editing experience. - Added focus management after markdown transformations to maintain seamless editing flow. - **Bug Fixes** - Removed unnecessary prevention of default behavior on space and shift-space key presses in list and paragraph editors. - **Refactor** - Enhanced event handling and typing for editor input events, improving reliability and maintainability. - Refined internal prefix text extraction logic for markdown processing. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
181 lines
4.8 KiB
TypeScript
181 lines
4.8 KiB
TypeScript
import {
|
|
DocModeProvider,
|
|
TelemetryProvider,
|
|
} from '@blocksuite/affine-shared/services';
|
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
|
import type { BlockComponent } from '@blocksuite/std';
|
|
import { InlineMarkdownExtension } from '@blocksuite/std/inline';
|
|
|
|
export const LatexExtension = InlineMarkdownExtension<AffineTextAttributes>({
|
|
name: 'latex',
|
|
|
|
pattern:
|
|
/(?:\$\$)(?<content>[^$]+)(?:\$\$)\s$|(?<blockPrefix>\$\$\$\$)\s$|(?<inlinePrefix>\$\$)\s$/g,
|
|
action: ({ inlineEditor, prefixText, inlineRange, pattern, undoManager }) => {
|
|
const match = pattern.exec(prefixText);
|
|
if (!match || !match.groups) return;
|
|
const content = match.groups['content'];
|
|
const inlinePrefix = match.groups['inlinePrefix'];
|
|
const blockPrefix = match.groups['blockPrefix'];
|
|
|
|
if (!inlineEditor.rootElement) return;
|
|
const blockComponent =
|
|
inlineEditor.rootElement.closest<BlockComponent>('[data-block-id]');
|
|
if (!blockComponent) return;
|
|
|
|
const doc = blockComponent.store;
|
|
const std = blockComponent.std;
|
|
const parentComponent = blockComponent.parentComponent;
|
|
if (!parentComponent) return;
|
|
const index = parentComponent.model.children.indexOf(blockComponent.model);
|
|
if (index === -1) return;
|
|
const mode = std.get(DocModeProvider).getEditorMode() ?? 'page';
|
|
const ifEdgelessText = blockComponent.closest('affine-edgeless-text');
|
|
|
|
if (blockPrefix === '$$$$') {
|
|
undoManager.stopCapturing();
|
|
|
|
inlineEditor.deleteText({
|
|
index: inlineRange.index - 5,
|
|
length: 5,
|
|
});
|
|
|
|
const id = doc.addBlock(
|
|
'affine:latex',
|
|
{
|
|
latex: '',
|
|
},
|
|
parentComponent.model,
|
|
index + 1
|
|
);
|
|
blockComponent.host.updateComplete
|
|
.then(() => {
|
|
const latexBlock = blockComponent.std.view.getBlock(id);
|
|
if (!latexBlock || latexBlock.flavour !== 'affine:latex') return;
|
|
|
|
//FIXME(@Flrande): wait for refactor
|
|
// @ts-expect-error BS-2241
|
|
latexBlock.toggleEditor();
|
|
})
|
|
.catch(console.error);
|
|
|
|
std.getOptional(TelemetryProvider)?.track('Latex', {
|
|
from:
|
|
mode === 'page'
|
|
? 'doc'
|
|
: ifEdgelessText
|
|
? 'edgeless text'
|
|
: 'edgeless note',
|
|
page: mode === 'page' ? 'doc' : 'edgeless',
|
|
segment: mode === 'page' ? 'doc' : 'whiteboard',
|
|
module: 'equation',
|
|
control: 'create equation',
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (inlinePrefix === '$$') {
|
|
undoManager.stopCapturing();
|
|
|
|
inlineEditor.deleteText({
|
|
index: inlineRange.index - 3,
|
|
length: 3,
|
|
});
|
|
inlineEditor.insertText(
|
|
{
|
|
index: inlineRange.index - 3,
|
|
length: 0,
|
|
},
|
|
' '
|
|
);
|
|
inlineEditor.formatText(
|
|
{
|
|
index: inlineRange.index - 3,
|
|
length: 1,
|
|
},
|
|
{
|
|
latex: '',
|
|
}
|
|
);
|
|
|
|
inlineEditor
|
|
.waitForUpdate()
|
|
.then(async () => {
|
|
await inlineEditor.waitForUpdate();
|
|
|
|
const textPoint = inlineEditor.getTextPoint(
|
|
inlineRange.index - 3 + 1
|
|
);
|
|
if (!textPoint) return;
|
|
|
|
const [text] = textPoint;
|
|
const latexNode = text.parentElement?.closest('affine-latex-node');
|
|
if (!latexNode) return;
|
|
|
|
latexNode.toggleEditor();
|
|
})
|
|
.catch(console.error);
|
|
|
|
std.getOptional(TelemetryProvider)?.track('Latex', {
|
|
from:
|
|
mode === 'page'
|
|
? 'doc'
|
|
: ifEdgelessText
|
|
? 'edgeless text'
|
|
: 'edgeless note',
|
|
page: mode === 'page' ? 'doc' : 'edgeless',
|
|
segment: mode === 'page' ? 'doc' : 'whiteboard',
|
|
module: 'inline equation',
|
|
control: 'create inline equation',
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
if (!content || content.length === 0) return;
|
|
|
|
undoManager.stopCapturing();
|
|
|
|
const startIndex = inlineRange.index - 1 - 2 - content.length - 2;
|
|
inlineEditor.deleteText({
|
|
index: startIndex,
|
|
length: 2 + content.length + 2 + 1,
|
|
});
|
|
inlineEditor.insertText(
|
|
{
|
|
index: startIndex,
|
|
length: 0,
|
|
},
|
|
' '
|
|
);
|
|
inlineEditor.formatText(
|
|
{
|
|
index: startIndex,
|
|
length: 1,
|
|
},
|
|
{
|
|
latex: String.raw`${content}`,
|
|
}
|
|
);
|
|
|
|
inlineEditor.setInlineRange({
|
|
index: startIndex + 1,
|
|
length: 0,
|
|
});
|
|
|
|
std.getOptional(TelemetryProvider)?.track('Latex', {
|
|
from:
|
|
mode === 'page'
|
|
? 'doc'
|
|
: ifEdgelessText
|
|
? 'edgeless text'
|
|
: 'edgeless note',
|
|
page: mode === 'page' ? 'doc' : 'edgeless',
|
|
segment: mode === 'page' ? 'doc' : 'whiteboard',
|
|
module: 'inline equation',
|
|
control: 'create inline equation',
|
|
});
|
|
},
|
|
});
|