diff --git a/.changeset/green-spies-jam.md b/.changeset/green-spies-jam.md new file mode 100644 index 00000000000..9670b73a03e --- /dev/null +++ b/.changeset/green-spies-jam.md @@ -0,0 +1,8 @@ +--- +"@milkdown/plugin-block": patch +"@milkdown/components": patch +"@milkdown/crepe": patch +"@milkdown/kit": patch +--- + +Fix plugin block bugs diff --git a/packages/components/src/table-block/view/utils.ts b/packages/components/src/table-block/view/utils.ts index 62056a21ea2..5032e645ccc 100644 --- a/packages/components/src/table-block/view/utils.ts +++ b/packages/components/src/table-block/view/utils.ts @@ -20,31 +20,37 @@ export function findNodeIndex(parent: Node, child: Node) { export function findPointerIndex(event: PointerEvent, view?: EditorView): CellIndex | undefined { if (!view) return - const posAtCoords = view.posAtCoords({ left: event.clientX, top: event.clientY }) - if (!posAtCoords) - return - const pos = posAtCoords?.inside - if (pos == null || pos < 0) - return - const $pos = view.state.doc.resolve(pos) - const node = view.state.doc.nodeAt(pos) - if (!node) - return + try { + const posAtCoords = view.posAtCoords({ left: event.clientX, top: event.clientY }) + if (!posAtCoords) + return + const pos = posAtCoords?.inside + if (pos == null || pos < 0) + return - const cellType = ['table_cell', 'table_header'] - const rowType = ['table_row', 'table_header_row'] + const $pos = view.state.doc.resolve(pos) + const node = view.state.doc.nodeAt(pos) + if (!node) + return - const cell = cellType.includes(node.type.name) ? node : findParent(node => cellType.includes(node.type.name))($pos)?.node - const row = findParent(node => rowType.includes(node.type.name))($pos)?.node - const table = findParent(node => node.type.name === 'table')($pos)?.node - if (!cell || !row || !table) - return + const cellType = ['table_cell', 'table_header'] + const rowType = ['table_row', 'table_header_row'] + + const cell = cellType.includes(node.type.name) ? node : findParent(node => cellType.includes(node.type.name))($pos)?.node + const row = findParent(node => rowType.includes(node.type.name))($pos)?.node + const table = findParent(node => node.type.name === 'table')($pos)?.node + if (!cell || !row || !table) + return - const columnIndex = findNodeIndex(row, cell) - const rowIndex = findNodeIndex(table, row) + const columnIndex = findNodeIndex(row, cell) + const rowIndex = findNodeIndex(table, row) - return [rowIndex, columnIndex] + return [rowIndex, columnIndex] + } + catch { + return undefined + } } export function getRelatedDOM(contentWrapperRef: Ref, [rowIndex, columnIndex]: CellIndex) { diff --git a/packages/crepe/src/feature/block-edit/handle/index.ts b/packages/crepe/src/feature/block-edit/handle/index.ts index 5059f5aa444..547cee63a5c 100644 --- a/packages/crepe/src/feature/block-edit/handle/index.ts +++ b/packages/crepe/src/feature/block-edit/handle/index.ts @@ -1,10 +1,11 @@ import type { PluginView } from '@milkdown/kit/prose/state' import { TextSelection } from '@milkdown/kit/prose/state' -import { BlockProvider, block } from '@milkdown/kit/plugin/block' +import { BlockProvider, block, blockConfig } from '@milkdown/kit/plugin/block' import type { Ctx } from '@milkdown/kit/ctx' import type { AtomicoThis } from 'atomico/types/dom' import { editorViewCtx } from '@milkdown/kit/core' import { paragraphSchema } from '@milkdown/kit/preset/commonmark' +import { findParent } from '@milkdown/kit/prose' import { menuAPI } from '../menu' import { defIfNotExists } from '../../../utils' import type { BlockEditFeatureConfig } from '../index' @@ -28,6 +29,9 @@ export class BlockHandleView implements PluginView { content, getOffset: () => 16, getPlacement: ({ active, blockDom }) => { + if (active.node.type.name === 'heading') + return 'left' + let totalDescendant = 0 active.node.descendants((node) => { totalDescendant += node.childCount @@ -40,7 +44,7 @@ export class BlockHandleView implements PluginView { const paddingBottom = Number.parseInt(style.paddingBottom, 10) || 0 const height = domRect.height - paddingTop - paddingBottom const handleHeight = handleRect.height - return totalDescendant > 2 || handleHeight * 2 < height ? 'left-start' : 'left' + return totalDescendant > 2 || handleHeight < height ? 'left-start' : 'left' }, }) this.update() @@ -79,6 +83,15 @@ export class BlockHandleView implements PluginView { defIfNotExists('milkdown-block-handle', BlockHandleElement) export function configureBlockHandle(ctx: Ctx, config?: BlockEditFeatureConfig) { + ctx.set(blockConfig.key, { + filterNodes: (pos) => { + const filter = findParent(node => ['table', 'blockquote'].includes(node.type.name))(pos) + if (filter) + return false + + return true + }, + }) ctx.set(block.key, { view: () => new BlockHandleView(ctx, config), }) diff --git a/packages/crepe/src/theme/common/block-edit.css b/packages/crepe/src/theme/common/block-edit.css index 339bf46aa37..2bee5ff087a 100644 --- a/packages/crepe/src/theme/common/block-edit.css +++ b/packages/crepe/src/theme/common/block-edit.css @@ -2,6 +2,7 @@ milkdown-block-handle { &[data-show='false'] { opacity: 0; + pointer-events: none; } transition: all 0.2s; position: absolute; diff --git a/packages/plugins/plugin-block/src/__internal__/select-node-by-dom.ts b/packages/plugins/plugin-block/src/__internal__/select-node-by-dom.ts index 2ee08ba6e08..e45d07a5e73 100644 --- a/packages/plugins/plugin-block/src/__internal__/select-node-by-dom.ts +++ b/packages/plugins/plugin-block/src/__internal__/select-node-by-dom.ts @@ -8,39 +8,44 @@ export function selectRootNodeByDom(view: EditorView, coords: { x: number, y: nu if (!root) return null - const pos = view.posAtCoords({ - left: coords.x, - top: coords.y, - })?.inside - if (pos == null || pos < 0) - return null - - let $pos = view.state.doc.resolve(pos) - let node = view.state.doc.nodeAt(pos) - let element = view.nodeDOM(pos) as HTMLElement | null - - const filter = (needLookup: boolean) => { - const checkDepth = $pos.depth >= 1 && $pos.index($pos.depth) === 0 - const shouldLookUp = needLookup || checkDepth - - if (!shouldLookUp) - return - - const ancestorPos = $pos.before($pos.depth) - node = view.state.doc.nodeAt(ancestorPos) - element = view.nodeDOM(ancestorPos) as HTMLElement | null - $pos = view.state.doc.resolve(ancestorPos) - - if (!filterNodes($pos, node!)) - filter(true) + try { + const pos = view.posAtCoords({ + left: coords.x, + top: coords.y, + })?.inside + if (pos == null || pos < 0) + return null + + let $pos = view.state.doc.resolve(pos) + let node = view.state.doc.nodeAt(pos) + let element = view.nodeDOM(pos) as HTMLElement | null + + const filter = (needLookup: boolean) => { + const checkDepth = $pos.depth >= 1 && $pos.index($pos.depth) === 0 + const shouldLookUp = needLookup || checkDepth + + if (!shouldLookUp) + return + + const ancestorPos = $pos.before($pos.depth) + node = view.state.doc.nodeAt(ancestorPos) + element = view.nodeDOM(ancestorPos) as HTMLElement | null + $pos = view.state.doc.resolve(ancestorPos) + + if (!filterNodes($pos, node!)) + filter(true) + } + + // If filterNodes returns false, we should look up the parent node. + const filterResult = filterNodes($pos, node!) + filter(!filterResult) + + if (!element || !node) + return null + + return { node, $pos, el: element } } - - // If filterNodes returns false, we should look up the parent node. - const filterResult = filterNodes($pos, node!) - filter(!filterResult) - - if (!element || !node) + catch { return null - - return { node, $pos, el: element } + } } diff --git a/packages/plugins/plugin-block/src/block-provider.ts b/packages/plugins/plugin-block/src/block-provider.ts index e2faa3e78ae..c62d6c99eaa 100644 --- a/packages/plugins/plugin-block/src/block-provider.ts +++ b/packages/plugins/plugin-block/src/block-provider.ts @@ -170,11 +170,5 @@ export class BlockProvider { /// Hide the block. hide = () => { this.#element.dataset.show = 'false' - setTimeout(() => { - Object.assign(this.#element.style, { - left: `-999px`, - top: `-999px`, - }) - }, 200) } } diff --git a/storybook/stories/crepe/setup.ts b/storybook/stories/crepe/setup.ts index 008123c1f62..a7bcfefb577 100644 --- a/storybook/stories/crepe/setup.ts +++ b/storybook/stories/crepe/setup.ts @@ -127,6 +127,10 @@ const crepe = new Crepe({ > > No escape from [reality](https://en.wikipedia.org/wiki/Bohemian_Rhapsody). +Open your eyes, look up to the skies and see. + +I'm just a poor boy, I need no sympathy, because I'm easy come, easy go, little high, little low. + | Fruit | Animal | Vegetable | | ----- | :----: | --------: | | 🍎 | 🐱 | 🥕 |