🐛 Fix cut copy paste

This commit is contained in:
Alejandro Alonso
2026-03-04 11:55:45 +01:00
parent 287b9d4597
commit da372099f7
3 changed files with 66 additions and 8 deletions

View File

@@ -111,6 +111,21 @@
(let [text (text-editor/text-editor-export-selection)]
(.setData (.-clipboardData event) "text/plain" text))))))
on-cut
(mf/use-fn
(fn [^js event]
(when (text-editor/text-editor-is-active?)
(dom/prevent-default event)
(when (text-editor/text-editor-get-selection)
(let [text (text-editor/text-editor-export-selection)]
(.setData (.-clipboardData event) "text/plain" (or text ""))
(when (and text (seq text))
(text-editor/text-editor-delete-backward)
(sync-wasm-text-editor-content!)
(wasm.api/request-render "text-cut"))))
(when-let [node (mf/ref-val contenteditable-ref)]
(set! (.-textContent node) "")))))
on-key-down
(mf/use-fn
(fn [^js event]
@@ -303,6 +318,7 @@
:on-input on-input
:on-paste on-paste
:on-copy on-copy
:on-cut on-cut
:on-focus on-focus
:on-blur on-blur
;; FIXME on-click

View File

@@ -576,6 +576,7 @@ impl TextContent {
for paragraph in self.paragraphs() {
let paragraph_style = paragraph.paragraph_to_style();
let mut builder = ParagraphBuilder::new(&paragraph_style, fonts);
let mut has_text = false;
for span in paragraph.children() {
let remove_alpha = use_shadow.unwrap_or(false) && !span.is_transparent();
let text_style = span.to_style(
@@ -585,9 +586,15 @@ impl TextContent {
paragraph.line_height(),
);
let text: String = span.apply_text_transform();
if !text.is_empty() {
has_text = true;
}
builder.push_style(&text_style);
builder.add_text(&text);
}
if !has_text {
builder.add_text(" ");
}
paragraph_group.push(vec![builder]);
}

View File

@@ -282,9 +282,7 @@ pub extern "C" fn text_editor_insert_text() {
let cursor = state.text_editor_state.selection.focus;
if let Some(new_offset) = insert_text_at_cursor(text_content, &cursor, &text) {
let new_cursor =
TextPositionWithAffinity::new_without_affinity(cursor.paragraph, new_offset);
if let Some(new_cursor) = insert_text_with_newlines(text_content, &cursor, &text) {
state.text_editor_state.selection.set_caret(new_cursor);
}
@@ -751,12 +749,10 @@ pub extern "C" fn text_editor_export_selection() -> *mut u8 {
char_pos += span_len;
}
}
if !para_text.is_empty() {
if !result.is_empty() {
result.push('\n');
}
result.push_str(&para_text);
if para_idx > start.paragraph {
result.push('\n');
}
result.push_str(&para_text);
}
let mut bytes = result.into_bytes();
bytes.push(0);
@@ -1053,6 +1049,45 @@ fn find_span_at_offset(para: &Paragraph, char_offset: usize) -> Option<(usize, u
None
}
/// Insert text at a cursor position, splitting on newlines into multiple paragraphs.
/// Returns the final cursor position after insertion.
fn insert_text_with_newlines(
text_content: &mut TextContent,
cursor: &TextPositionWithAffinity,
text: &str,
) -> Option<TextPositionWithAffinity> {
let normalized = text.replace("\r\n", "\n").replace('\r', "\n");
let lines: Vec<&str> = normalized.split('\n').collect();
if lines.is_empty() {
return None;
}
let mut current_cursor = *cursor;
if let Some(new_offset) = insert_text_at_cursor(text_content, &current_cursor, lines[0]) {
current_cursor =
TextPositionWithAffinity::new_without_affinity(current_cursor.paragraph, new_offset);
} else {
return None;
}
for line in lines.iter().skip(1) {
if !split_paragraph_at_cursor(text_content, &current_cursor) {
break;
}
current_cursor =
TextPositionWithAffinity::new_without_affinity(current_cursor.paragraph + 1, 0);
if let Some(new_offset) = insert_text_at_cursor(text_content, &current_cursor, line) {
current_cursor = TextPositionWithAffinity::new_without_affinity(
current_cursor.paragraph,
new_offset,
);
}
}
Some(current_cursor)
}
/// Insert text at a cursor position. Returns the new character offset after insertion.
fn insert_text_at_cursor(
text_content: &mut TextContent,