mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-18 18:46:19 +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 -->
75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import {
|
|
ListBlockModel,
|
|
ParagraphBlockModel,
|
|
ParagraphBlockSchema,
|
|
type ParagraphType,
|
|
} from '@blocksuite/affine-model';
|
|
import { focusTextModel } from '@blocksuite/affine-rich-text';
|
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
|
import { matchModels } from '@blocksuite/affine-shared/utils';
|
|
import type { BlockComponent } from '@blocksuite/std';
|
|
import { InlineMarkdownExtension } from '@blocksuite/std/inline';
|
|
|
|
export const ParagraphMarkdownExtension =
|
|
InlineMarkdownExtension<AffineTextAttributes>({
|
|
name: 'heading',
|
|
pattern: /^((#{1,6})|(>))\s$/,
|
|
action: ({ inlineEditor, pattern, inlineRange, prefixText }) => {
|
|
if (inlineEditor.yTextString.slice(0, inlineRange.index).includes('\n')) {
|
|
return;
|
|
}
|
|
|
|
const match = prefixText.match(pattern);
|
|
if (!match) return;
|
|
|
|
const type = (
|
|
match[2] ? `h${match[2].length}` : 'quote'
|
|
) as ParagraphType;
|
|
|
|
if (!inlineEditor.rootElement) return;
|
|
const blockComponent =
|
|
inlineEditor.rootElement.closest<BlockComponent>('[data-block-id]');
|
|
if (!blockComponent) return;
|
|
|
|
const { model, std, store } = blockComponent;
|
|
if (
|
|
!matchModels(model, [ParagraphBlockModel]) &&
|
|
matchModels(model, [ListBlockModel])
|
|
) {
|
|
const parent = store.getParent(model);
|
|
if (!parent) return;
|
|
const index = parent.children.indexOf(model);
|
|
|
|
store.captureSync();
|
|
inlineEditor.deleteText({
|
|
index: 0,
|
|
length: inlineRange.index,
|
|
});
|
|
store.deleteBlock(model, { deleteChildren: false });
|
|
const id = store.addBlock<ParagraphBlockModel>(
|
|
ParagraphBlockSchema.model.flavour,
|
|
{
|
|
type: type,
|
|
text: model.text?.clone(),
|
|
children: model.children,
|
|
},
|
|
parent,
|
|
index
|
|
);
|
|
|
|
focusTextModel(std, id);
|
|
} else if (
|
|
matchModels(model, [ParagraphBlockModel]) &&
|
|
model.props.type !== type
|
|
) {
|
|
store.captureSync();
|
|
inlineEditor.deleteText({
|
|
index: 0,
|
|
length: inlineRange.index,
|
|
});
|
|
store.updateBlock(model, { type });
|
|
focusTextModel(std, model.id);
|
|
}
|
|
},
|
|
});
|