merge upstream changes

This commit is contained in:
Adrian Wannenmacher committed 2023-04-11 19:21:48 +02:00
commit 231e32d76e
343 files changed
+20245 -14076

No files matched your search

+1 -33
View File
@@ -18,8 +18,6 @@ cargo run --example hello_world
[custom_assets](./custom_assets.rs) - Include images
[custom_element](./custom_element.rs) - Render webcomponents
[custom_html](./custom_html.rs) - Customize wrapper HTML
[eval](./eval.rs) - Evaluate JS expressions
@@ -132,36 +130,6 @@ cargo run --example hello_world
[todomvc](./todomvc.rs) - Todo task list example
## Terminal UI
[tui_all_events](../packages/tui/examples/tui_all_events.rs) - All of the terminal events
[tui_border](../packages/tui/examples/tui_border.rs) - Different styles of borders and corners
[tui_buttons](../packages/tui/examples/tui_buttons.rs) - A grid of buttons that work demonstrate the focus system
[tui_color_test](../packages/tui/examples/tui_color_test.rs) - Grid of colors to demonstrate compatablility with different terminal color rendering modes
[tui_colorpicker](../packages/tui/examples/tui_colorpicker.rs) - A colorpicker
[tui_components](../packages/tui/examples/tui_components.rs) - Simple component example
[tui_flex](../packages/tui/examples/tui_flex.rs) - Flexbox support
[tui_hover](../packages/tui/examples/tui_hover.rs) - Detect hover and mouse events
[tui_list](../packages/tui/examples/tui_list.rs) - Renders a list of items
[tui_margin](../packages/tui/examples/tui_margin.rs) - Margins around flexboxes
[tui_quadrants](../packages/tui/examples/tui_quadrants.rs) - Four quadrants
[tui_readme](../packages/tui/examples/tui_readme.rs) - The readme example
[tui_task](../packages/tui/examples/tui_task.rs) - Background tasks
[tui_text](../packages/tui/examples/tui_text.rs) - Simple text example
# TODO
Missing Features
- Fine-grained reactivity
@@ -175,4 +143,4 @@ Missing examples
- Custom elements
- Component Children: Pass children into child components
- Render To string: Render a mounted virtualdom to a string
- Testing and Debugging
- Testing and Debugging
+18
View File
@@ -0,0 +1,18 @@
use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
cx.render(rsx! {
button {
onclick: |_| async move {
println!("hello, desktop!");
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
println!("goodbye, desktop!");
},
"hello, desktop!"
}
})
}
+1 -1
View File
@@ -82,7 +82,7 @@ fn app(cx: Scope) -> Element {
onclick: move |_| {
let temp = calc_val(val.as_str());
if temp > 0.0 {
val.set(format!("-{}", temp));
val.set(format!("-{temp}"));
} else {
val.set(format!("{}", temp.abs()));
}
+1 -1
View File
@@ -13,7 +13,7 @@ fn app(cx: Scope) -> Element {
.await
.unwrap();
println!("{:#?}, ", res);
println!("{res:#?}, ");
});
cx.render(rsx! {
+28
View File
@@ -0,0 +1,28 @@
//! Example: README.md showcase
//!
//! The example from the README.md.
use dioxus::prelude::*;
use dioxus_signals::{use_init_signal_rt, use_signal};
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
use_init_signal_rt(cx);
let mut count = use_signal(cx, || 0);
use_future!(cx, || async move {
loop {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
count += 1;
println!("current: {count}");
}
});
cx.render(rsx! {
div { "High-Five counter: {count}" }
})
}
+82
View File
@@ -0,0 +1,82 @@
//! This example shows how to create a popup window and send data back to the parent window.
use dioxus::prelude::*;
use dioxus_desktop::use_window;
use futures_util::StreamExt;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let window = use_window(cx);
let emails_sent = use_ref(cx, Vec::new);
let tx = use_coroutine(cx, |mut rx: UnboundedReceiver<String>| {
to_owned![emails_sent];
async move {
while let Some(message) = rx.next().await {
emails_sent.write().push(message);
}
}
});
cx.render(rsx! {
div {
h1 { "This is your email" }
button {
onclick: move |_| {
let dom = VirtualDom::new_with_props(compose, ComposeProps {
app_tx: tx.clone()
});
// this returns a weak reference to the other window
// Be careful not to keep a strong reference to the other window or it will never be dropped
// and the window will never close.
window.new_window(dom, Default::default());
},
"Click to compose a new email"
}
ul {
emails_sent.read().iter().map(|message| cx.render(rsx! {
li {
h3 { "email" }
span {"{message}"}
}
}))
}
}
})
}
struct ComposeProps {
app_tx: Coroutine<String>,
}
fn compose(cx: Scope<ComposeProps>) -> Element {
let user_input = use_state(cx, String::new);
let window = use_window(cx);
cx.render(rsx! {
div {
h1 { "Compose a new email" }
button {
onclick: move |_| {
cx.props.app_tx.send(user_input.get().clone());
window.close();
},
"Click to send"
}
input {
oninput: move |e| {
user_input.set(e.value.clone());
},
value: "{user_input}"
}
}
})
}
+36
View File
@@ -0,0 +1,36 @@
//! Comparison example with leptos' counter example
//! https://github.com/leptos-rs/leptos/blob/main/examples/counters/src/lib.rs
use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let counters = use_state(cx, || vec![0, 0, 0]);
let sum: usize = counters.iter().copied().sum();
render! {
div {
button { onclick: move |_| counters.make_mut().push(0), "Add counter" }
button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" }
p { "Total: {sum}" }
for (i, counter) in counters.iter().enumerate() {
li {
button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" }
input {
value: "{counter}",
oninput: move |e| {
if let Ok(value) = e.value.parse::<usize>() {
counters.make_mut()[i] = value;
}
}
}
button { onclick: move |_| counters.make_mut()[i] += 1, "+1" }
button { onclick: move |_| { counters.make_mut().remove(i); }, "x" }
}
}
}
}
}
+2 -1
View File
@@ -8,7 +8,8 @@ fn app(cx: Scope) -> Element {
cx.render(rsx! {
div {
"This should show an image:"
img { src: "examples/assets/logo.png", }
img { src: "examples/assets/logo.png" }
img { src: "/Users/jonkelley/Desktop/blitz.png" }
}
})
}
-40
View File
@@ -1,40 +0,0 @@
//! This example shows to wrap a webcomponent / custom element with a component.
//!
//! Oftentimes, a third party library will provide a webcomponent that you want
//! to use in your application. This example shows how to create that custom element
//! directly with the raw_element method on NodeFactory.
use dioxus::prelude::*;
fn main() {
let mut dom = VirtualDom::new(app);
let _ = dom.rebuild();
let output = dioxus_ssr::render(&dom);
println!("{}", output);
}
fn app(cx: Scope) -> Element {
let g = cx.component(component, (), "component");
let c = cx.make_node(g);
cx.render(rsx! {
div { c }
})
// let nf = NodeFactory::new(cx);
// let mut attrs = dioxus::core::exports::bumpalo::collections::Vec::new_in(nf.bump());
// attrs.push(nf.attr("client-id", format_args!("abc123"), None, false));
// attrs.push(nf.attr("name", format_args!("bob"), None, false));
// attrs.push(nf.attr("age", format_args!("47"), None, false));
// Some(nf.raw_element("my-element", None, &[], attrs.into_bump_slice(), &[], None))
}
fn component(cx: Scope) -> Element {
todo!()
}
+1 -1
View File
@@ -52,7 +52,7 @@ struct DogApi {
#[inline_props]
async fn breed_pic(cx: Scope, breed: String) -> Element {
let fut = use_future!(cx, |breed| async move {
reqwest::get(format!("https://dog.ceo/api/breed/{}/images/random", breed))
reqwest::get(format!("https://dog.ceo/api/breed/{breed}/images/random"))
.await
.unwrap()
.json::<DogApi>()
+36
View File
@@ -0,0 +1,36 @@
use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let count = if cx.generation() % 2 == 0 { 10 } else { 0 };
println!("Generation: {}", cx.generation());
if cx.generation() < 10 {
cx.needs_update();
}
render! {
(0..count).map(|_| rsx!{
drop_child {}
})
}
}
fn drop_child(cx: Scope) -> Element {
cx.use_hook(|| Drops);
render! {
div{}
}
}
struct Drops;
impl Drop for Drops {
fn drop(&mut self) {
println!("Dropped!");
}
}
+9 -13
View File
@@ -1,25 +1,17 @@
use dioxus::prelude::*;
use dioxus_desktop::EvalResult;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let script = use_state(cx, String::new);
let eval = dioxus_desktop::use_eval(cx);
let future: &UseRef<Option<EvalResult>> = use_ref(cx, || None);
if future.read().is_some() {
let future_clone = future.clone();
cx.spawn(async move {
if let Some(fut) = future_clone.with_mut(|o| o.take()) {
println!("{:?}", fut.await)
}
});
}
let script = use_state(cx, String::new);
let output = use_state(cx, String::new);
cx.render(rsx! {
div {
p { "Output: {output}" }
input {
placeholder: "Enter an expression",
value: "{script}",
@@ -27,8 +19,12 @@ fn app(cx: Scope) -> Element {
}
button {
onclick: move |_| {
let fut = eval(script);
future.set(Some(fut));
to_owned![script, eval, output];
cx.spawn(async move {
if let Ok(res) = eval(script.to_string()).await {
output.set(res.to_string());
}
});
},
"Execute"
}
+1
View File
@@ -10,6 +10,7 @@ fn main() {
static NAME: Atom<String> = |_| "world".to_string();
fn app(cx: Scope) -> Element {
use_init_atom_root(cx);
let name = use_read(cx, NAME);
cx.render(rsx! {
+1 -1
View File
@@ -89,7 +89,7 @@ impl Files {
let paths = match std::fs::read_dir(cur_path) {
Ok(e) => e,
Err(err) => {
let err = format!("An error occured: {:?}", err);
let err = format!("An error occured: {err:?}");
self.err = Some(err);
self.path_stack.pop();
return;
+1 -1
View File
@@ -3,7 +3,7 @@ use dioxus_desktop::Config;
fn main() {
let cfg = Config::new().with_file_drop_handler(|_w, e| {
println!("{:?}", e);
println!("{e:?}");
true
});
+3 -3
View File
@@ -42,7 +42,7 @@ fn app(cx: Scope) -> Element {
// so the value of our input event will be either huey, dewey, louie, or true/false (because of the checkboxe)
// be mindful in grouping inputs together, as they will all be handled by the same event handler
oninput: move |evt| {
println!("{:?}", evt);
println!("{evt:?}");
},
div {
input {
@@ -104,7 +104,7 @@ fn app(cx: Scope) -> Element {
name: "pdf",
r#type: "checkbox",
oninput: move |evt| {
println!("{:?}", evt);
println!("{evt:?}");
},
}
label {
@@ -121,7 +121,7 @@ fn app(cx: Scope) -> Element {
r#type: "{field}",
value: "{value}",
oninput: move |evt: FormEvent| {
println!("{:?}", evt);
println!("{evt:?}");
},
}
label {
+27
View File
@@ -0,0 +1,27 @@
use dioxus::prelude::*;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let window = dioxus_desktop::use_window(cx);
cx.render(rsx! {
div {
button {
onclick: move |_| {
let dom = VirtualDom::new(popup);
window.new_window(dom, Default::default());
},
"New Window"
}
}
})
}
fn popup(cx: Scope) -> Element {
cx.render(rsx! {
div { "This is a popup!" }
})
}
+5 -5
View File
@@ -16,18 +16,18 @@ fn app(cx: Scope) -> Element {
onclick: move |_| println!("clicked! top"),
"- div"
button {
onclick: move |_| println!("clicked! bottom propoate"),
"Propogate"
onclick: move |_| println!("clicked! bottom propagate"),
"Propagate"
}
button {
onclick: move |evt| {
println!("clicked! bottom no bubbling");
evt.stop_propogation();
evt.stop_propagation();
},
"Dont propogate"
"Dont propagate"
}
button {
"Does not handle clicks - only propogate"
"Does not handle clicks - only propagate"
}
}
})
+63
View File
@@ -0,0 +1,63 @@
use dioxus::prelude::*;
use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, LogicalSize, WindowBuilder};
fn main() {
dioxus_desktop::launch_cfg(app, make_config());
}
fn app(cx: Scope) -> Element {
let window = use_window(cx);
cx.render(rsx! {
div {
width: "100%",
height: "100%",
background_color: "red",
border: "1px solid black",
div {
width: "100%",
height: "10px",
background_color: "black",
onmousedown: move |_| window.drag(),
}
"This is an overlay!"
}
})
}
fn make_config() -> dioxus_desktop::Config {
dioxus_desktop::Config::default()
.with_window(make_window())
.with_custom_head(
r#"
<style type="text/css">
html, body {
height: 100px;
margin: 0;
overscroll-behavior-y: none;
overscroll-behavior-x: none;
overflow: hidden;
}
#main, #bodywrap {
height: 100%;
margin: 0;
overscroll-behavior-x: none;
overscroll-behavior-y: none;
}
</style>
"#
.to_owned(),
)
}
fn make_window() -> WindowBuilder {
WindowBuilder::new()
.with_transparent(true)
.with_decorations(false)
.with_resizable(false)
.with_always_on_top(true)
.with_position(PhysicalPosition::new(0, 0))
.with_max_inner_size(LogicalSize::new(100000, 50))
}
+2 -2
View File
@@ -83,7 +83,7 @@ fn app(cx: Scope) -> Element {
div {
class: {
const WORD: &str = "expressions";
format_args!("Arguments can be passed in through curly braces for complex {}", WORD)
format_args!("Arguments can be passed in through curly braces for complex {WORD}")
}
}
}
@@ -214,7 +214,7 @@ fn app(cx: Scope) -> Element {
}
fn format_dollars(dollars: u32, cents: u32) -> String {
format!("${}.{:02}", dollars, cents)
format!("${dollars}.{cents:02}")
}
fn helper<'a>(cx: &'a ScopeState, text: &str) -> Element<'a> {
+17
View File
@@ -0,0 +1,17 @@
use dioxus::prelude::*;
use dioxus_desktop::tao::keyboard::ModifiersState;
use dioxus_desktop::use_global_shortcut;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let toggled = use_state(cx, || false);
use_global_shortcut(cx, KeyCode::S, ModifiersState::CONTROL, {
to_owned![toggled];
move || toggled.modify(|t| !*t)
});
cx.render(rsx!("toggle: {toggled.get()}"))
}
+30
View File
@@ -0,0 +1,30 @@
use dioxus::prelude::*;
use dioxus_signals::{use_init_signal_rt, use_signal};
use std::time::Duration;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
use_init_signal_rt(cx);
let mut count = use_signal(cx, || 0);
use_future!(cx, || async move {
loop {
count += 1;
tokio::time::sleep(Duration::from_millis(400)).await;
}
});
cx.render(rsx! {
h1 { "High-Five counter: {count}" }
button { onclick: move |_| count += 1, "Up high!" }
button { onclick: move |_| count -= 1, "Down low!" }
if count() > 5 {
rsx!{ h2 { "High five!" } }
}
})
}
+1 -1
View File
@@ -27,7 +27,7 @@ fn main() {
let mut file = String::new();
let mut renderer = dioxus_ssr::Renderer::default();
renderer.render_to(&mut file, &vdom).unwrap();
println!("{}", file);
println!("{file}");
}
fn app(cx: Scope) -> Element {
+1 -1
View File
@@ -9,7 +9,7 @@ fn main() {
fn app(cx: Scope) -> Element {
let model = use_state(cx, || String::from("asd"));
println!("{}", model);
println!("{model}");
cx.render(rsx! {
textarea {
+86 -39
View File
@@ -7,7 +7,7 @@ fn main() {
dioxus_desktop::launch(app);
}
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum FilterState {
All,
Active,
@@ -39,56 +39,99 @@ pub fn app(cx: Scope<()>) -> Element {
.collect::<Vec<_>>();
filtered_todos.sort_unstable();
let show_clear_completed = todos.values().any(|todo| todo.checked);
let items_left = filtered_todos.len();
let item_text = match items_left {
let active_todo_count = todos.values().filter(|item| !item.checked).count();
let active_todo_text = match active_todo_count {
1 => "item",
_ => "items",
};
cx.render(rsx!{
let show_clear_completed = todos.values().any(|todo| todo.checked);
let selected = |state| {
if *filter == state {
"selected"
} else {
"false"
}
};
cx.render(rsx! {
section { class: "todoapp",
style { include_str!("./assets/todomvc.css") }
div {
header { class: "header",
h1 {"todos"}
input {
class: "new-todo",
placeholder: "What needs to be done?",
value: "{draft}",
autofocus: "true",
oninput: move |evt| {
draft.set(evt.value.clone());
},
onkeydown: move |evt| {
if evt.key() == Key::Enter && !draft.is_empty() {
todos.make_mut().insert(
**todo_id,
TodoItem {
id: **todo_id,
checked: false,
contents: draft.to_string(),
},
);
*todo_id.make_mut() += 1;
draft.set("".to_string());
}
header { class: "header",
h1 {"todos"}
input {
class: "new-todo",
placeholder: "What needs to be done?",
value: "{draft}",
autofocus: "true",
oninput: move |evt| {
draft.set(evt.value.clone());
},
onkeydown: move |evt| {
if evt.key() == Key::Enter && !draft.is_empty() {
todos.make_mut().insert(
**todo_id,
TodoItem {
id: **todo_id,
checked: false,
contents: draft.to_string(),
},
);
*todo_id.make_mut() += 1;
draft.set("".to_string());
}
}
}
}
section {
class: "main",
if !todos.is_empty() {
rsx! {
input {
id: "toggle-all",
class: "toggle-all",
r#type: "checkbox",
onchange: move |_| {
let check = active_todo_count != 0;
for (_, item) in todos.make_mut().iter_mut() {
item.checked = check;
}
},
checked: if active_todo_count == 0 { "true" } else { "false" },
}
label { r#for: "toggle-all" }
}
}
ul { class: "todo-list",
filtered_todos.iter().map(|id| rsx!(TodoEntry { key: "{id}", id: *id, todos: todos }))
filtered_todos.iter().map(|id| rsx!(TodoEntry {
key: "{id}",
id: *id,
todos: todos,
}))
}
(!todos.is_empty()).then(|| rsx!(
footer { class: "footer",
span { class: "todo-count",
strong {"{items_left} "}
span {"{item_text} left"}
strong {"{active_todo_count} "}
span {"{active_todo_text} left"}
}
ul { class: "filters",
li { class: "All", a { onclick: move |_| filter.set(FilterState::All), "All" }}
li { class: "Active", a { onclick: move |_| filter.set(FilterState::Active), "Active" }}
li { class: "Completed", a { onclick: move |_| filter.set(FilterState::Completed), "Completed" }}
for (state, state_text, url) in [
(FilterState::All, "All", "#/"),
(FilterState::Active, "Active", "#/active"),
(FilterState::Completed, "Completed", "#/completed"),
] {
li {
a {
href: url,
class: selected(state),
onclick: move |_| filter.set(state),
prevent_default: "onclick",
state_text
}
}
}
}
show_clear_completed.then(|| rsx!(
button {
@@ -102,8 +145,8 @@ pub fn app(cx: Scope<()>) -> Element {
}
}
footer { class: "info",
p {"Double-click to edit a todo"}
p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }}
p { "Double-click to edit a todo" }
p { "Created by ", a { href: "http://github.com/jkelleyrtp/", "jkelleyrtp" }}
p { "Part of ", a { href: "http://todomvc.com", "TodoMVC" }}
}
})
@@ -136,13 +179,17 @@ pub fn TodoEntry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
cx.props.todos.make_mut()[&cx.props.id].checked = evt.value.parse().unwrap();
}
}
label {
r#for: "cbg-{todo.id}",
onclick: move |_| is_editing.set(true),
ondblclick: move |_| is_editing.set(true),
prevent_default: "onclick",
"{todo.contents}"
}
button {
class: "destroy",
onclick: move |_| { cx.props.todos.make_mut().remove(&todo.id); },
prevent_default: "onclick",
}
}
is_editing.then(|| rsx!{
input {
+6 -6
View File
@@ -35,13 +35,13 @@ fn app(cx: Scope) -> Element {
nav { class: "md:ml-auto flex flex-wrap items-center text-base justify-center" }
button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.set_minimized(true),
"Minimize"
}
button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| {
window.set_fullscreen(!**fullscreen);
@@ -52,7 +52,7 @@ fn app(cx: Scope) -> Element {
}
button {
class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.close(),
"Close"
}
@@ -66,7 +66,7 @@ fn app(cx: Scope) -> Element {
div {
button {
class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| {
window.set_always_on_top(!always_on_top);
always_on_top.set(!always_on_top);
@@ -77,7 +77,7 @@ fn app(cx: Scope) -> Element {
div {
button {
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| {
window.set_decorations(!decorations);
decorations.set(!decorations);
@@ -88,7 +88,7 @@ fn app(cx: Scope) -> Element {
div {
button {
class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded",
onmousedown: |evt| evt.stop_propogation(),
onmousedown: |evt| evt.stop_propagation(),
onclick: move |_| window.set_title("Dioxus Application"),
"Change Title"
}
+42
View File
@@ -0,0 +1,42 @@
use dioxus::prelude::*;
use dioxus_desktop::tao::event::WindowEvent;
use dioxus_desktop::use_wry_event_handler;
use dioxus_desktop::wry::application::event::Event as WryEvent;
fn main() {
dioxus_desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let focused = use_state(cx, || false);
use_wry_event_handler(cx, {
to_owned![focused];
move |event, _| {
if let WryEvent::WindowEvent {
event: WindowEvent::Focused(new_focused),
..
} = event
{
focused.set(*new_focused);
}
}
});
cx.render(rsx! {
div{
width: "100%",
height: "100%",
display: "flex",
flex_direction: "column",
align_items: "center",
{
if *focused.get() {
"This window is focused!"
} else {
"This window is not focused!"
}
}
}
})
}
+5 -4
View File
@@ -7,16 +7,17 @@ fn main() {
fn app(cx: Scope) -> Element {
let window = use_window(cx);
let level = use_state(cx, || 1.0);
cx.render(rsx! {
input {
r#type: "number",
value: "{level}",
oninput: |e| {
let num = e.value.parse::<f64>().unwrap_or(1.0);
level.set(num);
window.set_zoom_level(num);
if let Ok(new_zoom) = e.value.parse::<f64>() {
level.set(new_zoom);
window.webview.zoom(new_zoom);
}
}
}
})