DioxusLabs/dioxus

State management with dynamic rendering inside contenteditable divs

Open

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

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

仓库指标

Star
 (36,038 star)
PR 合并指标
 (平均合并 16天 13小时) (30 天内合并 9 个 PR)

描述

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

贡献者指南