zino_dioxus/typography/
editor.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use dioxus::prelude::*;
use std::time::Duration;
use zino_core::{json, JsonValue, SharedString};

/// A ToastUI Editor.
pub fn TuiEditor(props: TuiEditorProps) -> Element {
    let mut markdown = use_signal(String::new);
    let eval_editor = document::eval(
        r#"
        const { Editor } = toastui;
        const { codeSyntaxHighlight } = Editor.plugin;

        let options = await dioxus.recv();
        options.el = document.getElementById(options.id);
        options.plugins = [codeSyntaxHighlight];
        options.events = {
            change: function() {
                document.getElementById("tui-editor-input").value = tuiEditor.getMarkdown();
            },
        };
        const tuiEditor = new Editor(options);
        tuiEditor.show();
        "#,
    );
    spawn(async move {
        loop {
            let mut eval = document::eval(
                r#"
                const value = document.getElementById("tui-editor-input").value;
                dioxus.send(value);
                "#,
            );
            if let Ok(JsonValue::String(s)) = eval.recv().await {
                if markdown() != s {
                    if let Some(handler) = props.on_change.as_ref() {
                        handler.call(s.clone());
                    }
                    markdown.set(s);
                }
            }
            // Sleep for 100 milliseconds to avoid blocking the thread.
            tokio::time::sleep(Duration::from_millis(100)).await;
        }
    });
    rsx! {
        input {
            id: "tui-editor-input",
            r#type: "hidden",
        }
        div {
            id: "{props.id}",
            onmounted: move |_event| {
                let options = json!({
                    "id": props.id,
                    "height": props.height,
                    "minHeight": props.min_height,
                    "initialValue": props.initial_value,
                    "initialEditType": props.edit_type,
                    "previewStyle": props.preview_style,
                    "language": props.locale,
                    "theme": props.theme,
                    "referenceDefinition": true,
                    "usageStatistics": false,
                });
                eval_editor.send(options).ok();
            }
        }
    }
}

/// The [`TuiEditor`] properties struct for the configuration of the component.
#[derive(Clone, PartialEq, Props)]
pub struct TuiEditorProps {
    /// The editor ID.
    #[props(into, default = "editor")]
    pub id: SharedString,
    /// The height of the container.
    #[props(into, default = "auto")]
    pub height: SharedString,
    /// The min-height of the container.
    #[props(into, default = "300px")]
    pub min_height: SharedString,
    /// The initial value of Markdown string.
    #[props(into)]
    pub initial_value: SharedString,
    /// The initial type to show: `markdown` | `wysiwyg`.
    #[props(into, default = "markdown")]
    pub edit_type: SharedString,
    /// The preview style of Markdown mode: `tab` | `vertical`.
    #[props(into, default = "vertical")]
    pub preview_style: SharedString,
    /// The theme: `light` | `dark`.
    #[props(into, default = "light")]
    pub theme: SharedString,
    /// The i18n locale.
    #[props(into, default = "en-US")]
    pub locale: SharedString,
    /// An event handler to be called when the input value is changed.
    pub on_change: Option<EventHandler<String>>,
}