refactor: extract table toolbar view

This commit is contained in:
lix-2026
2026-05-25 20:40:55 +08:00
parent f8decfebd6
commit def143ea24
6 changed files with 418 additions and 277 deletions
+28 -266
View File
@@ -58,23 +58,19 @@ use editor_runtime::mindmap_node_view::{
};
use editor_runtime::overlays::{
clamp_overlay_anchor,
close_editor_floating_overlays_if_escape, current_table_overlay_anchor,
close_editor_floating_overlays_if_escape,
image_element_from_target, image_toolbar_anchor_from_image, open_block_menu_overlay,
open_image_toolbar_overlay, open_slash_menu_overlay, selection_bounding_rect,
should_auto_close_toolbar_overlays, sync_overlays_on_selection_change, table_col_aux_style,
table_overlay_anchor_from_table, table_row_aux_style, table_selection_overlay_style,
toolbar_overlay_locked, try_sync_editor_overlay_state, FloatingToolbarAnchor, ImageToolbarAnchor,
TableOverlayAnchor, TableSelectionKind, TableSelectionOverlayState,
should_auto_close_toolbar_overlays, sync_overlays_on_selection_change,
table_overlay_anchor_from_table, toolbar_overlay_locked, try_sync_editor_overlay_state,
FloatingToolbarAnchor, ImageToolbarAnchor, TableOverlayAnchor, TableSelectionOverlayState,
};
use editor_runtime::persistence::{
load_persisted_document, normalize_identity_value, persist_document_state,
persisted_document_identity, PersistedDocumentIdentity,
};
use editor_runtime::slash_actions::{SlashActionKind, SLASH_ACTIONS};
use editor_runtime::table_commands::{
run_table_option_action, run_table_toolbar_action, table_option_checked, TableToolbarAction,
TABLE_OPTION_ACTIONS, TABLE_TOOLBAR_ACTIONS,
};
use editor_runtime::table_toolbar_view::table_toolbar_view;
#[cfg(test)]
use editor_runtime::persistence::persisted_document_storage_key;
@@ -6078,263 +6074,29 @@ fn App(mount_options: MountOptions) -> impl IntoView {
set_hovered_block.set(None);
}
>
{move || {
if !table_toolbar_open.get() || slash_open.get() || block_menu_open.get() || dragging_block_index.get().is_some() {
return ().into_any();
}
let Some(anchor) = table_overlay_anchor.get() else {
return ().into_any();
};
let controls_style = format!(
"left:{:.1}px;top:{:.1}px;width:{:.1}px;height:{:.1}px;",
anchor.left,
anchor.top,
anchor.width,
anchor.height
);
view! {
<div
class="table-controls"
data-testid="mnote-leptos-tiptap-table-controls"
style=controls_style
>
{move || {
table_selection_overlay.get().map(|selection| {
view! {
<div
class="table-selection-overlay"
data-testid="table-selection-overlay"
data-selection-kind=selection.kind.id()
data-selection-index=selection.index.to_string()
style=table_selection_overlay_style(&anchor, &selection)
></div>
}
}).into_any()
}}
{(0..anchor.rows).map(|index| {
let active = table_selection_overlay.get()
.map(|selection| selection.kind == TableSelectionKind::Row && selection.index == index)
.unwrap_or(false);
view! {
<button
type="button"
class="table-aux-btn table-row-aux"
data-testid=format!("table-row-aux-{index}")
data-active=active.to_string()
style=table_row_aux_style(&anchor, index)
title="点击插入一行"
aria-label="点击插入一行"
on:mousedown=move |event: MouseEvent| {
event.prevent_default();
event.stop_propagation();
}
on:click=move |event: MouseEvent| {
event.prevent_default();
event.stop_propagation();
set_table_toolbar_open.set(true);
set_table_options_open.set(false);
match run_table_toolbar_action(editor, TableToolbarAction::AddRowAfter) {
Ok(message) => {
sync_persisted_editor_command(
editor,
&runtime_persisted_identity(document_id, workspace_id),
set_dirty_count,
set_html_output,
set_document_json,
set_json_output,
title,
set_command_feedback,
message,
);
if let Err(err) = editor.select_table_row(index as u32) {
set_command_feedback.set(format!("行已插入,但表格行选区同步失败:{err}"));
}
set_table_overlay_anchor.set(current_table_overlay_anchor());
set_table_selection_overlay.set(Some(TableSelectionOverlayState { kind: TableSelectionKind::Row, index }));
}
Err(err) => set_command_feedback.set(err),
}
}
>"+"</button>
}
}).collect_view()}
{(0..anchor.cols).map(|index| {
let active = table_selection_overlay.get()
.map(|selection| selection.kind == TableSelectionKind::Column && selection.index == index)
.unwrap_or(false);
view! {
<button
type="button"
class="table-aux-btn table-col-aux"
data-testid=format!("table-col-aux-{index}")
data-active=active.to_string()
style=table_col_aux_style(&anchor, index)
title="点击插入一列"
aria-label="点击插入一列"
on:mousedown=move |event: MouseEvent| {
event.prevent_default();
event.stop_propagation();
}
on:click=move |event: MouseEvent| {
event.prevent_default();
event.stop_propagation();
set_table_toolbar_open.set(true);
set_table_options_open.set(false);
match run_table_toolbar_action(editor, TableToolbarAction::AddColumnAfter) {
Ok(message) => {
sync_persisted_editor_command(
editor,
&runtime_persisted_identity(document_id, workspace_id),
set_dirty_count,
set_html_output,
set_document_json,
set_json_output,
title,
set_command_feedback,
message,
);
if let Err(err) = editor.select_table_column(index as u32) {
set_command_feedback.set(format!("列已插入,但表格列选区同步失败:{err}"));
}
set_table_overlay_anchor.set(current_table_overlay_anchor());
set_table_selection_overlay.set(Some(TableSelectionOverlayState { kind: TableSelectionKind::Column, index }));
}
Err(err) => set_command_feedback.set(err),
}
}
>"+"</button>
}
}).collect_view()}
</div>
}.into_any()
}}
{move || {
if !table_toolbar_open.get() || slash_open.get() || block_menu_open.get() || dragging_block_index.get().is_some() {
return ().into_any();
}
view! {
<div
class="table-toolbar"
data-testid="mnote-leptos-tiptap-table-toolbar"
on:mousedown=move |event: MouseEvent| {
event.prevent_default();
event.stop_propagation();
}
on:click=move |event: MouseEvent| {
event.stop_propagation();
}
>
{TABLE_TOOLBAR_ACTIONS.iter().enumerate().map(|(index, action)| {
let action = *action;
let testid = format!("table-toolbar-{}", action.id());
view! {
<>
{if index == 3 {
view! { <span class="table-toolbar-separator" aria-hidden="true"></span> }.into_any()
} else {
().into_any()
}}
<button
type="button"
class="table-toolbar-btn"
data-testid=testid
title=action.title()
aria-label=action.title()
on:click=move |_| {
match run_table_toolbar_action(editor, action) {
Ok(message) => {
if matches!(action, TableToolbarAction::DeleteTable) {
set_table_toolbar_open.set(false);
set_table_options_open.set(false);
set_table_overlay_anchor.set(None);
set_table_selection_overlay.set(None);
} else {
set_table_selection_overlay.set(None);
}
sync_persisted_editor_command(
editor,
&runtime_persisted_identity(document_id, workspace_id),
set_dirty_count,
set_html_output,
set_document_json,
set_json_output,
title,
set_command_feedback,
message,
);
if !matches!(action, TableToolbarAction::DeleteTable) {
set_table_overlay_anchor.set(current_table_overlay_anchor());
}
}
Err(err) => set_command_feedback.set(err),
}
}
>
{action.icon()}
</button>
</>
}
}).collect_view()}
<span class="table-toolbar-separator" aria-hidden="true"></span>
<button
type="button"
class="table-toolbar-btn"
data-testid="table-toolbar-options"
title="选项"
aria-label="选项"
aria-expanded=move || table_options_open.get().to_string()
on:click=move |_| {
set_table_options_open.update(|open| *open = !*open);
}
>
"选项"
</button>
{move || {
if !table_options_open.get() {
return ().into_any();
}
view! {
<div class="table-options-menu" data-testid="table-toolbar-options-menu">
{TABLE_OPTION_ACTIONS.iter().map(|action| {
let action = *action;
let testid = format!("table-option-{}", action.id());
view! {
<button
type="button"
class="table-option-btn"
data-testid=testid
role="switch"
aria-checked=move || table_option_checked(&document_json.get(), action).to_string()
on:click=move |_| {
match run_table_option_action(editor, action) {
Ok(message) => {
sync_persisted_editor_command(
editor,
&runtime_persisted_identity(document_id, workspace_id),
set_dirty_count,
set_html_output,
set_document_json,
set_json_output,
title,
set_command_feedback,
message,
);
}
Err(err) => set_command_feedback.set(err),
}
}
>
<span>{action.title()}</span>
<span class="table-option-switch" aria-hidden="true"></span>
</button>
}
}).collect_view()}
</div>
}.into_any()
}}
</div>
}.into_any()
}}
{table_toolbar_view(
editor,
table_toolbar_open,
set_table_toolbar_open,
table_options_open,
set_table_options_open,
table_overlay_anchor,
set_table_overlay_anchor,
table_selection_overlay,
set_table_selection_overlay,
slash_open,
block_menu_open,
dragging_block_index,
document_json,
set_document_json,
set_dirty_count,
set_html_output,
set_json_output,
title,
document_id,
workspace_id,
set_command_feedback,
)}
{move || {
let Some(anchor) = image_toolbar_anchor.get() else {
return ().into_any();