fix(keyboard): route edit keys to scene template search field
Some checks failed
Rust multi-platform build / ${{ matrix.label }} (false, windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (true, false, macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (true, false, windows-aarch64, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
Rust multi-platform build / wasm32-unknown-unknown / op-host-web (compile guard) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (macos-latest) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (ubuntu-latest) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (windows-latest) (push) Has been cancelled
Rust check (native) / cargo-deny (native) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, linux-aarch64, ubuntu-24.04-arm, aarch64-unknown-linux-gnu) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, linux-x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (android-aarch64, ubuntu-latest, aarch64-linux-android) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (android-x86_64, ubuntu-latest, x86_64-linux-android) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (ios-aarch64, macos-latest, aarch64-apple-ios) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (ios-aarch64-sim, macos-latest, aarch64-apple-ios-sim) (push) Has been cancelled
Version consistency / Verify synchronized versions (push) Has been cancelled
WASM bundle build (#56 — real canvaskit deployable) / build + size-gate canvaskit web bundle (push) Has been cancelled
WASM bundle check (kickoff §1.2) / cargo check --target wasm32-unknown-unknown (push) Has been cancelled
WASM bundle check (kickoff §1.2) / cargo-deny --target wasm32-unknown-unknown check bans (push) Has been cancelled
Some checks failed
Rust multi-platform build / ${{ matrix.label }} (false, windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (true, false, macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (true, false, windows-aarch64, windows-latest, aarch64-pc-windows-msvc) (push) Has been cancelled
Rust multi-platform build / wasm32-unknown-unknown / op-host-web (compile guard) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (macos-latest) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (ubuntu-latest) (push) Has been cancelled
Rust check (native) / ${{ matrix.os }} / 1.94 (windows-latest) (push) Has been cancelled
Rust check (native) / cargo-deny (native) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, linux-aarch64, ubuntu-24.04-arm, aarch64-unknown-linux-gnu) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, linux-x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (false, macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (android-aarch64, ubuntu-latest, aarch64-linux-android) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (android-x86_64, ubuntu-latest, x86_64-linux-android) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (ios-aarch64, macos-latest, aarch64-apple-ios) (push) Has been cancelled
Rust multi-platform build / ${{ matrix.label }} (cargo check only) (ios-aarch64-sim, macos-latest, aarch64-apple-ios-sim) (push) Has been cancelled
Version consistency / Verify synchronized versions (push) Has been cancelled
WASM bundle build (#56 — real canvaskit deployable) / build + size-gate canvaskit web bundle (push) Has been cancelled
WASM bundle check (kickoff §1.2) / cargo check --target wasm32-unknown-unknown (push) Has been cancelled
WASM bundle check (kickoff §1.2) / cargo-deny --target wasm32-unknown-unknown check bans (push) Has been cancelled
Backspace, forward-delete, and arrow keys were falling through to the canvas when the Scene Template (Asset) Center was open, so the search field could not be edited and the selection behind the overlay could be deleted. Route these keys to the gallery's focused field for native parity and add regression tests.
This commit is contained in:
parent
2a872b1bb8
commit
de2bdd62b9
|
|
@ -612,6 +612,7 @@ pub(super) async fn mount_ck(canvas_id: String) -> Result<(), JsValue> {
|
||||||
"ArrowRight" if is_mod => consumed = b.host.apply_text_edit_line_edge(true),
|
"ArrowRight" if is_mod => consumed = b.host.apply_text_edit_line_edge(true),
|
||||||
"ArrowLeft" if !is_mod => {
|
"ArrowLeft" if !is_mod => {
|
||||||
consumed = b.host.apply_prompt_center_caret(false, shift)
|
consumed = b.host.apply_prompt_center_caret(false, shift)
|
||||||
|
|| b.host.apply_scene_template_caret(false, shift)
|
||||||
|| b.host.apply_image_panel_caret(false, shift)
|
|| b.host.apply_image_panel_caret(false, shift)
|
||||||
|| b.host.apply_settings_caret(false)
|
|| b.host.apply_settings_caret(false)
|
||||||
|| b.host.apply_chat_model_picker_caret(false)
|
|| b.host.apply_chat_model_picker_caret(false)
|
||||||
|
|
@ -623,6 +624,7 @@ pub(super) async fn mount_ck(canvas_id: String) -> Result<(), JsValue> {
|
||||||
}
|
}
|
||||||
"ArrowRight" if !is_mod => {
|
"ArrowRight" if !is_mod => {
|
||||||
consumed = b.host.apply_prompt_center_caret(true, shift)
|
consumed = b.host.apply_prompt_center_caret(true, shift)
|
||||||
|
|| b.host.apply_scene_template_caret(true, shift)
|
||||||
|| b.host.apply_image_panel_caret(true, shift)
|
|| b.host.apply_image_panel_caret(true, shift)
|
||||||
|| b.host.apply_settings_caret(true)
|
|| b.host.apply_settings_caret(true)
|
||||||
|| b.host.apply_chat_model_picker_caret(true)
|
|| b.host.apply_chat_model_picker_caret(true)
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,17 @@ impl WidgetHost {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// Native parity (`op-host-native/widget_host/keyboard_delete.rs`). The
|
||||||
|
// Asset Center owns Backspace while it is open; without this arm the
|
||||||
|
// key fell through to the canvas and either did nothing visible in the
|
||||||
|
// search box or deleted the selection behind the overlay.
|
||||||
|
if let Some(changed) = shared::scene_template_backspace(&mut self.editor_state, self.now_ms)
|
||||||
|
{
|
||||||
|
if changed {
|
||||||
|
self.mark_dirty();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if self.editor_state.editor_ui.collab_join_input_active() {
|
if self.editor_state.editor_ui.collab_join_input_active() {
|
||||||
let changed = op_editor_ui::widgets::collab_ui::join_address_backspace(
|
let changed = op_editor_ui::widgets::collab_ui::join_address_backspace(
|
||||||
&mut self.editor_state.editor_ui,
|
&mut self.editor_state.editor_ui,
|
||||||
|
|
@ -347,6 +358,16 @@ impl WidgetHost {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// Native parity: forward-Delete belongs to the Asset Center's focused
|
||||||
|
// field while it is open (same gap as Backspace above).
|
||||||
|
if let Some(changed) =
|
||||||
|
shared::scene_template_delete_forward(&mut self.editor_state, self.now_ms)
|
||||||
|
{
|
||||||
|
if changed {
|
||||||
|
self.mark_dirty();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if self.apply_image_panel_delete() {
|
if self.apply_image_panel_delete() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,17 @@ impl WidgetHost {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Left / Right arrow in the Scene Template Center's focused input
|
||||||
|
/// (native parity, `keyboard_caret.rs`). Without this the arrow keys
|
||||||
|
/// nudged the canvas behind the open gallery instead of the caret.
|
||||||
|
pub fn apply_scene_template_caret(&mut self, forward: bool, extend: bool) -> bool {
|
||||||
|
if shared::scene_template_caret(&mut self.editor_state, forward, extend, self.now_ms) {
|
||||||
|
self.mark_dirty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Cmd/Ctrl+C — copy the selection into the clipboard.
|
/// Cmd/Ctrl+C — copy the selection into the clipboard.
|
||||||
pub fn apply_copy(&mut self) -> bool {
|
pub fn apply_copy(&mut self) -> bool {
|
||||||
if self.editor_state.editor_ui.image_panel.search_open
|
if self.editor_state.editor_ui.image_panel.search_open
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,98 @@ fn plain_characters_reach_the_panel() {
|
||||||
assert_eq!(search(&host), "rect");
|
assert_eq!(search(&host), "rect");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Backspace had the same native-parity gap as `apply_text` did: the web
|
||||||
|
/// `apply_backspace` ladder skipped the Asset Center, so the key fell through
|
||||||
|
/// to the canvas and could not edit the search box (and would delete the
|
||||||
|
/// selection behind the overlay).
|
||||||
|
#[test]
|
||||||
|
fn backspace_edits_the_search_field() {
|
||||||
|
let mut host = gallery_host();
|
||||||
|
for c in "rect".chars() {
|
||||||
|
host.apply_text(c);
|
||||||
|
}
|
||||||
|
assert_eq!(search(&host), "rect");
|
||||||
|
|
||||||
|
assert!(host.apply_backspace());
|
||||||
|
assert_eq!(search(&host), "rec");
|
||||||
|
|
||||||
|
assert!(host.apply_backspace());
|
||||||
|
assert_eq!(search(&host), "re");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Backspace is swallowed even when the search box is empty — the open
|
||||||
|
/// gallery owns the key and it must never fall through to node deletion.
|
||||||
|
#[test]
|
||||||
|
fn backspace_on_an_empty_search_is_swallowed() {
|
||||||
|
let mut host = gallery_host();
|
||||||
|
host.editor_state.set_single_selection(op_editor_core::NodeId::new("n1"));
|
||||||
|
|
||||||
|
assert!(host.apply_backspace());
|
||||||
|
assert!(search(&host).is_empty());
|
||||||
|
assert!(
|
||||||
|
!host.editor_state.selection.is_empty(),
|
||||||
|
"Backspace behind the open gallery must not delete the selection"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forward-Delete edits the focused field (native parity); it must not fall
|
||||||
|
/// through to the canvas selection either.
|
||||||
|
#[test]
|
||||||
|
fn delete_edits_the_search_field() {
|
||||||
|
let mut host = gallery_host();
|
||||||
|
for c in "rect".chars() {
|
||||||
|
host.apply_text(c);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let input = &mut host.editor_state.editor_ui.scene_template_center.search;
|
||||||
|
input.set_caret(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(host.apply_delete());
|
||||||
|
assert_eq!(search(&host), "ect");
|
||||||
|
|
||||||
|
assert!(host.apply_delete());
|
||||||
|
assert_eq!(search(&host), "ct");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Left / Right arrows move the search caret instead of nudging the canvas
|
||||||
|
/// behind the open gallery (native parity, `apply_scene_template_caret`).
|
||||||
|
#[test]
|
||||||
|
fn arrows_move_the_search_caret() {
|
||||||
|
let mut host = gallery_host();
|
||||||
|
for c in "rect".chars() {
|
||||||
|
host.apply_text(c);
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
host.editor_state
|
||||||
|
.editor_ui
|
||||||
|
.scene_template_center
|
||||||
|
.search
|
||||||
|
.caret(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(host.apply_scene_template_caret(false, false));
|
||||||
|
assert_eq!(
|
||||||
|
host.editor_state
|
||||||
|
.editor_ui
|
||||||
|
.scene_template_center
|
||||||
|
.search
|
||||||
|
.caret(),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(host.apply_scene_template_caret(true, false));
|
||||||
|
assert_eq!(
|
||||||
|
host.editor_state
|
||||||
|
.editor_ui
|
||||||
|
.scene_template_center
|
||||||
|
.search
|
||||||
|
.caret(),
|
||||||
|
4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// The gate the tool shortcuts read, so a letter typed into the gallery is
|
/// The gate the tool shortcuts read, so a letter typed into the gallery is
|
||||||
/// never also a tool switch.
|
/// never also a tool switch.
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue