feat(editor): simple table block (#9740)

close: BS-2122, BS-2125, BS-2124, BS-2420, PD-2073, BS-2126, BS-2469, BS-2470, BS-2478, BS-2471
This commit is contained in:
zzj3720
2025-01-24 10:07:57 +00:00
parent 3f4311ff1c
commit 5a5779c05a
61 changed files with 3577 additions and 381 deletions

View File

@@ -439,6 +439,8 @@ export const BUILT_IN_GROUPS: MenuItemGroup<FormatBarContext>[] = [
];
export function toolbarMoreButton(toolbar: AffineFormatBarWidget) {
const richText = getRichText();
if (richText?.dataset.disableAskAi !== undefined) return null;
const context = new FormatBarContext(toolbar);
const actions = renderGroups(toolbar.moreGroups, context);
@@ -455,3 +457,15 @@ export function toolbarMoreButton(toolbar: AffineFormatBarWidget) {
</editor-menu-button>
`;
}
const getRichText = () => {
const selection = getSelection();
if (!selection) return null;
if (selection.rangeCount === 0) return null;
const range = selection.getRangeAt(0);
const commonAncestorContainer =
range.commonAncestorContainer instanceof Element
? range.commonAncestorContainer
: range.commonAncestorContainer.parentElement;
if (!commonAncestorContainer) return null;
return commonAncestorContainer.closest('rich-text');
};

View File

@@ -1,7 +1,8 @@
import { DatabaseSelection } from '@blocksuite/affine-block-database';
import { HoverController } from '@blocksuite/affine-components/hover';
import type { RichText } from '@blocksuite/affine-components/rich-text';
import { isFormatSupported } from '@blocksuite/affine-components/rich-text';
import {
isFormatSupported,
type RichText,
} from '@blocksuite/affine-components/rich-text';
import {
cloneGroups,
getMoreMenuConfig,
@@ -205,34 +206,20 @@ export class AffineFormatBarWidget extends WidgetComponent {
);
this.disposables.addFromEvent(document, 'selectionchange', () => {
if (!this.host.event.active) return;
const databaseSelection = this.host.selection.find(DatabaseSelection);
if (!databaseSelection) {
return;
}
const reset = () => {
this.reset();
this.requestUpdate();
};
const viewSelection = databaseSelection.viewSelection;
// check table selection
if (
viewSelection.type === 'table' &&
(viewSelection.selectionType !== 'area' || !viewSelection.isEditing)
)
return reset();
// check kanban selection
if (
(viewSelection.type === 'kanban' &&
viewSelection.selectionType !== 'cell') ||
!viewSelection.isEditing
)
return reset();
const range = this.nativeRange;
if (!range || range.collapsed) return reset();
if (!range) return;
const container =
range.commonAncestorContainer instanceof Element
? range.commonAncestorContainer
: range.commonAncestorContainer.parentElement;
if (!container) return;
const notBlockText = container.closest('rich-text')?.dataset.notBlockText;
if (notBlockText == null) return;
if (range.collapsed) return reset();
this._displayType = 'native';
this.requestUpdate();
});
@@ -551,12 +538,16 @@ export class AffineFormatBarWidget extends WidgetComponent {
}
const items = ConfigRenderer(this);
const moreButton = toolbarMoreButton(this);
return html`
<editor-toolbar class="${AFFINE_FORMAT_BAR_WIDGET}">
${items}
<editor-toolbar-separator></editor-toolbar-separator>
${toolbarMoreButton(this)}
${moreButton
? html`
<editor-toolbar-separator></editor-toolbar-separator>
${moreButton}
`
: nothing}
</editor-toolbar>
`;
}

View File

@@ -246,6 +246,23 @@ export const defaultSlashMenuConfig: SlashMenuConfig = {
// ---------------------------------------------------------
{ groupName: 'Content & Media' },
{
name: 'Table',
description: 'Create a table block.',
icon: DatabaseTableViewIcon20,
tooltip: slashMenuToolTips['Table View'],
showWhen: ({ model }) => !insideEdgelessText(model),
action: ({ rootComponent }) => {
rootComponent.std.command
.chain()
.getSelectedModels()
.insertTableBlock({
place: 'after',
removeEmptyLine: true,
})
.run();
},
},
{
name: 'Image',
description: 'Insert an image.',