Skip to content

Commit

Permalink
fix(core): fix menu not close when click outside (#9535)
Browse files Browse the repository at this point in the history
  • Loading branch information
EYHN committed Jan 10, 2025
1 parent 9882af5 commit 18ff750
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 36 deletions.
54 changes: 50 additions & 4 deletions blocksuite/blocks/src/root-block/page/page-root-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PageViewportService } from '@blocksuite/affine-shared/services';
import type { Viewport } from '@blocksuite/affine-shared/types';
import {
focusTitle,
getClosestBlockComponentByPoint,
getDocTitleInlineEditor,
getScrollContainer,
matchFlavours,
Expand All @@ -15,6 +16,7 @@ import {
BlockSelection,
TextSelection,
} from '@blocksuite/block-std';
import { Point } from '@blocksuite/global/utils';
import type { BlockModel, Text } from '@blocksuite/store';
import { css, html } from 'lit';
import { query } from 'lit/decorators.js';
Expand Down Expand Up @@ -303,7 +305,7 @@ export class PageRootBlockComponent extends BlockComponent<
},
});

this.handleEvent('click', ctx => {
this.handleEvent('pointerDown', ctx => {
const event = ctx.get('pointerState');
if (
event.raw.target !== this &&
Expand All @@ -312,7 +314,6 @@ export class PageRootBlockComponent extends BlockComponent<
) {
return;
}

const { paddingLeft, paddingRight } = window.getComputedStyle(
this.rootElementContainer
);
Expand All @@ -325,8 +326,53 @@ export class PageRootBlockComponent extends BlockComponent<
parseFloat(paddingLeft),
parseFloat(paddingRight)
);
if (isClickOnBlankArea) {
this.host.selection.clear(['block']);
if (!isClickOnBlankArea) {
return;
}

const hostRect = this.host.getBoundingClientRect();
const x = hostRect.width / 2 + hostRect.left;
const point = new Point(x, event.raw.clientY);
const side = event.raw.clientX < x ? 'left' : 'right';

const nearestBlock = getClosestBlockComponentByPoint(point);
event.raw.preventDefault();
if (nearestBlock) {
const text = nearestBlock.model.text;
if (text) {
this.host.selection.setGroup('note', [
this.host.selection.create(TextSelection, {
from: {
blockId: nearestBlock.model.id,
index: side === 'left' ? 0 : text.length,
length: 0,
},
to: null,
}),
]);
} else {
this.host.selection.setGroup('note', [
this.host.selection.create(BlockSelection, {
blockId: nearestBlock.model.id,
}),
]);
}
} else {
if (this.host.selection.find(BlockSelection)) {
this.host.selection.clear(['block']);
}
}

return;
});

this.handleEvent('click', ctx => {
const event = ctx.get('pointerState');
if (
event.raw.target !== this &&
event.raw.target !== this.viewportElement &&
event.raw.target !== this.rootElementContainer
) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ export class AffinePageDraggingAreaWidget extends WidgetComponent<
const container = this.block.rootElementContainer;
if (!container) return;

const currentFocus = document.activeElement;
if (!container.contains(currentFocus)) {
return;
}

const containerRect = container.getBoundingClientRect();
const containerStyles = window.getComputedStyle(container);
const paddingLeft = parseFloat(containerStyles.paddingLeft);
Expand Down
1 change: 0 additions & 1 deletion blocksuite/framework/block-std/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ export * from './scope/index.js';
export * from './selection/index.js';
export * from './service/index.js';
export * from './spec/index.js';
export * from './utils/index.js';
export * from './view/index.js';
14 changes: 14 additions & 0 deletions blocksuite/framework/block-std/src/range/active.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Check if the active element is in the editor host.
* TODO(@mirone): this is a trade-off, we need to use separate awareness store for every store to make sure the selection is isolated.
*
* @param editorHost - The editor host element.
* @returns Whether the active element is in the editor host.
*/
export function isActiveInEditor(editorHost: HTMLElement) {
const currentActiveElement = document.activeElement;
if (!currentActiveElement) return false;
const currentEditorHost = currentActiveElement?.closest('editor-host');
if (!currentEditorHost) return false;
return currentEditorHost === editorHost;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { signal } from '@preact/signals-core';

import { TextSelection } from '../selection/index.js';
import type { BlockComponent } from '../view/element/block-component.js';
import { isActiveInEditor } from './active.js';

export const getInlineRangeProvider: (
element: BlockComponent
Expand Down Expand Up @@ -87,6 +88,8 @@ export const getInlineRangeProvider: (

editorHost.disposables.add(
selectionManager.slots.changed.on(selections => {
if (!isActiveInEditor(editorHost)) return;

const textSelection = selections.find(s => s.type === 'text') as
| TextSelection
| undefined;
Expand Down
3 changes: 3 additions & 0 deletions blocksuite/framework/block-std/src/range/range-binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { BaseSelection, BlockModel } from '@blocksuite/store';
import { TextSelection } from '../selection/index.js';
import type { BlockComponent } from '../view/element/block-component.js';
import { BLOCK_ID_ATTR } from '../view/index.js';
import { isActiveInEditor } from './active.js';
import { RANGE_SYNC_EXCLUDE_ATTR } from './consts.js';
import type { RangeManager } from './range-manager.js';

Expand Down Expand Up @@ -169,6 +170,7 @@ export class RangeBinding {
private readonly _onNativeSelectionChanged = async () => {
if (this.isComposing) return;
if (!this.host) return; // Unstable when switching views, card <-> embed
if (!isActiveInEditor(this.host)) return;

await this.host.updateComplete;

Expand Down Expand Up @@ -247,6 +249,7 @@ export class RangeBinding {
};

private readonly _onStdSelectionChanged = (selections: BaseSelection[]) => {
// TODO(@mirone): this is a trade-off, we need to use separate awareness store for every store to make sure the selection is isolated.
const closestHost = document.activeElement?.closest('editor-host');
if (closestHost && closestHost !== this.host) return;

Expand Down
1 change: 0 additions & 1 deletion blocksuite/framework/block-std/src/utils/index.ts

This file was deleted.

30 changes: 0 additions & 30 deletions blocksuite/framework/block-std/src/utils/path-finder.ts

This file was deleted.

0 comments on commit 18ff750

Please sign in to comment.