mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-05-08 22:07:32 +08:00
### Problem ●In edgeless mode, after clicking and moving in a connector's label editor, if the label editor has empty content at the end of the editing, the label editor for that connector can not be triggered again. ●The following video demonstrates this issue: https://github.com/user-attachments/assets/8d300720-5ed8-4f9c-90fa-fbf059417ff8 ### Root Cause **Direct cause** ●The `labelOffset` property is **stashed** at drag-start, but is **not properly popped** afterward. As a result, when `mountConnectorLabelEditor()` is called the second time (`packages/affine/gfx/connector/src/text/edgeless-connector-label-editor.ts`), `connector.labelOffset` returns `undefined` instead of the default value provided by the `@field` decorator. **Why moving after clicking incorrectly triggers a drag-start** ●The root issue lies in the interaction between click and drag event handling. Here's the actual flow: 1.`dispatcher.add('click', () => true)` is registered in `EdgelessConnectorLabelEditor`. 2.On pointer-down, both `ClickController` and `DragController` receive the event. 3.On pointer-up, `ClickController` fires a **synthetic click**. The handler from step 1 returns `true`, triggering `context.get('defaultState').event.stopPropagation()`. 4.This prevents the native pointer-up from bubbling to `DragController`. However, a subsequent pointer-move still causes `DragController` to **incorrectly synthesize a drag-start + drag-move**. **Fundamental root cause** ●The line `context.get('defaultState').event.stopPropagation()` in `UIEventDispatcher::run()` stops **both** synthetic and native event bubbling. It should only stop synthetic event propagation. ●The synthetic event bubbling stopping is already properly handled by the immediate `return` statement on the next line, because the runners are prepared in strict order (current → parent → grandparent → ... → global) by `UIEventDispatcher::_getEventScope()` and then **executed sequentially** in `UIEventDispatcher::run()`. ### Fix ●Since I cannot rule out that other (current or future) event handlers may rely on this native event bubbling stopping behavior, I chose not to remove the `context.get('defaultState').event.stopPropagation()` line completely. Instead, I added a new constant and now skip `stopPropagation()` **only** for the following synthetic events: ```ts const syntheticEventNames = new Set(['click', 'doubleClick', 'tripleClick']); ``` These currently represent all known synthetic click events triggered from pointer-up. ### After ●The video below shows the behavior after this fix. https://github.com/user-attachments/assets/65b8a3ce-0767-4d80-986b-8bc6081ddd4c
BlockSuite Framework
Here are the vanilla framework packages in BlockSuite.