${isGfx
@@ -236,6 +290,9 @@ export class AffineDragHandleWidget extends WidgetComponent {
@query('.affine-drag-handle-grabber')
accessor dragHandleGrabber!: HTMLDivElement;
+ @query('.affine-add-block-widget-container')
+ accessor addBlockWidgetContainer!: HTMLDivElement;
+
@state()
accessor dragHoverRect: {
width: number;
diff --git a/blocksuite/affine/widgets/drag-handle/src/effects.ts b/blocksuite/affine/widgets/drag-handle/src/effects.ts
index 70330667ba..cd02b7b335 100644
--- a/blocksuite/affine/widgets/drag-handle/src/effects.ts
+++ b/blocksuite/affine/widgets/drag-handle/src/effects.ts
@@ -1,12 +1,14 @@
+import { AffineAddBlockWidget } from './components/add-block-widget';
import {
EDGELESS_DND_PREVIEW_ELEMENT,
EdgelessDndPreviewElement,
} from './components/edgeless-preview/preview';
-import { AFFINE_DRAG_HANDLE_WIDGET } from './consts';
+import { AFFINE_ADD_BLOCK_WIDGET, AFFINE_DRAG_HANDLE_WIDGET } from './consts';
import { AffineDragHandleWidget } from './drag-handle';
export function effects() {
customElements.define(AFFINE_DRAG_HANDLE_WIDGET, AffineDragHandleWidget);
+ customElements.define(AFFINE_ADD_BLOCK_WIDGET, AffineAddBlockWidget);
customElements.define(
EDGELESS_DND_PREVIEW_ELEMENT,
EdgelessDndPreviewElement
diff --git a/blocksuite/affine/widgets/drag-handle/src/styles.ts b/blocksuite/affine/widgets/drag-handle/src/styles.ts
index 7d61fb3b39..b4d62ada08 100644
--- a/blocksuite/affine/widgets/drag-handle/src/styles.ts
+++ b/blocksuite/affine/widgets/drag-handle/src/styles.ts
@@ -1,7 +1,10 @@
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import { css } from 'lit';
-import { DRAG_HANDLE_CONTAINER_WIDTH } from './config.js';
+import {
+ ADD_BLOCK_WIDGET_WIDTH,
+ DRAG_HANDLE_CONTAINER_WIDTH,
+} from './config.js';
export const styles = css`
.affine-drag-handle-widget {
@@ -10,6 +13,20 @@ export const styles = css`
left: 0;
top: 0;
contain: size layout;
+ pointer-events: none;
+ }
+
+ .affine-add-block-widget-container {
+ top: 0;
+ left: 0;
+ position: absolute;
+ display: flex;
+ justify-content: center;
+ width: ${ADD_BLOCK_WIDGET_WIDTH}px;
+ min-height: 12px;
+ pointer-events: none;
+ user-select: none;
+ box-sizing: border-box;
}
.affine-drag-handle-container {
diff --git a/blocksuite/affine/widgets/drag-handle/src/watchers/pointer-event-watcher.ts b/blocksuite/affine/widgets/drag-handle/src/watchers/pointer-event-watcher.ts
index cc2059627c..bf1a072434 100644
--- a/blocksuite/affine/widgets/drag-handle/src/watchers/pointer-event-watcher.ts
+++ b/blocksuite/affine/widgets/drag-handle/src/watchers/pointer-event-watcher.ts
@@ -12,6 +12,7 @@ import { computed } from '@preact/signals-core';
import throttle from 'lodash-es/throttle';
import {
+ ADD_BLOCK_WIDGET_WIDTH,
DRAG_HANDLE_CONTAINER_WIDTH,
DRAG_HANDLE_GRABBER_BORDER_RADIUS,
DRAG_HANDLE_GRABBER_HEIGHT,
@@ -199,6 +200,7 @@ export class PointerEventWatcher {
!this.widget.isDragHandleHovered
) {
this.showDragHandleOnHoverBlock();
+ this.widget.showAddBlockWidget = true;
this._lastHoveredBlockId = this.widget.anchorBlockId.peek();
}
};
@@ -251,8 +253,13 @@ export class PointerEventWatcher {
return;
}
- // When pointer on drag handle, should do nothing
- if (element.closest('.affine-drag-handle-container')) return;
+ // When pointer on drag handle or add-block widget, should do nothing
+ if (
+ element.closest('.affine-drag-handle-container') ||
+ element.closest('.affine-add-block-widget-container')
+ ) {
+ return;
+ }
if (!this.widget.rootComponent) return;
@@ -317,6 +324,7 @@ export class PointerEventWatcher {
const container = this.widget.dragHandleContainer;
const grabber = this.widget.dragHandleGrabber;
+ const addBlockWidgetContainer = this.widget.addBlockWidgetContainer;
if (!container || !grabber) return;
this.widget.activeDragHandle = 'block';
@@ -336,6 +344,21 @@ export class PointerEventWatcher {
Object.assign(container.style, containerStyle);
container.style.display = 'flex';
+
+ // Position the add-block widget beside the drag handle, aligned to the first line.
+ if (
+ addBlockWidgetContainer &&
+ this.widget.showAddBlockWidget &&
+ this.widget.mode === 'page'
+ ) {
+ const posTop = this._getTopWithBlockComponent(block);
+ addBlockWidgetContainer.style.left = `${draggingAreaRect.left - ADD_BLOCK_WIDGET_WIDTH}px`;
+ addBlockWidgetContainer.style.top = `${posTop}px`;
+ addBlockWidgetContainer.style.height = 'auto';
+ addBlockWidgetContainer.style.display = 'flex';
+ } else if (addBlockWidgetContainer) {
+ addBlockWidgetContainer.style.display = 'none';
+ }
};
if (isBlockIdEqual(block.blockId, this._lastShowedBlock?.id)) {
diff --git a/blocksuite/affine/widgets/drag-handle/tsconfig.json b/blocksuite/affine/widgets/drag-handle/tsconfig.json
index 89887c9a74..b26acff316 100644
--- a/blocksuite/affine/widgets/drag-handle/tsconfig.json
+++ b/blocksuite/affine/widgets/drag-handle/tsconfig.json
@@ -16,6 +16,7 @@
{ "path": "../../components" },
{ "path": "../../ext-loader" },
{ "path": "../../model" },
+ { "path": "../../rich-text" },
{ "path": "../../shared" },
{ "path": "../../../framework/global" },
{ "path": "../../../framework/std" },
diff --git a/tools/utils/src/workspace.gen.ts b/tools/utils/src/workspace.gen.ts
index 52b7937595..053fbe2004 100644
--- a/tools/utils/src/workspace.gen.ts
+++ b/tools/utils/src/workspace.gen.ts
@@ -828,6 +828,7 @@ export const PackageList = [
'blocksuite/affine/components',
'blocksuite/affine/ext-loader',
'blocksuite/affine/model',
+ 'blocksuite/affine/rich-text',
'blocksuite/affine/shared',
'blocksuite/framework/global',
'blocksuite/framework/std',
diff --git a/yarn.lock b/yarn.lock
index bbe350fb5c..75d57ed08f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2932,6 +2932,7 @@ __metadata:
"@blocksuite/affine-components": "workspace:*"
"@blocksuite/affine-ext-loader": "workspace:*"
"@blocksuite/affine-model": "workspace:*"
+ "@blocksuite/affine-rich-text": "workspace:*"
"@blocksuite/affine-shared": "workspace:*"
"@blocksuite/global": "workspace:*"
"@blocksuite/icons": "npm:^2.2.17"