DioxusLabs/dioxus

State management with dynamic rendering inside contenteditable divs

Open

#1,962 创建于 2024年2月22日

在 GitHub 查看
 (4 评论) (0 反应) (0 负责人)Rust (36,038 star) (1,655 fork)batch import
bughelp wanted

描述

State isn't synced properly when user deletes children nodes in contentetitable div

the user can delete elements by using the backspace inside contentetitable elements. Video below.

I also have a question regarding the event listeners of the child elements. Why they aren't triggered at all? Only the parent element event listeners are called.

Steps To Reproduce

Code:


#![allow(non_snake_case)]
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
use dioxus::prelude::*;
use dioxus_desktop::{tao::event_loop::EventLoop, use_window, LogicalSize, WindowBuilder};
use uuid::Uuid;

fn main() {
    // launch the dioxus app in a webview
    dioxus_desktop::launch_cfg(
        App,
        dioxus_desktop::Config::new()
            .with_custom_head(
                r#"
            <head> 
                <link rel="stylesheet" href="public/tailwind.css">
            </head>
            "#
                .to_string(),
            )
            .with_window(
                WindowBuilder::new()
                    .with_title("Desktop App")
                    .with_inner_size(LogicalSize {
                        width: 400.0,
                        height: 400.0,
                    })
                    .with_min_inner_size(LogicalSize {
                        width: 400.0,
                        height: 400.0,
                    })
                    .with_transparent(true),
            ),
    )
}

enum Blocks {
    ParagraphBlock(Uuid)
}

pub fn Paragraph(cx: Scope) -> Element {
    let inner_text = use_state(cx, || "".to_string());

    cx.render(rsx! {
        div {
            class: "border-solid border-2 border-indigo-300 p-4 rounded-lg some-block",
            onkeydown: move |e| {println!("Inner State (onkeydown) {:?}", e.key().to_string());},
            oninput : move |e| {println!("Inner State (oninput) {:?}", e.data.value.clone()); inner_text.set(e.data.value.clone())},
            p{
                class: "text-xs font-semibold text-gray-600 uppercase some-block-header",
                "contenteditable": "false",
                "Paragraph"
            },
            p {
                class: "text-base text-gray-800 empty:before:content-[attr(data-placeholder)] empty:before:text-gray-300 whitespace-pre-wrap selectable-area",
                "data-placeholder" : "Write text here ..",
                inner_text.as_str()
                
            }
            
        }
    }
)
}


fn App(cx: Scope) -> Element {
    let window = use_window(&cx);

    let some_blocks = use_ref(cx, Vec::<Blocks>::new);
    if some_blocks.read().is_empty() {
        some_blocks
            .write()
            .push(Blocks::ParagraphBlock(Uuid::new_v4()));

        some_blocks
            .write()
            .push(Blocks::ParagraphBlock(Uuid::new_v4()));
    
        some_blocks
            .write()
            .push(Blocks::ParagraphBlock(Uuid::new_v4()));
    }

    let binding = some_blocks.read();
    let blocks_rendered = binding
        .iter()
        .map(|block| match block {
            Blocks::ParagraphBlock(id) => rsx! {Paragraph{key: "{id}"}},
        });

    cx.render(rsx! {
         div {
            class: "h-screen w-screen flex bg-pink-100 p-4 rounded-lg flex-col space-y-4 overflow-auto",
            "contenteditable" : "true",
            onkeydown: move |_e| { println!("Number of blocks: {:?} ", some_blocks.read().len()) },
            onmousedown: move |_| {window.drag()},
            blocks_rendered
         }
    })
}


Expected behavior

State should be maintained and synced

Screenshots

dioxus-bug

Environment:

  • Dioxus version: 0.4.3
  • Rust version: rustc 1.76.0
  • OS info: Windows 10
  • App platform: desktop

Questionnaire

  • I'm interested in fixing this myself but don't know where to start
  • I would like to fix and I have a solution
  • I don't have time to fix this right now, but maybe later

贡献者指南