Files
new-markdown/tests/image-enter.test.ts
Muse 5f4a80fa01 feat(editor): 图片可选中换行、可调大小、右键链接针对图片(docs/31)
用户反馈三件:图片选不中没法在后面打字、右键不能改大小、图片的
超链接是空的。无头 Chrome 真实点击复现根因:点击能形成节点选区
但无任何视觉提示;图片选中时按 Enter 走 splitBlock,新段落插到
图片前面且选区仍停在图片上,接着打字会把图片替换掉。
- Enter 修复:捕获阶段 keydown 只接管图片选区,在图片所在文本块后
  插空段落并移入光标(createParagraphNear 对行内节点无效,自己写);
  选中图片加主题色描边。
- 大小:图片节点加 width 属性,带尺寸时序列化为 <img … width>、
  否则标准语法;remark 插件把孤立 <img> 解析回图片节点(实体解码、
  块级包段落),往返逐字一致;右键「调整图片大小…」弹窗 px/% 可调。
- 链接:右键图片的「超链接…」改为图片模式,预填包裹链接、提交对
  图片节点挂/摘 link 标记([![alt](src)](href) 可往返)。
验证:vitest 148+2(新增 image-size/image-enter 共 12 例)、构建通过、
无头 Chrome 实测点击/Enter/打字全流程。
2026-11-15 09:41:24 +08:00

45 lines
2.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from 'vitest'
import { editorViewCtx } from '@milkdown/kit/core'
import { NodeSelection } from '@milkdown/kit/prose/state'
import { createMarkdownEditor, getMarkdown } from '../src/editor/editor'
describe('图片选中时按 Enter(docs/31)', () => {
it('在图片段落后新建空段落并把光标移入,图片保留', async () => {
const root = document.createElement('div')
document.body.appendChild(root)
const editor = createMarkdownEditor(root, '前文\n\n![图](a.png)\n\n后文\n')
await editor.create()
const after = editor.action((ctx) => {
const view = ctx.get(editorViewCtx)
let pos = -1
view.state.doc.descendants((n, p) => { if (n.type.name === 'image') pos = p; return true })
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, pos)))
view.dom.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
const blocks: string[] = []
view.state.doc.forEach((n) => blocks.push(n.type.name + ':' + n.textContent + (n.content.size && n.firstChild?.type.name === 'image' ? '[img]' : '')))
return { blocks, selType: view.state.selection.constructor.name, selFrom: view.state.selection.from }
})
expect(after.blocks).toEqual(['paragraph:前文', 'paragraph:[img]', 'paragraph:', 'paragraph:后文'])
expect(after.selType).toContain('TextSelection')
expect(getMarkdown(editor)).toContain('![图](a.png)')
await editor.destroy(); root.remove()
})
it('普通文本处按 Enter 不被接管(仍是原有分段行为)', async () => {
const root = document.createElement('div')
document.body.appendChild(root)
const editor = createMarkdownEditor(root, '你好世界\n')
await editor.create()
editor.action((ctx) => {
const view = ctx.get(editorViewCtx)
// 光标放文本中间(非图片选区),捕获监听应放行——这里只断言监听不误伤:
// jsdom 里默认 Enter 链未必完整执行,至少文档不能被插入多余段落到图片逻辑位置
view.dom.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, cancelable: true }))
return null
})
// 不抛错、编辑器仍可用即可(默认链行为由无头浏览器实测覆盖)
expect(getMarkdown(editor)).toContain('你好世界')
await editor.destroy(); root.remove()
})
})