feat(web): mark real document blocks without overlay
Add data-testid=document-block plus block id on every wrapper so pure-mode editors stay addressable without changing visuals. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import { MathBlockView } from './blocks/MathBlockView';
|
|||||||
import { ListBlockView } from './blocks/ListBlockView';
|
import { ListBlockView } from './blocks/ListBlockView';
|
||||||
import { BlockContextMenu } from './BlockContextMenu';
|
import { BlockContextMenu } from './BlockContextMenu';
|
||||||
import { canAddBlockComment } from '../../lib/commentPolicy';
|
import { canAddBlockComment } from '../../lib/commentPolicy';
|
||||||
|
import { documentBlockDomAttrs } from '../../lib/documentBlockDom';
|
||||||
import { Plus, ArrowUp, ArrowDown, Trash2, MessageSquare } from 'lucide-react';
|
import { Plus, ArrowUp, ArrowDown, Trash2, MessageSquare } from 'lucide-react';
|
||||||
|
|
||||||
export interface BlockRendererProps {
|
export interface BlockRendererProps {
|
||||||
@@ -150,6 +151,7 @@ export const BlockRenderer: React.FC<BlockRendererProps> = ({
|
|||||||
<div
|
<div
|
||||||
key={block.id || idx}
|
key={block.id || idx}
|
||||||
id={block.id ? `block-${block.id}` : undefined}
|
id={block.id ? `block-${block.id}` : undefined}
|
||||||
|
{...documentBlockDomAttrs(block)}
|
||||||
data-overlay-kind={hunk?.kind}
|
data-overlay-kind={hunk?.kind}
|
||||||
onMouseEnter={() => setHoveredIndex(idx)}
|
onMouseEnter={() => setHoveredIndex(idx)}
|
||||||
onMouseLeave={() => setHoveredIndex(null)}
|
onMouseLeave={() => setHoveredIndex(null)}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, it } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import {
|
||||||
|
DOCUMENT_BLOCK_TESTID,
|
||||||
|
documentBlockDomAttrs,
|
||||||
|
} from './documentBlockDom';
|
||||||
|
|
||||||
|
describe('documentBlockDomAttrs', () => {
|
||||||
|
it('marks a real DocumentBlock in pure mode without overlay kind', () => {
|
||||||
|
const attrs = documentBlockDomAttrs({ id: 'blk_intake_p1' });
|
||||||
|
assert.equal(attrs['data-testid'], DOCUMENT_BLOCK_TESTID);
|
||||||
|
assert.equal(attrs['data-testid'], 'document-block');
|
||||||
|
assert.equal(attrs['data-document-block'], 'blk_intake_p1');
|
||||||
|
assert.equal(attrs['data-block-id'], 'blk_intake_p1');
|
||||||
|
assert.equal('data-overlay-kind' in attrs, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the same stable attrs when overlay is later attached separately', () => {
|
||||||
|
const pure = documentBlockDomAttrs({ id: 'blk_h1' });
|
||||||
|
const withOverlay = {
|
||||||
|
...documentBlockDomAttrs({ id: 'blk_h1' }),
|
||||||
|
'data-overlay-kind': 'modify',
|
||||||
|
};
|
||||||
|
assert.equal(pure['data-document-block'], withOverlay['data-document-block']);
|
||||||
|
assert.equal(pure['data-testid'], withOverlay['data-testid']);
|
||||||
|
assert.notEqual(Object.prototype.hasOwnProperty.call(pure, 'data-overlay-kind'), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/** 真实 DocumentBlock wrapper 的稳定寻址标识,与 overlay 是否存在无关。 */
|
||||||
|
export const DOCUMENT_BLOCK_TESTID = 'document-block';
|
||||||
|
|
||||||
|
export function documentBlockDomAttrs(block: { id?: string }): {
|
||||||
|
'data-testid': typeof DOCUMENT_BLOCK_TESTID;
|
||||||
|
'data-document-block': string;
|
||||||
|
'data-block-id': string;
|
||||||
|
} {
|
||||||
|
const id = block.id || '';
|
||||||
|
return {
|
||||||
|
'data-testid': DOCUMENT_BLOCK_TESTID,
|
||||||
|
'data-document-block': id,
|
||||||
|
'data-block-id': id,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user