refactor: extract block dnd handle predicate
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
# Batch X Worker A: 5-29 block DnD DOM boundary readonly audit
|
||||||
|
|
||||||
|
## Role
|
||||||
|
|
||||||
|
You are a leaf Reasonix coding worker. Do not spawn any other agent, runner, ACP process, Claude Code, Codex, Hermes, or Reasonix. Do not create, delete, or modify worktrees. Do not create new `.codex/reasonix-tasks/*.md` files.
|
||||||
|
|
||||||
|
## Project
|
||||||
|
|
||||||
|
Project root for this run:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/mnt/Data1T/mnote-worktrees/0525-x-worker-a-5-29-dnd-dom-readonly
|
||||||
|
```
|
||||||
|
|
||||||
|
## Task
|
||||||
|
|
||||||
|
Perform a read-only audit for the next small 5-29 editor runtime extraction around block drag-and-drop DOM helpers.
|
||||||
|
|
||||||
|
Focus only on these current symbols:
|
||||||
|
|
||||||
|
- `drop_indicator_from_target` in `rust/spikes/leptos-tiptap-spike/src/lib.rs`
|
||||||
|
- `drop_indicator_from_point` in `rust/spikes/leptos-tiptap-spike/src/lib.rs`
|
||||||
|
- `hovered_block_from_target` in `rust/spikes/leptos-tiptap-spike/src/lib.rs`
|
||||||
|
- helper dependencies used by those functions, such as `target_element`, `direct_block_from_element`, `top_level_block_index`, `block_state_from_index`, `editor_root_element`, `editor_stage_element`, and `HANDLE_SHELL_SELECTOR`
|
||||||
|
- existing `editor_runtime/block_dnd.rs`
|
||||||
|
|
||||||
|
## Required output
|
||||||
|
|
||||||
|
Write a handoff that answers:
|
||||||
|
|
||||||
|
1. Which exact helper, if any, can be moved next into `editor_runtime/block_dnd.rs` without moving Leptos signals, event listeners, or block reorder behavior?
|
||||||
|
2. Which functions must stay in `lib.rs` for now, and why?
|
||||||
|
3. What is the smallest safe implementation diff Codex should make next?
|
||||||
|
4. What commands should Codex run after that diff?
|
||||||
|
5. What browser smoke, if any, is needed to prove behavior did not regress?
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- Read-only only. Do not edit source files, design docs, task files, generated wasm/js, or tests.
|
||||||
|
- Do not run `cargo build`, `cargo check`, `wasm-bindgen`, browser tests, or dev servers.
|
||||||
|
- You may run read-only commands such as `rg`, `sed`, `git status`, `git diff --stat`, and CodeGraph if available.
|
||||||
|
- If you find the task needs implementation, report the proposed patch in prose only.
|
||||||
|
- Keep the result narrow. Do not propose a broad drag-and-drop rewrite.
|
||||||
|
|
||||||
|
## Acceptance contract
|
||||||
|
|
||||||
|
The run is acceptable only if:
|
||||||
|
|
||||||
|
- Worktree diff is empty.
|
||||||
|
- `process-handoff.md` and `process-handoff.json` exist.
|
||||||
|
- The handoff includes the five required answers above.
|
||||||
|
- The handoff does not claim code was changed or tests were run.
|
||||||
@@ -206,3 +206,9 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据
|
|||||||
- 修改:`rust/spikes/leptos-tiptap-spike/src/lib.rs`、generated island wasm。
|
- 修改:`rust/spikes/leptos-tiptap-spike/src/lib.rs`、generated island wasm。
|
||||||
- 当前执行约束同步修正:`3-20` / `5-29` checklist 均保持“当前 goal 下每批最多 2 个 worker”。
|
- 当前执行约束同步修正:`3-20` / `5-29` checklist 均保持“当前 goal 下每批最多 2 个 worker”。
|
||||||
- 已验证:`git diff --check`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task489-block-menu-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task488-local-attachment-link-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`、`codegraph sync .`、`codegraph status . --json` pending 0。
|
- 已验证:`git diff --check`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task489-block-menu-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task488-local-attachment-link-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`、`codegraph sync .`、`codegraph status . --json` pending 0。
|
||||||
|
- 2026-05-25:Batch X 计划只派发 1 个只读 Reasonix worker 审计 block DnD DOM 边界,任务书 `.codex/reasonix-tasks/2026-05-25-batch-x-worker-a-5-29-dnd-dom-readonly.md`,worktree `/mnt/Data1T/mnote-worktrees/0525-x-worker-a-5-29-dnd-dom-readonly`。
|
||||||
|
- 派发异常:启动本只读 worker 后,又出现未由主控批准的 Worker A/B/C/D runner 与 ACP 进程,超过当前 goal 的“每批最多 2 个 worker”;主控已终止全部 `reasonix-coding-runner` / `reasonix acp` / `reasonix/dist/cli/index.js acp` 进程,本批不采纳任何 Reasonix 输出。
|
||||||
|
- Codex 主控改为本地最小机械切片:`editor_runtime/block_dnd.rs` 新增 `element_within_handle_shell(element, handle_selector)`,只封装 handle-shell DOM predicate;`lib.rs` 的 `hovered_block_from_target`、editor stage click / mousemove / dragover 调用点改为委托该 helper。
|
||||||
|
- 未迁:`hovered_block_from_target`、`drop_indicator_from_target`、`drop_indicator_from_point`、拖拽 listener、block reorder 行为和 DOM -> block 状态解析链仍留在 `lib.rs`。
|
||||||
|
- 修改:`rust/spikes/leptos-tiptap-spike/src/editor_runtime/block_dnd.rs`、`rust/spikes/leptos-tiptap-spike/src/lib.rs`。
|
||||||
|
- 已验证:`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task489-block-menu-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task488-local-attachment-link-delete-undo-smoke.js`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3001 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`、`git diff --check`、`codegraph sync .`、`codegraph status . --json` pending 0。
|
||||||
|
|||||||
+1
-1
@@ -1284,7 +1284,7 @@ function __wbg_get_imports() {
|
|||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
__wbindgen_cast_0000000000000006: function(arg0, arg1) {
|
||||||
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 856, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("KeyboardEvent")], shim_idx: 886, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
|
||||||
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hd90af689bc3e71bf);
|
const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hd90af689bc3e71bf);
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -4,7 +4,7 @@
|
|||||||
//! 也不分发 editor command;调用方负责保留编辑器状态编排。
|
//! 也不分发 editor command;调用方负责保留编辑器状态编排。
|
||||||
|
|
||||||
use crate::editor_runtime::block_hover_state::{DropIndicatorState, DropPlacement};
|
use crate::editor_runtime::block_hover_state::{DropIndicatorState, DropPlacement};
|
||||||
use web_sys::{window, EventTarget};
|
use web_sys::{window, Element, EventTarget};
|
||||||
|
|
||||||
pub(crate) struct HandleCorridorGeometry {
|
pub(crate) struct HandleCorridorGeometry {
|
||||||
pub(crate) stage_left: f64,
|
pub(crate) stage_left: f64,
|
||||||
@@ -81,6 +81,10 @@ pub(crate) fn event_target_from_point(client_x: i32, client_y: i32) -> Option<Ev
|
|||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn element_within_handle_shell(element: &Element, handle_selector: &str) -> bool {
|
||||||
|
element.closest(handle_selector).ok().flatten().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ use web_sys::{
|
|||||||
|
|
||||||
use editor_runtime::attachment_upload::dispatch_editor_upload_request;
|
use editor_runtime::attachment_upload::dispatch_editor_upload_request;
|
||||||
use editor_runtime::block_dnd::{
|
use editor_runtime::block_dnd::{
|
||||||
drop_indicator_from_geometry, event_target_from_point, pointer_in_handle_corridor_geometry,
|
drop_indicator_from_geometry, element_within_handle_shell, event_target_from_point,
|
||||||
HandleCorridorGeometry,
|
pointer_in_handle_corridor_geometry, HandleCorridorGeometry,
|
||||||
};
|
};
|
||||||
use editor_runtime::block_menu_overlay;
|
use editor_runtime::block_menu_overlay;
|
||||||
use editor_runtime::block_menu_legacy_html::{
|
use editor_runtime::block_menu_legacy_html::{
|
||||||
@@ -4914,12 +4914,7 @@ fn hovered_block_from_target(target: web_sys::EventTarget) -> Option<HoveredBloc
|
|||||||
let root = editor_root_element()?;
|
let root = editor_root_element()?;
|
||||||
let element = target_element(target)?;
|
let element = target_element(target)?;
|
||||||
|
|
||||||
if element
|
if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) {
|
||||||
.closest(HANDLE_SHELL_SELECTOR)
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8103,7 +8098,7 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(element) = target_element(target.clone()) {
|
if let Some(element) = target_element(target.clone()) {
|
||||||
if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() {
|
if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8155,7 +8150,7 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(element) = target_element(target.clone()) {
|
if let Some(element) = target_element(target.clone()) {
|
||||||
if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() {
|
if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8208,7 +8203,7 @@ fn App(mount_options: MountOptions) -> impl IntoView {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(element) = target_element(target.clone()) {
|
if let Some(element) = target_element(target.clone()) {
|
||||||
if element.closest(HANDLE_SHELL_SELECTOR).ok().flatten().is_some() {
|
if element_within_handle_shell(&element, HANDLE_SHELL_SELECTOR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user