mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 09:21:24 +08:00
feat(editor): unify block props api (#10888)
Closes: [BS-2707](https://linear.app/affine-design/issue/BS-2707/统一使用props获取和更新block-prop)
This commit is contained in:
@@ -90,8 +90,8 @@ export const dedentParagraphCommand: Command<{
|
||||
|
||||
if (
|
||||
matchModels(model, [ParagraphBlockModel]) &&
|
||||
model.type.startsWith('h') &&
|
||||
model.collapsed
|
||||
model.props.type.startsWith('h') &&
|
||||
model.props.collapsed
|
||||
) {
|
||||
const collapsedSiblings = calculateCollapsedSiblings(model);
|
||||
store.moveBlocks([model, ...collapsedSiblings], grandParent, parent, false);
|
||||
|
||||
@@ -96,7 +96,7 @@ export const indentParagraphCommand: Command<{
|
||||
if (
|
||||
nearestHeading &&
|
||||
matchModels(nearestHeading, [ParagraphBlockModel]) &&
|
||||
nearestHeading.collapsed
|
||||
nearestHeading.props.collapsed
|
||||
) {
|
||||
store.updateBlock(nearestHeading, {
|
||||
collapsed: false,
|
||||
@@ -106,8 +106,8 @@ export const indentParagraphCommand: Command<{
|
||||
|
||||
if (
|
||||
matchModels(model, [ParagraphBlockModel]) &&
|
||||
model.type.startsWith('h') &&
|
||||
model.collapsed
|
||||
model.props.type.startsWith('h') &&
|
||||
model.props.collapsed
|
||||
) {
|
||||
const collapsedSiblings = calculateCollapsedSiblings(model);
|
||||
store.moveBlocks([model, ...collapsedSiblings], previousSibling);
|
||||
@@ -125,7 +125,7 @@ export const indentParagraphCommand: Command<{
|
||||
if (
|
||||
nearestHeading &&
|
||||
matchModels(nearestHeading, [ParagraphBlockModel]) &&
|
||||
nearestHeading.collapsed
|
||||
nearestHeading.props.collapsed
|
||||
) {
|
||||
store.updateBlock(nearestHeading, {
|
||||
collapsed: false,
|
||||
@@ -136,7 +136,7 @@ export const indentParagraphCommand: Command<{
|
||||
// update collapsed state of affine list
|
||||
if (
|
||||
matchModels(previousSibling, [ListBlockModel]) &&
|
||||
previousSibling.collapsed
|
||||
previousSibling.props.collapsed
|
||||
) {
|
||||
store.updateBlock(previousSibling, {
|
||||
collapsed: false,
|
||||
|
||||
@@ -37,16 +37,16 @@ export const splitParagraphCommand: Command<
|
||||
// be deleted and not counted as model.text.yText.length.
|
||||
// Example: "`a`[enter]" -> yText[<ContentFormat: Code>, "a", <ContentFormat: Code>]
|
||||
// In this case, we should not split the block.
|
||||
if (model.text.yText.length < splitIndex + splitLength) return;
|
||||
if (model.props.text.yText.length < splitIndex + splitLength) return;
|
||||
|
||||
if (model.children.length > 0 && splitIndex > 0) {
|
||||
store.captureSync();
|
||||
const right = model.text.split(splitIndex, splitLength);
|
||||
const right = model.props.text.split(splitIndex, splitLength);
|
||||
const id = store.addBlock(
|
||||
model.flavour,
|
||||
{
|
||||
text: right,
|
||||
type: model.type,
|
||||
type: model.props.type,
|
||||
},
|
||||
model,
|
||||
0
|
||||
@@ -60,12 +60,12 @@ export const splitParagraphCommand: Command<
|
||||
const index = parent.children.indexOf(model);
|
||||
if (index < 0) return;
|
||||
store.captureSync();
|
||||
const right = model.text.split(splitIndex, splitLength);
|
||||
const right = model.props.text.split(splitIndex, splitLength);
|
||||
const id = store.addBlock(
|
||||
model.flavour,
|
||||
{
|
||||
text: right,
|
||||
type: model.type,
|
||||
type: model.props.type,
|
||||
},
|
||||
parent,
|
||||
index + 1
|
||||
|
||||
@@ -67,7 +67,7 @@ export class ParagraphHeadingIcon extends SignalWatcher(
|
||||
`;
|
||||
|
||||
override render() {
|
||||
const type = this.model.type$.value;
|
||||
const type = this.model.props.type$.value;
|
||||
if (!type.startsWith('h')) return nothing;
|
||||
|
||||
const i = parseInt(type.slice(1));
|
||||
|
||||
@@ -148,20 +148,20 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<
|
||||
|
||||
this.disposables.add(
|
||||
effect(() => {
|
||||
const type = this.model.type$.value;
|
||||
if (!type.startsWith('h') && this.model.collapsed) {
|
||||
this.model.collapsed = false;
|
||||
const type = this.model.props.type$.value;
|
||||
if (!type.startsWith('h') && this.model.props.collapsed) {
|
||||
this.model.props.collapsed = false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.disposables.add(
|
||||
effect(() => {
|
||||
const collapsed = this.model.collapsed$.value;
|
||||
const collapsed = this.model.props.collapsed$.value;
|
||||
this._readonlyCollapsed = collapsed;
|
||||
|
||||
// reset text selection when selected block is collapsed
|
||||
if (this.model.type$.value.startsWith('h') && collapsed) {
|
||||
if (this.model.props.type$.value.startsWith('h') && collapsed) {
|
||||
const collapsedSiblings = this.collapsedSiblings;
|
||||
const textSelection = this.host.selection.find(TextSelection);
|
||||
|
||||
@@ -181,19 +181,19 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<
|
||||
// # 456
|
||||
//
|
||||
// we need to update collapsed state of 123 when 456 converted to text
|
||||
let beforeType = this.model.type$.peek();
|
||||
let beforeType = this.model.props.type$.peek();
|
||||
this.disposables.add(
|
||||
effect(() => {
|
||||
const type = this.model.type$.value;
|
||||
const type = this.model.props.type$.value;
|
||||
if (beforeType !== type && !type.startsWith('h')) {
|
||||
const nearestHeading = getNearestHeadingBefore(this.model);
|
||||
if (
|
||||
nearestHeading &&
|
||||
nearestHeading.type.startsWith('h') &&
|
||||
nearestHeading.collapsed &&
|
||||
nearestHeading.props.type.startsWith('h') &&
|
||||
nearestHeading.props.collapsed &&
|
||||
!this.doc.readonly
|
||||
) {
|
||||
nearestHeading.collapsed = false;
|
||||
nearestHeading.props.collapsed = false;
|
||||
}
|
||||
}
|
||||
beforeType = type;
|
||||
@@ -208,14 +208,14 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<
|
||||
}
|
||||
|
||||
override renderBlock(): TemplateResult<1> {
|
||||
const { type$ } = this.model;
|
||||
const { type$ } = this.model.props;
|
||||
const collapsed = this.doc.readonly
|
||||
? this._readonlyCollapsed
|
||||
: this.model.collapsed;
|
||||
: this.model.props.collapsed;
|
||||
const collapsedSiblings = this.collapsedSiblings;
|
||||
|
||||
let style = html``;
|
||||
if (this.model.type$.value.startsWith('h') && collapsed) {
|
||||
if (this.model.props.type$.value.startsWith('h') && collapsed) {
|
||||
style = html`
|
||||
<style>
|
||||
${collapsedSiblings.map(sibling =>
|
||||
@@ -259,14 +259,14 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<
|
||||
[TOGGLE_BUTTON_PARENT_CLASS]: true,
|
||||
})}
|
||||
>
|
||||
${this.model.type$.value.startsWith('h')
|
||||
${this.model.props.type$.value.startsWith('h')
|
||||
? html`
|
||||
<affine-paragraph-heading-icon
|
||||
.model=${this.model}
|
||||
></affine-paragraph-heading-icon>
|
||||
`
|
||||
: nothing}
|
||||
${this.model.type$.value.startsWith('h') &&
|
||||
${this.model.props.type$.value.startsWith('h') &&
|
||||
collapsedSiblings.length > 0
|
||||
? html`
|
||||
<blocksuite-toggle-button
|
||||
@@ -285,7 +285,7 @@ export class ParagraphBlockComponent extends CaptionedBlockComponent<
|
||||
`
|
||||
: nothing}
|
||||
<rich-text
|
||||
.yText=${this.model.text.yText}
|
||||
.yText=${this.model.props.text.yText}
|
||||
.inlineEventSource=${this.topContenteditableElement ?? nothing}
|
||||
.undoManager=${this.doc.history}
|
||||
.attributesSchema=${this.attributesSchema}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const ParagraphKeymapExtension = KeymapExtension(
|
||||
|
||||
// When deleting at line start of a paragraph block,
|
||||
// firstly switch it to normal text, then delete this empty block.
|
||||
if (model.type !== 'text') {
|
||||
if (model.props.type !== 'text') {
|
||||
// Try to switch to normal text
|
||||
store.captureSync();
|
||||
store.updateBlock(model, { type: 'text' });
|
||||
@@ -91,7 +91,7 @@ export const ParagraphKeymapExtension = KeymapExtension(
|
||||
if (!inlineRange || !inlineEditor) return;
|
||||
const raw = ctx.get('keyboardState').raw;
|
||||
raw.preventDefault();
|
||||
if (model.type === 'quote') {
|
||||
if (model.props.type === 'quote') {
|
||||
store.captureSync();
|
||||
inlineEditor.insertText(inlineRange, '\n');
|
||||
inlineEditor.setInlineRange({
|
||||
@@ -123,10 +123,10 @@ export const ParagraphKeymapExtension = KeymapExtension(
|
||||
if (!inlineRange || !inlineEditor) return;
|
||||
|
||||
const raw = ctx.get('keyboardState').raw;
|
||||
const isEnd = model.text.length === inlineRange.index;
|
||||
const isEnd = model.props.text.length === inlineRange.index;
|
||||
|
||||
if (model.type === 'quote') {
|
||||
const textStr = model.text.toString();
|
||||
if (model.props.type === 'quote') {
|
||||
const textStr = model.props.text.toString();
|
||||
|
||||
/**
|
||||
* If quote block ends with two blank lines, split the block
|
||||
@@ -145,7 +145,7 @@ export const ParagraphKeymapExtension = KeymapExtension(
|
||||
if (isEnd && endWithTwoBlankLines) {
|
||||
raw.preventDefault();
|
||||
store.captureSync();
|
||||
model.text.delete(inlineRange.index - 1, 1);
|
||||
model.props.text.delete(inlineRange.index - 1, 1);
|
||||
std.command.chain().pipe(addParagraphCommand).run();
|
||||
return true;
|
||||
}
|
||||
@@ -158,17 +158,17 @@ export const ParagraphKeymapExtension = KeymapExtension(
|
||||
return true;
|
||||
}
|
||||
|
||||
if (model.type.startsWith('h') && model.collapsed) {
|
||||
if (model.props.type.startsWith('h') && model.props.collapsed) {
|
||||
const parent = store.getParent(model);
|
||||
if (!parent) return true;
|
||||
const index = parent.children.indexOf(model);
|
||||
if (index === -1) return true;
|
||||
const collapsedSiblings = calculateCollapsedSiblings(model);
|
||||
|
||||
const rightText = model.text.split(inlineRange.index);
|
||||
const rightText = model.props.text.split(inlineRange.index);
|
||||
const newId = store.addBlock(
|
||||
model.flavour,
|
||||
{ type: model.type, text: rightText },
|
||||
{ type: model.props.type, text: rightText },
|
||||
parent,
|
||||
index + collapsedSiblings.length + 1
|
||||
);
|
||||
|
||||
@@ -8,7 +8,7 @@ export class ParagraphBlockService extends BlockService {
|
||||
static override readonly flavour = ParagraphBlockSchema.model.flavour;
|
||||
|
||||
placeholderGenerator: (model: ParagraphBlockModel) => string = model => {
|
||||
if (model.type === 'text') {
|
||||
if (model.props.type === 'text') {
|
||||
return "Type '/' for commands";
|
||||
}
|
||||
|
||||
@@ -21,6 +21,6 @@ export class ParagraphBlockService extends BlockService {
|
||||
h6: 'Heading 6',
|
||||
quote: '',
|
||||
};
|
||||
return placeholders[model.type];
|
||||
return placeholders[model.props.type];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export function forwardDelete(std: BlockStdScope) {
|
||||
matchModels(model.parent, [CalloutBlockModel])
|
||||
)
|
||||
return;
|
||||
const isEnd = isCollapsed && text.from.index === model.text.length;
|
||||
const isEnd = isCollapsed && text.from.index === model.props.text.length;
|
||||
if (!isEnd) return;
|
||||
const parent = store.getParent(model);
|
||||
if (!parent) return;
|
||||
@@ -57,7 +57,7 @@ export function forwardDelete(std: BlockStdScope) {
|
||||
}
|
||||
|
||||
if (matchModels(nextSibling, [ParagraphBlockModel, ListBlockModel])) {
|
||||
model.text.join(nextSibling.text);
|
||||
model.props.text.join(nextSibling.props.text);
|
||||
if (nextSibling.children) {
|
||||
const parent = store.getParent(nextSibling);
|
||||
if (!parent) return false;
|
||||
@@ -70,7 +70,7 @@ export function forwardDelete(std: BlockStdScope) {
|
||||
|
||||
const nextBlock = getNextContentBlock(host, model);
|
||||
if (nextBlock?.text) {
|
||||
model.text.join(nextBlock.text);
|
||||
model.props.text.join(nextBlock.text);
|
||||
if (nextBlock.children) {
|
||||
const parent = store.getParent(nextBlock);
|
||||
if (!parent) return false;
|
||||
|
||||
@@ -72,8 +72,8 @@ export function mergeWithPrev(editorHost: EditorHost, model: BlockModel) {
|
||||
)
|
||||
return false;
|
||||
|
||||
const lengthBeforeJoin = prevBlock.text?.length ?? 0;
|
||||
prevBlock.text.join(model.text as Text);
|
||||
const lengthBeforeJoin = prevBlock.props.text?.length ?? 0;
|
||||
prevBlock.props.text.join(model.text as Text);
|
||||
doc.deleteBlock(model, {
|
||||
bringChildrenTo: parent,
|
||||
});
|
||||
@@ -138,7 +138,7 @@ function handleNoPreviousSibling(editorHost: EditorHost, model: ExtendedModel) {
|
||||
}
|
||||
|
||||
const rootModel = model.doc.root as RootBlockModel;
|
||||
const title = rootModel.title;
|
||||
const title = rootModel.props.title;
|
||||
|
||||
doc.captureSync();
|
||||
let textLength = 0;
|
||||
|
||||
Reference in New Issue
Block a user