mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 21:38:44 +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 -->
137 lines
3.9 KiB
TypeScript
137 lines
3.9 KiB
TypeScript
import { textKeymap } from '@blocksuite/affine-inline-preset';
|
|
import { ListBlockSchema } from '@blocksuite/affine-model';
|
|
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
|
|
import { IS_MAC } from '@blocksuite/global/env';
|
|
import { KeymapExtension, TextSelection } from '@blocksuite/std';
|
|
|
|
import {
|
|
canDedentListCommand,
|
|
dedentListCommand,
|
|
} from './commands/dedent-list.js';
|
|
import {
|
|
canIndentListCommand,
|
|
indentListCommand,
|
|
} from './commands/indent-list.js';
|
|
import { listToParagraphCommand } from './commands/list-to-paragraph.js';
|
|
import { splitListCommand } from './commands/split-list.js';
|
|
import { forwardDelete } from './utils/forward-delete.js';
|
|
|
|
export const ListKeymapExtension = KeymapExtension(
|
|
std => {
|
|
return {
|
|
Enter: ctx => {
|
|
const text = std.selection.find(TextSelection);
|
|
if (!text) return false;
|
|
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
std.command
|
|
.chain()
|
|
.pipe(splitListCommand, {
|
|
blockId: text.from.blockId,
|
|
inlineIndex: text.from.index,
|
|
})
|
|
.run();
|
|
return true;
|
|
},
|
|
'Mod-Enter': ctx => {
|
|
const text = std.selection.find(TextSelection);
|
|
if (!text) return false;
|
|
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
std.command
|
|
.chain()
|
|
.pipe(splitListCommand, {
|
|
blockId: text.from.blockId,
|
|
inlineIndex: text.from.index,
|
|
})
|
|
.run();
|
|
return true;
|
|
},
|
|
Tab: ctx => {
|
|
const [_, { selectedModels }] = std.command
|
|
.chain()
|
|
.pipe(getSelectedModelsCommand, {
|
|
types: ['text'],
|
|
})
|
|
.run();
|
|
if (selectedModels?.length !== 1) {
|
|
return false;
|
|
}
|
|
const text = std.selection.find(TextSelection);
|
|
if (!text) return false;
|
|
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
std.command
|
|
.chain()
|
|
.pipe(canIndentListCommand, {
|
|
blockId: text.from.blockId,
|
|
inlineIndex: text.from.index,
|
|
})
|
|
.pipe(indentListCommand)
|
|
.run();
|
|
return true;
|
|
},
|
|
'Shift-Tab': ctx => {
|
|
const [_, { selectedModels }] = std.command
|
|
.chain()
|
|
.pipe(getSelectedModelsCommand, {
|
|
types: ['text'],
|
|
})
|
|
.run();
|
|
if (selectedModels?.length !== 1) {
|
|
return;
|
|
}
|
|
const text = std.selection.find(TextSelection);
|
|
if (!text) return false;
|
|
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
std.command
|
|
.chain()
|
|
.pipe(canDedentListCommand, {
|
|
blockId: text.from.blockId,
|
|
inlineIndex: text.from.index,
|
|
})
|
|
.pipe(dedentListCommand)
|
|
.run();
|
|
return true;
|
|
},
|
|
Backspace: ctx => {
|
|
const text = std.selection.find(TextSelection);
|
|
if (!text) return false;
|
|
const isCollapsed = text.isCollapsed();
|
|
const isStart = isCollapsed && text.from.index === 0;
|
|
if (!isStart) return false;
|
|
|
|
ctx.get('defaultState').event.preventDefault();
|
|
std.command
|
|
.chain()
|
|
.pipe(listToParagraphCommand, {
|
|
id: text.from.blockId,
|
|
})
|
|
.run();
|
|
return true;
|
|
},
|
|
'Control-d': ctx => {
|
|
if (!IS_MAC) return;
|
|
const deleted = forwardDelete(std);
|
|
if (!deleted) return;
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
return true;
|
|
},
|
|
Delete: ctx => {
|
|
const deleted = forwardDelete(std);
|
|
if (!deleted) return;
|
|
ctx.get('keyboardState').raw.preventDefault();
|
|
return true;
|
|
},
|
|
};
|
|
},
|
|
{
|
|
flavour: ListBlockSchema.model.flavour,
|
|
}
|
|
);
|
|
|
|
export const ListTextKeymapExtension = KeymapExtension(textKeymap, {
|
|
flavour: ListBlockSchema.model.flavour,
|
|
});
|