feat(editor): content block getter command (#10720)

### TL;DR
Added new commands to retrieve the first and last content blocks in a document.

### What changed?
- Created `getFirstContentBlockCommand` to find the first content block in a document
- Created `getLastContentBlockCommand` to find the last content block in a document
- Added `getFirstNoteBlock` utility function to find the first note block in a document
This commit is contained in:
yoyoyohamapi
2025-03-14 02:35:20 +00:00
parent d936553047
commit aa15b106d9
4 changed files with 104 additions and 0 deletions
@@ -0,0 +1,43 @@
import type { Command } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
import { getFirstNoteBlock } from '../../utils';
/**
* Get the first content block in the document
*
* @param ctx - Command context
* @param ctx.root - The root note block model
* @param next - Next handler function
* @returns The first content block model or null
*/
export const getFirstContentBlockCommand: Command<
{
root?: BlockModel;
},
{
firstBlock: BlockModel | null;
}
> = (ctx, next) => {
const doc = ctx.std.host.doc;
const noteBlock = ctx.root ?? getFirstNoteBlock(doc);
if (!noteBlock) {
next({
firstBlock: null,
});
return;
}
for (const child of noteBlock.children) {
if (child.role === 'content') {
next({
firstBlock: child,
});
return;
}
}
next({
firstBlock: null,
});
};
@@ -0,0 +1,43 @@
import type { Command } from '@blocksuite/block-std';
import type { BlockModel } from '@blocksuite/store';
import { getLastNoteBlock } from '../../utils';
/**
* Get the last content block in the document
*
* @param ctx - Command context
* @param ctx.root - The root note block model
* @param next - Next handler function
* @returns The last content block model or null
*/
export const getLastContentBlockCommand: Command<
{
root?: BlockModel;
},
{
lastBlock: BlockModel | null;
}
> = (ctx, next) => {
const noteBlock = ctx.root ?? getLastNoteBlock(ctx.std.host.doc);
if (!noteBlock) {
next({
lastBlock: null,
});
return;
}
const children = noteBlock.children;
for (let i = children.length - 1; i >= 0; i--) {
if (children[i].role === 'content') {
next({
lastBlock: children[i],
});
return;
}
}
next({
lastBlock: null,
});
};
@@ -1,4 +1,6 @@
export { getBlockIndexCommand } from './get-block-index.js';
export { getFirstContentBlockCommand } from './get-first-content-block.js';
export { getLastContentBlockCommand } from './get-last-content-block.js';
export { getNextBlockCommand } from './get-next-block.js';
export { getPrevBlockCommand } from './get-prev-block.js';
export { getSelectedBlocksCommand } from './get-selected-blocks.js';
@@ -57,3 +57,19 @@ export function getLastNoteBlock(doc: Store) {
}
return note;
}
export function getFirstNoteBlock(doc: Store) {
let note: NoteBlockModel | null = null;
if (!doc.root) return null;
const { children } = doc.root;
for (const child of children) {
if (
matchModels(child, [NoteBlockModel]) &&
child.displayMode !== NoteDisplayMode.EdgelessOnly
) {
note = child as NoteBlockModel;
break;
}
}
return note;
}