refactor: extract table toolbar view
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user