├── .vscode ├── .gitignore ├── settings.json └── spellright.dict ├── packages ├── cli │ ├── examples │ │ ├── README.md │ │ └── plugin │ │ │ ├── init.lua │ │ │ └── interface.lua │ ├── docs │ │ ├── .gitignore │ │ ├── book.toml │ │ └── src │ │ │ ├── plugin │ │ │ └── interface │ │ │ │ ├── os.md │ │ │ │ ├── command.md │ │ │ │ ├── dirs.md │ │ │ │ ├── log.md │ │ │ │ ├── path.md │ │ │ │ └── network.md │ │ │ ├── SUMMARY.md │ │ │ ├── introduction.md │ │ │ ├── installation.md │ │ │ └── creating.md │ ├── .gitignore │ ├── tests │ │ ├── main.rs │ │ ├── fixtures │ │ │ ├── test.zip │ │ │ └── dangerous.zip │ │ └── svg.html │ ├── src │ │ ├── assets │ │ │ ├── icon.ico │ │ │ ├── index.html │ │ │ └── autoreload.js │ │ ├── plugin │ │ │ └── interface │ │ │ │ ├── dirs.rs │ │ │ │ ├── os.rs │ │ │ │ ├── log.rs │ │ │ │ └── network.rs │ │ ├── lib.rs │ │ └── cli │ │ │ ├── clean.rs │ │ │ └── plugin.rs │ ├── .vscode │ │ └── settings.json │ ├── Dioxus.toml │ └── .github │ │ └── workflows │ │ ├── build.yml │ │ └── docs.yml ├── hooks │ ├── src │ │ ├── usesignal.rs │ │ ├── userootcontext.rs │ │ ├── usecontext.rs │ │ └── usecallback.rs │ └── Cargo.toml ├── router-macro │ ├── README.md │ ├── src │ │ ├── query.rs │ │ └── layout.rs │ └── Cargo.toml ├── ssr │ ├── src │ │ ├── config.rs │ │ └── template.rs │ ├── tests │ │ ├── inner_html.rs │ │ ├── bool_attr.rs │ │ └── styles.rs │ └── Cargo.toml ├── web │ ├── .gitignore │ ├── .vscode │ │ └── settings.json │ ├── examples │ │ ├── README.md │ │ └── timeout_count.rs │ ├── BUGS.md │ └── src │ │ ├── ricpolyfill.js │ │ └── eval.js ├── fullstack │ ├── .gitignore │ ├── examples │ │ ├── axum-desktop │ │ │ ├── .gitignore │ │ │ ├── src │ │ │ │ ├── client.rs │ │ │ │ ├── server.rs │ │ │ │ └── lib.rs │ │ │ └── Cargo.toml │ │ ├── axum-auth │ │ │ └── .gitignore │ │ ├── axum-router │ │ │ ├── .gitignore │ │ │ └── Cargo.toml │ │ ├── axum-hello-world │ │ │ ├── .gitignore │ │ │ └── Cargo.toml │ │ ├── salvo-hello-world │ │ │ ├── .gitignore │ │ │ └── Cargo.toml │ │ ├── static-hydrated │ │ │ ├── .gitignore │ │ │ ├── Cargo.toml │ │ │ └── Dioxus.toml │ │ └── warp-hello-world │ │ │ ├── .gitignore │ │ │ └── Cargo.toml │ └── src │ │ └── hooks │ │ ├── mod.rs │ │ └── server_cached.rs ├── fermi │ ├── src │ │ ├── atoms │ │ │ ├── selector.rs │ │ │ ├── selectorfamily.rs │ │ │ ├── atomref.rs │ │ │ ├── atomfamily.rs │ │ │ └── atom.rs │ │ ├── hooks │ │ │ ├── init_atom_root.rs │ │ │ ├── set.rs │ │ │ ├── atom_root.rs │ │ │ └── read.rs │ │ └── callback.rs │ └── Cargo.toml ├── router │ ├── .gitignore │ ├── tests │ │ └── via_ssr │ │ │ └── main.rs │ └── src │ │ ├── hooks │ │ └── use_router.rs │ │ ├── history │ │ └── web_scroll.rs │ │ ├── components │ │ └── default_errors.rs │ │ └── utils │ │ └── use_router_internal.rs ├── rink │ ├── .gitignore │ ├── .vscode │ │ └── spellright.dict │ ├── src │ │ └── widgets │ │ │ ├── textbox.rs │ │ │ └── password.rs │ ├── examples │ │ └── example.png │ └── Cargo.toml ├── dioxus-tui │ ├── .gitignore │ ├── .vscode │ │ └── spellright.dict │ ├── examples │ │ ├── example.png │ │ ├── readme_hello_world.rs │ │ ├── list.rs │ │ ├── border.rs │ │ └── task.rs │ └── Cargo.toml ├── html │ └── src │ │ ├── web_sys_bind │ │ └── mod.rs │ │ ├── native_bind │ │ ├── mod.rs │ │ └── native_file_engine.rs │ │ └── events │ │ ├── scroll.rs │ │ ├── toggle.rs │ │ ├── selection.rs │ │ ├── image.rs │ │ ├── transition.rs │ │ ├── clipboard.rs │ │ ├── focus.rs │ │ ├── composition.rs │ │ ├── animation.rs │ │ ├── touch.rs │ │ └── drag.rs ├── native-core │ ├── .gitignore │ ├── src │ │ ├── utils │ │ │ └── mod.rs │ │ └── node_watcher.rs │ └── Cargo.toml ├── native-core-macro │ ├── .gitignore │ └── Cargo.toml ├── mobile │ ├── .cargo │ │ └── config.toml │ ├── src │ │ └── lib.rs │ ├── Makefile.toml │ ├── .vscode │ │ └── settings.json │ └── Cargo.toml ├── core │ ├── tests │ │ ├── .rustfmt.toml │ │ ├── hotreloading.rs │ │ ├── safety.rs │ │ ├── bubble_error.rs │ │ ├── error_boundary.rs │ │ ├── boolattrs.rs │ │ ├── create_element.rs │ │ ├── suspense.rs │ │ ├── README.md │ │ └── miri_full_app.rs │ ├── .vscode │ │ ├── settings.json │ │ └── spellright.dict │ ├── src │ │ ├── dirty_scope.rs │ │ ├── scheduler │ │ │ ├── suspense.rs │ │ │ └── mod.rs │ │ ├── bump_frame.rs │ │ └── subtree.rs │ ├── compile_tests │ │ ├── props_safety_temporary_values.rs │ │ ├── props_safety_temporary_values.stderr │ │ ├── props_safety.stderr │ │ └── props_safety.rs │ └── Cargo.toml ├── autofmt │ ├── tests │ │ ├── samples │ │ │ ├── immediate_expr.rsx │ │ │ ├── collapse_expr.rsx │ │ │ ├── t2.rsx │ │ │ ├── tinynoopt.rsx │ │ │ ├── emoji.rsx │ │ │ ├── tiny.rsx │ │ │ ├── trailing_expr.rsx │ │ │ ├── ifchain_forloop.rsx │ │ │ ├── key.rsx │ │ │ ├── multirsx.rsx │ │ │ ├── raw_strings.rsx │ │ │ ├── messy_indent.rsx │ │ │ ├── reallylong.rsx │ │ │ ├── long_exprs.rsx │ │ │ ├── manual_props.rsx │ │ │ ├── comments.rsx │ │ │ ├── commentshard.rsx │ │ │ ├── long.rsx │ │ │ └── attributes.rsx │ │ ├── wrong │ │ │ ├── multi.rsx │ │ │ ├── comments.wrong.rsx │ │ │ ├── multi.wrong.rsx │ │ │ ├── comments.rsx │ │ │ ├── multiexpr.wrong.rsx │ │ │ └── multiexpr.rsx │ │ ├── wrong.rs │ │ └── samples.rs │ └── Cargo.toml ├── extension │ ├── static │ │ └── icon.png │ ├── .gitignore │ ├── DEV.md │ ├── tsconfig.json │ ├── pkg │ │ └── package.json │ ├── Cargo.toml │ ├── .vscode │ │ ├── tasks.json │ │ └── launch.json │ ├── README.md │ ├── .eslintrc.js │ └── LICENSE.txt ├── liveview │ ├── .vscode │ │ └── settings.json │ └── src │ │ ├── index.html │ │ ├── adapters │ │ ├── salvo_adapter.rs │ │ ├── axum_adapter.rs │ │ └── warp_adapter.rs │ │ └── main.js ├── desktop │ └── src │ │ ├── assets │ │ ├── default_icon.bin │ │ └── default_icon.png │ │ ├── index.html │ │ ├── events.rs │ │ └── waker.rs ├── check │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── core-macro │ ├── tests │ │ ├── rsx.rs │ │ ├── rsx │ │ │ ├── trailing-comma-0.stderr │ │ │ └── trailing-comma-0.rs │ │ └── ifmt.rs │ ├── src │ │ └── component_body_deserializers │ │ │ └── mod.rs │ └── Cargo.toml ├── rsx │ ├── src │ │ ├── hot_reload │ │ │ ├── mod.rs │ │ │ └── hot_reloading_context.rs │ │ └── errors.rs │ └── Cargo.toml ├── signals │ ├── src │ │ └── lib.rs │ ├── examples │ │ ├── selector.rs │ │ ├── context.rs │ │ └── dependancies.rs │ ├── Cargo.toml │ └── tests │ │ └── effect.rs ├── generational-box │ ├── Cargo.toml │ └── README.md ├── rsx-rosetta │ ├── examples │ │ └── html.rs │ └── Cargo.toml ├── interpreter │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── server-macro │ └── Cargo.toml ├── dioxus │ └── src │ │ └── lib.rs └── hot-reload │ └── Cargo.toml ├── playwright-tests ├── fullstack │ ├── .gitignore │ └── Cargo.toml ├── web │ └── Cargo.toml ├── package.json ├── liveview │ └── Cargo.toml └── fullstack.spec.js ├── codecov.yml ├── .mailmap ├── examples ├── tailwind │ ├── input.css │ ├── tailwind.config.js │ ├── Cargo.toml │ └── Dioxus.toml ├── assets │ └── logo.png ├── PWA-example │ ├── public │ │ ├── favicon.ico │ │ ├── logo_192.png │ │ ├── logo_512.png │ │ └── manifest.json │ ├── Cargo.toml │ ├── src │ │ └── main.rs │ ├── Dioxus.toml │ ├── index.html │ └── LICENSE ├── mobile_demo │ ├── .gitignore │ ├── mobile.toml │ └── src │ │ └── index.html ├── hello_world.rs ├── web_component.rs ├── custom_assets.rs ├── shortcut.rs ├── filedragdrop.rs ├── query_segments_demo │ └── Cargo.toml ├── button.rs ├── readme.rs ├── textarea.rs ├── callback.rs ├── clock.rs ├── generic_component.rs ├── disabled.rs ├── window_zoom.rs ├── multiwindow.rs ├── xss_safety.rs ├── drops.rs ├── signals.rs ├── heavy_compute.rs ├── error_handle.rs ├── tasks.rs ├── scroll_to_top.rs ├── form.rs ├── simple_list.rs ├── nested_listeners.rs ├── eval.rs ├── custom_html.rs ├── simple_router.rs ├── ssr.rs ├── optional_props.rs ├── inlineprops.rs ├── control_focus.rs ├── hydration.rs ├── window_focus.rs └── counter.rs ├── .docker ├── Dockerfile_code_coverage ├── Dockerfile_test ├── Dockerfile_pre_test ├── Dockerfile_base_test_image └── README.md ├── .github ├── dependabot.yml ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_requst.md │ └── bug_report.md ├── notes └── CONTRIBUTING.md ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitignore └── LICENSE-MIT /.vscode/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/cli/examples/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/hooks/src/usesignal.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/router-macro/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/ssr/src/config.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/ssr/src/template.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/web/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | -------------------------------------------------------------------------------- /packages/cli/docs/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /packages/fullstack/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /packages/fermi/src/atoms/selector.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/router/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | static -------------------------------------------------------------------------------- /packages/fermi/src/atoms/selectorfamily.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/rink/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /playwright-tests/fullstack/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | fail_ci_if_error: false 3 | -------------------------------------------------------------------------------- /packages/dioxus-tui/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /packages/html/src/web_sys_bind/mod.rs: -------------------------------------------------------------------------------- 1 | mod events; 2 | -------------------------------------------------------------------------------- /packages/native-core/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /packages/rink/.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | esque 2 | Tui 3 | -------------------------------------------------------------------------------- /packages/dioxus-tui/.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | esque 2 | Tui 3 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-desktop/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target -------------------------------------------------------------------------------- /packages/native-core-macro/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /packages/router/tests/via_ssr/main.rs: -------------------------------------------------------------------------------- 1 | mod link; 2 | mod outlet; 3 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Jonathan Kelley 2 | -------------------------------------------------------------------------------- /packages/cli/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | .DS_Store 4 | .idea/ 5 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-auth/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target 3 | static -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-router/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target 3 | static -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target 3 | static -------------------------------------------------------------------------------- /packages/fullstack/examples/salvo-hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target 3 | static -------------------------------------------------------------------------------- /packages/fullstack/examples/static-hydrated/.gitignore: -------------------------------------------------------------------------------- 1 | docs 2 | target 3 | static -------------------------------------------------------------------------------- /packages/fullstack/examples/warp-hello-world/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | target 3 | static -------------------------------------------------------------------------------- /packages/mobile/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "aarch64-apple-ios" 3 | -------------------------------------------------------------------------------- /examples/tailwind/input.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /packages/core/tests/.rustfmt.toml: -------------------------------------------------------------------------------- 1 | struct_variant_width = 100 2 | struct_lit_width = 80 3 | -------------------------------------------------------------------------------- /packages/fullstack/src/hooks/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod server_cached; 2 | pub mod server_future; 3 | -------------------------------------------------------------------------------- /examples/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/examples/assets/logo.png -------------------------------------------------------------------------------- /packages/core/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.checkOnSave.allTargets": false 3 | } 4 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/immediate_expr.rsx: -------------------------------------------------------------------------------- 1 | fn it_works() { 2 | cx.render(rsx!(())) 3 | } 4 | 5 | -------------------------------------------------------------------------------- /packages/cli/tests/main.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn ready() { 3 | println!("Compiled successfully!") 4 | } 5 | -------------------------------------------------------------------------------- /packages/html/src/native_bind/mod.rs: -------------------------------------------------------------------------------- 1 | mod native_file_engine; 2 | 3 | pub use native_file_engine::*; 4 | -------------------------------------------------------------------------------- /packages/mobile/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | 3 | pub use dioxus_desktop::*; 4 | -------------------------------------------------------------------------------- /packages/web/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.target": "wasm32-unknown-unknown", 3 | } 4 | -------------------------------------------------------------------------------- /packages/cli/src/assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/cli/src/assets/icon.ico -------------------------------------------------------------------------------- /packages/rink/src/widgets/textbox.rs: -------------------------------------------------------------------------------- 1 | use super::text_like::TextLike; 2 | 3 | pub(crate) type TextBox = TextLike; 4 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/collapse_expr.rsx: -------------------------------------------------------------------------------- 1 | fn itworks() { 2 | rsx!( "{name}", "{name}", "{name}" ) 3 | } 4 | 5 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/t2.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div {} 3 | div { 4 | // div { 5 | } 6 | } 7 | 8 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/tinynoopt.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | div {} 4 | div {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/core/.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | Dodrio 2 | VDoms 3 | dom 4 | virtualdom 5 | ns 6 | nohasher 7 | Preact 8 | vnodes 9 | -------------------------------------------------------------------------------- /packages/core/tests/hotreloading.rs: -------------------------------------------------------------------------------- 1 | //! It should be possible to swap out templates at runtime, enabling hotreloading 2 | -------------------------------------------------------------------------------- /packages/extension/static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/extension/static/icon.png -------------------------------------------------------------------------------- /packages/liveview/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": [ 3 | "warp" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/rink/examples/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/rink/examples/example.png -------------------------------------------------------------------------------- /packages/cli/tests/fixtures/test.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/cli/tests/fixtures/test.zip -------------------------------------------------------------------------------- /packages/mobile/Makefile.toml: -------------------------------------------------------------------------------- 1 | [tasks.test] 2 | command = "cargo" 3 | args = [ 4 | "test", 5 | "--no-run", 6 | ] 7 | 8 | -------------------------------------------------------------------------------- /examples/PWA-example/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/examples/PWA-example/public/favicon.ico -------------------------------------------------------------------------------- /examples/PWA-example/public/logo_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/examples/PWA-example/public/logo_192.png -------------------------------------------------------------------------------- /examples/PWA-example/public/logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/examples/PWA-example/public/logo_512.png -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/multi.rsx: -------------------------------------------------------------------------------- 1 | fn app(cx: Scope) -> Element { 2 | cx.render(rsx! { div { "hello world" } }) 3 | } 4 | -------------------------------------------------------------------------------- /packages/dioxus-tui/examples/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/dioxus-tui/examples/example.png -------------------------------------------------------------------------------- /packages/cli/tests/fixtures/dangerous.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/cli/tests/fixtures/dangerous.zip -------------------------------------------------------------------------------- /packages/desktop/src/assets/default_icon.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/desktop/src/assets/default_icon.bin -------------------------------------------------------------------------------- /packages/desktop/src/assets/default_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gobidev/dioxus/master/packages/desktop/src/assets/default_icon.png -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/comments.wrong.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | // Comments 4 | class: "asdasd", "hello world" } 5 | } 6 | -------------------------------------------------------------------------------- /packages/check/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod check; 2 | mod issues; 3 | mod metadata; 4 | 5 | pub use check::check_file; 6 | pub use issues::{Issue, IssueReport}; 7 | -------------------------------------------------------------------------------- /packages/cli/docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["YuKun Liu"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Dioxus CLI" 7 | -------------------------------------------------------------------------------- /examples/mobile_demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | target/ 3 | **/*.rs.bk 4 | 5 | # tauri-mobile 6 | .cargo/ 7 | /gen 8 | 9 | # macOS 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/multi.wrong.rsx: -------------------------------------------------------------------------------- 1 | fn app(cx: Scope) -> Element { 2 | cx.render(rsx! { 3 | div {"hello world" } 4 | }) 5 | } 6 | -------------------------------------------------------------------------------- /packages/cli/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Lua.diagnostics.globals": [ 3 | "plugin_logger", 4 | "PLUGIN_DOWNLOADER" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/comments.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | // Comments 4 | class: "asdasd", 5 | "hello world" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/core-macro/tests/rsx.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn rsx() { 3 | let t = trybuild::TestCases::new(); 4 | t.compile_fail("tests/rsx/trailing-comma-0.rs"); 5 | } 6 | -------------------------------------------------------------------------------- /.docker/Dockerfile_code_coverage: -------------------------------------------------------------------------------- 1 | FROM dioxus-test-image 2 | 3 | WORKDIR /run_test 4 | RUN cargo install cargo-tarpaulin 5 | RUN cargo cache -a 6 | 7 | ENTRYPOINT [ "bash" ] 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "[toml]": { 4 | "editor.formatOnSave": false 5 | }, 6 | "rust-analyzer.checkOnSave.allTargets": false, 7 | } 8 | -------------------------------------------------------------------------------- /.docker/Dockerfile_test: -------------------------------------------------------------------------------- 1 | FROM dioxus-pre-test 2 | 3 | RUN mkdir run_test 4 | COPY tmp /run_test 5 | WORKDIR /run_test 6 | RUN cargo make tests 7 | RUN cargo cache -a 8 | 9 | CMD ["exit"] 10 | -------------------------------------------------------------------------------- /examples/mobile_demo/mobile.toml: -------------------------------------------------------------------------------- 1 | [app] 2 | name = "mobile-demo" 3 | stylized-name = "Mobile Demo" 4 | domain = "example.com" 5 | template-pack = "wry" 6 | 7 | [apple] 8 | development-team = "34U4FG9TJ8" 9 | -------------------------------------------------------------------------------- /packages/core-macro/tests/rsx/trailing-comma-0.stderr: -------------------------------------------------------------------------------- 1 | error: missing trailing comma 2 | --> tests/rsx/trailing-comma-0.rs:9:20 3 | | 4 | 9 | class: "foo bar" 5 | | ^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /packages/mobile/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.inlayHints.enable": true, 3 | "rust-analyzer.checkOnSave.allTargets": true, 4 | "rust-analyzer.cargo.target": "aarch64-apple-ios" 5 | } 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # Maintain dependencies for GitHub Actions 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | -------------------------------------------------------------------------------- /packages/core-macro/src/component_body_deserializers/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module contains all [`ComponentBody`](crate::component_body::ComponentBody) deserializers. 2 | 3 | pub mod component; 4 | pub mod inline_props; 5 | -------------------------------------------------------------------------------- /packages/web/examples/README.md: -------------------------------------------------------------------------------- 1 | Examples 2 | ======== 3 | 4 | # Hydrate 5 | 6 | - `hydrate` show hydrate 7 | 8 | # Async 9 | 10 | - `timeout_count` button to add count and show count in the future 11 | -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/multiexpr.wrong.rsx: -------------------------------------------------------------------------------- 1 | fn ItWroks() { 2 | cx.render(rsx! { 3 | div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", left, right } 4 | }) 5 | } 6 | -------------------------------------------------------------------------------- /packages/extension/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | Thumbs.db 4 | */node_modules/ 5 | node_modules/ 6 | */out/ 7 | out/ 8 | */.vs/ 9 | .vs/ 10 | tsconfig.lsif.json 11 | *.lsif 12 | *.db 13 | *.vsix 14 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/emoji.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { class: "asdasdasd asdasdasd asdasdasd asdasdasd asdasdasd asdasdasd asdasdasd asdasdasd asdasdasd", 3 | section { "🦀🦀🦀🦀🦀🦀🦀🦀🦀🦀" } 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/tiny.rsx: -------------------------------------------------------------------------------- 1 | fn ItWorks() { 2 | rsx! { 3 | div { 4 | div { 5 | div {} 6 | div {} 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/rsx/src/hot_reload/mod.rs: -------------------------------------------------------------------------------- 1 | mod hot_reload_diff; 2 | pub use hot_reload_diff::*; 3 | mod hot_reloading_context; 4 | pub use hot_reloading_context::*; 5 | mod hot_reloading_file_map; 6 | pub use hot_reloading_file_map::*; 7 | -------------------------------------------------------------------------------- /packages/extension/DEV.md: -------------------------------------------------------------------------------- 1 | 2 | ## packaging 3 | 4 | ``` 5 | $ cd myExtension 6 | $ vsce package 7 | # myExtension.vsix generated 8 | $ vsce publish 9 | # .myExtension published to VS Code Marketplace 10 | ``` 11 | -------------------------------------------------------------------------------- /.docker/Dockerfile_pre_test: -------------------------------------------------------------------------------- 1 | FROM dioxus-base-test-image 2 | 3 | RUN cargo install cargo-binstall 4 | RUN cargo install cargo-make 5 | RUN cargo install wasm-pack 6 | RUN cargo install cargo-cache && cargo cache -a 7 | 8 | CMD ["exit"] 9 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/trailing_expr.rsx: -------------------------------------------------------------------------------- 1 | fn it_works() { 2 | cx.render(rsx! { 3 | div { 4 | span { "Description: ", package.description.as_deref().unwrap_or("❌❌❌❌ missing") } 5 | } 6 | }) 7 | } 8 | -------------------------------------------------------------------------------- /examples/hello_world.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! ( 9 | div { "Hello, world!" } 10 | )) 11 | } 12 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: DioxusLabs # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | open_collective: dioxus-labs # Replace with a single Open Collective username 5 | -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong/multiexpr.rsx: -------------------------------------------------------------------------------- 1 | fn ItWroks() { 2 | cx.render(rsx! { 3 | div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", 4 | left, 5 | right 6 | } 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /examples/tailwind/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | mode: "all", 4 | content: ["./src/**/*.{rs,html,css}", "./dist/**/*.html"], 5 | theme: { 6 | extend: {}, 7 | }, 8 | plugins: [], 9 | }; 10 | -------------------------------------------------------------------------------- /examples/web_component.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! { 9 | web-component { 10 | "my-prop": "5%", 11 | } 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/ifchain_forloop.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | // Does this work? 3 | for i in b { 4 | // Hey it works? 5 | div {} 6 | } 7 | 8 | // Some ifchain 9 | if a > 10 { 10 | // 11 | rsx! { div {} } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/web/BUGS.md: -------------------------------------------------------------------------------- 1 | # Known quirks for browsers and their workarounds 2 | 3 | - text merging (solved through comment nodes) 4 | - cursor jumping to end on inputs (not yet solved, solved in React already) 5 | - SVG attributes cannot be set (solved using the correct method) 6 | - volatile components 7 | -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/os.md: -------------------------------------------------------------------------------- 1 | # OS Functions 2 | 3 | OS functions are for getting system information. 4 | 5 | ### `current_platform() -> string ("windows" | "macos" | "linux")` 6 | 7 | Get the current OS platform. 8 | 9 | ```lua 10 | local platform = plugin.os.current_platform() 11 | ``` -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/key.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | li { key: "{link}", 3 | Link { class: "py-1 px-2 {hover} {hover_bg}", to: "{link}", "{name}" } 4 | } 5 | 6 | li { key: "{link}", asd: "asd", 7 | Link { class: "py-1 px-2 {hover} {hover_bg}", to: "{link}", "{name}" } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/hooks/src/userootcontext.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::ScopeState; 2 | 3 | /// 4 | pub fn use_root_context(cx: &ScopeState, new: impl FnOnce() -> T) -> &T { 5 | cx.use_hook(|| { 6 | cx.consume_context::() 7 | .unwrap_or_else(|| cx.provide_root_context(new())) 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /packages/signals/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![warn(missing_docs)] 3 | 4 | mod rt; 5 | pub use rt::*; 6 | mod effect; 7 | pub use effect::*; 8 | mod impls; 9 | mod selector; 10 | pub use selector::*; 11 | pub(crate) mod signal; 12 | pub use signal::*; 13 | mod dependency; 14 | pub use dependency::*; 15 | -------------------------------------------------------------------------------- /packages/desktop/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dioxus app 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/native-core/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! # Utilities for renders using the RealDOM 2 | //! 3 | //! This includes an iterator that can be used to iterate over the children of a node that persists changes in the struture of the DOM, and a cursor for text editing. 4 | 5 | mod persistant_iterator; 6 | pub use persistant_iterator::*; 7 | pub mod cursor; 8 | -------------------------------------------------------------------------------- /packages/core-macro/tests/rsx/trailing-comma-0.rs: -------------------------------------------------------------------------------- 1 | // Given an `rsx!` invocation with a missing trailing comma, 2 | // ensure the stderr output has an informative span. 3 | 4 | use dioxus::prelude::*; 5 | 6 | fn main() { 7 | rsx! { 8 | p { 9 | class: "foo bar" 10 | "Hello world" 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /packages/extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2021", 5 | "lib": [ 6 | "ES2021" 7 | ], 8 | "outDir": "out", 9 | "sourceMap": true, 10 | "strict": true, 11 | "rootDir": "src" 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | ".vscode-test", 16 | "out" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /notes/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | On Linux, install the following packages: 4 | 5 | ```bash 6 | sudo apt install libgdk3.0-cil libatk1.0-dev libcairo2-dev libpango1.0-dev libgdk-pixbuf2.0-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev 7 | ``` 8 | 9 | Then run: 10 | 11 | ```bash 12 | cargo test --workspace --tests 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/html/src/events/scroll.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type ScrollEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct ScrollData {} 7 | 8 | impl_event! { 9 | ScrollData; 10 | 11 | /// onscroll 12 | onscroll 13 | } 14 | -------------------------------------------------------------------------------- /packages/html/src/events/toggle.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type ToggleEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct ToggleData {} 7 | 8 | impl_event! { 9 | ToggleData; 10 | 11 | /// ontoggle 12 | ontoggle 13 | } 14 | -------------------------------------------------------------------------------- /packages/extension/pkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dioxus-ext", 3 | "version": "0.1.0", 4 | "files": [ 5 | "dioxus_ext_bg.wasm", 6 | "dioxus_ext.js", 7 | "dioxus_ext.d.ts", 8 | "dioxus_ext_bg.js", 9 | "dioxus_ext_bg.d.ts", 10 | "dioxus_ext_bg.wasm.d.ts" 11 | ], 12 | "main": "dioxus_ext.js", 13 | "types": "dioxus_ext.d.ts" 14 | } 15 | -------------------------------------------------------------------------------- /examples/custom_assets.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! { 9 | div { 10 | p { 11 | "This should show an image:" 12 | } 13 | img { src: "examples/assets/logo.png" } 14 | } 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/multirsx.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | 3 | // hi 4 | div {} 5 | 6 | // hi 7 | div { abcd, ball, s } 8 | 9 | // 10 | // 11 | // 12 | div { abcd, ball, s } 13 | 14 | // 15 | // 16 | // 17 | div { 18 | abcd, 19 | ball, 20 | s, 21 | 22 | // 23 | "asdasd" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_requst.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: If you have any interesting advice, you can tell us. 4 | --- 5 | 6 | ## Specific Demand 7 | 8 | 11 | 12 | ## Implement Suggestion 13 | 14 | -------------------------------------------------------------------------------- /examples/mobile_demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dioxus app 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VARIANT="nightly-bookworm-slim" 2 | FROM rustlang/rust:${VARIANT} 3 | ENV DEBIAN_FRONTEND noninteractive 4 | RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections 5 | 6 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive 7 | 8 | RUN apt-get -qq install build-essential libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/raw_strings.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | // Raw text strings 3 | button { r#"Click me"#, r##"Click me"##, r######"Click me"######, r#"dynamic {1}"# } 4 | 5 | // Raw attribute strings 6 | div { 7 | width: r#"10px"#, 8 | height: r##"{10}px"##, 9 | "raw-attr": r###"raw-attr"###, 10 | "raw-attr2": r###"{100}"### 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.docker/Dockerfile_base_test_image: -------------------------------------------------------------------------------- 1 | FROM rust:1.58-buster 2 | 3 | RUN apt update 4 | RUN apt install -y \ 5 | libglib2.0-dev \ 6 | libgtk-3-dev \ 7 | libsoup2.4-dev \ 8 | libappindicator3-dev \ 9 | libwebkit2gtk-4.0-dev \ 10 | firefox-esr \ 11 | # for Tarpaulin code coverage 12 | liblzma-dev binutils-dev libcurl4-openssl-dev libdw-dev libelf-dev 13 | 14 | CMD ["exit"] 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /playwright-tests/web/dist 3 | /playwright-tests/fullstack/dist 4 | /dist 5 | Cargo.lock 6 | .DS_Store 7 | 8 | .vscode/* 9 | !.vscode/settings.json 10 | !.vscode/tasks.json 11 | !.vscode/launch.json 12 | !.vscode/extensions.json 13 | tarpaulin-report.html 14 | 15 | # Jetbrain 16 | .idea/ 17 | node_modules/ 18 | /test-results/ 19 | /playwright-report/ 20 | /playwright/.cache/ 21 | -------------------------------------------------------------------------------- /packages/liveview/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dioxus app 5 | 6 | 7 | 8 |
9 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/rink/src/widgets/password.rs: -------------------------------------------------------------------------------- 1 | use super::text_like::{TextLike, TextLikeController}; 2 | 3 | pub(crate) type Password = TextLike; 4 | 5 | #[derive(Debug, Default)] 6 | pub(crate) struct PasswordController; 7 | 8 | impl TextLikeController for PasswordController { 9 | fn display_text(&self, text: &str) -> String { 10 | text.chars().map(|_| '.').collect() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-desktop/src/client.rs: -------------------------------------------------------------------------------- 1 | // Run with: 2 | // ```bash 3 | // cargo run --bin client --features desktop 4 | // ``` 5 | 6 | use axum_desktop::*; 7 | use dioxus_fullstack::prelude::server_fn::set_server_url; 8 | 9 | fn main() { 10 | // Set the url of the server where server functions are hosted. 11 | set_server_url("http://127.0.0.1:8080"); 12 | dioxus_desktop::launch(app) 13 | } 14 | -------------------------------------------------------------------------------- /playwright-tests/web/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-playwright-web-test" 3 | version = "0.0.1" 4 | edition = "2021" 5 | description = "Playwright test for Dioxus Web" 6 | license = "MIT OR Apache-2.0" 7 | publish = false 8 | 9 | [dependencies] 10 | dioxus = { path = "../../packages/dioxus" } 11 | dioxus-web = { path = "../../packages/web" } 12 | dioxus-html = { path = "../../packages/html" } 13 | serde_json = "1.0.96" 14 | -------------------------------------------------------------------------------- /packages/fermi/src/hooks/init_atom_root.rs: -------------------------------------------------------------------------------- 1 | use crate::AtomRoot; 2 | use dioxus_core::ScopeState; 3 | use std::rc::Rc; 4 | 5 | // Initializes the atom root and retuns it; 6 | pub fn use_init_atom_root(cx: &ScopeState) -> &Rc { 7 | cx.use_hook(|| match cx.consume_context::>() { 8 | Some(ctx) => ctx, 9 | None => cx.provide_context(Rc::new(AtomRoot::new(cx.schedule_update_any()))), 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /examples/shortcut.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_desktop::use_global_shortcut; 3 | 4 | fn main() { 5 | dioxus_desktop::launch(app); 6 | } 7 | 8 | fn app(cx: Scope) -> Element { 9 | let toggled = use_state(cx, || false); 10 | 11 | use_global_shortcut(cx, "ctrl+s", { 12 | to_owned![toggled]; 13 | move || toggled.modify(|t| !*t) 14 | }); 15 | 16 | cx.render(rsx!("toggle: {toggled.get()}")) 17 | } 18 | -------------------------------------------------------------------------------- /packages/generational-box/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generational-box" 3 | authors = ["Evan Almloff"] 4 | version = "0.0.0" 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | bumpalo = { version = "3.6" } 11 | 12 | [dev-dependencies] 13 | rand = "0.8.5" 14 | 15 | [features] 16 | default = ["check_generation"] 17 | check_generation = [] 18 | -------------------------------------------------------------------------------- /playwright-tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dioxus", 3 | "version": "1.0.0", 4 | "description": "

", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs", 8 | "example": "examples" 9 | }, 10 | "scripts": {}, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@playwright/test": "^1.36.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/cli/src/plugin/interface/dirs.rs: -------------------------------------------------------------------------------- 1 | use mlua::UserData; 2 | 3 | use crate::tools::app_path; 4 | 5 | pub struct PluginDirs; 6 | impl UserData for PluginDirs { 7 | fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { 8 | methods.add_function("plugins_dir", |_, ()| { 9 | let path = app_path().join("plugins"); 10 | Ok(path.to_str().unwrap().to_string()) 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/extension/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-ext" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | wasm-bindgen.workspace = true 11 | dioxus-autofmt.workspace = true 12 | rsx-rosetta.workspace = true 13 | html_parser.workspace = true 14 | 15 | 16 | [lib] 17 | crate-type = ["cdylib", "rlib"] 18 | -------------------------------------------------------------------------------- /packages/cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub const DIOXUS_CLI_VERSION: &str = "0.4.1"; 2 | 3 | pub mod builder; 4 | pub mod server; 5 | pub mod tools; 6 | 7 | pub use builder::*; 8 | 9 | pub mod cargo; 10 | pub use cargo::*; 11 | 12 | pub mod cli; 13 | pub use cli::*; 14 | 15 | pub mod config; 16 | pub use config::*; 17 | 18 | pub mod error; 19 | pub use error::*; 20 | 21 | pub mod logging; 22 | pub use logging::*; 23 | 24 | #[cfg(feature = "plugin")] 25 | pub mod plugin; 26 | -------------------------------------------------------------------------------- /packages/fermi/src/hooks/set.rs: -------------------------------------------------------------------------------- 1 | use crate::{use_atom_root, Writable}; 2 | use dioxus_core::ScopeState; 3 | use std::rc::Rc; 4 | 5 | pub fn use_set(cx: &ScopeState, f: impl Writable) -> &Rc { 6 | let root = use_atom_root(cx); 7 | cx.use_hook(|| { 8 | let id = f.unique_id(); 9 | let root = root.clone(); 10 | root.initialize(f); 11 | Rc::new(move |new| root.set(id, new)) as Rc 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /examples/filedragdrop.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_desktop::Config; 3 | 4 | fn main() { 5 | let cfg = Config::new().with_file_drop_handler(|_w, e| { 6 | println!("{e:?}"); 7 | true 8 | }); 9 | 10 | dioxus_desktop::launch_with_props(app, (), cfg); 11 | } 12 | 13 | fn app(cx: Scope) -> Element { 14 | cx.render(rsx!( 15 | div { 16 | h1 { "drag a file here and check your console" } 17 | } 18 | )) 19 | } 20 | -------------------------------------------------------------------------------- /packages/cli/examples/plugin/init.lua: -------------------------------------------------------------------------------- 1 | local Api = require("./interface") 2 | local log = Api.log; 3 | 4 | local manager = { 5 | name = "Dioxus-CLI Plugin Demo", 6 | repository = "http://github.com/DioxusLabs/cli", 7 | author = "YuKun Liu ", 8 | } 9 | 10 | manager.onLoad = function () 11 | log.info("plugin loaded.") 12 | end 13 | 14 | manager.onStartBuild = function () 15 | log.warn("system start to build") 16 | end 17 | 18 | return manager -------------------------------------------------------------------------------- /packages/dioxus-tui/examples/readme_hello_world.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_tui::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! { 9 | div { 10 | width: "100%", 11 | height: "10px", 12 | background_color: "red", 13 | justify_content: "center", 14 | align_items: "center", 15 | 16 | "Hello world!" 17 | } 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /examples/query_segments_demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "query_segments_demo" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | dioxus = { path = "../../packages/dioxus", version = "*" } 10 | dioxus-router = { path = "../../packages/router", version = "*" } 11 | dioxus-web = { path = "../../packages/web", version = "*" } 12 | form_urlencoded = "1.2.0" 13 | -------------------------------------------------------------------------------- /packages/extension/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": { 15 | "kind": "build", 16 | "isDefault": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /packages/html/src/events/selection.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type SelectionEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct SelectionData {} 7 | 8 | impl_event! [ 9 | SelectionData; 10 | 11 | /// select 12 | onselect 13 | 14 | /// selectstart 15 | onselectstart 16 | 17 | /// selectionchange 18 | onselectionchange 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/router/src/hooks/use_router.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::ScopeState; 2 | 3 | use crate::{prelude::RouterContext, utils::use_router_internal::use_router_internal}; 4 | 5 | #[deprecated = "prefer the use_navigator or use_route functions"] 6 | /// A hook that provides access to information about the router. 7 | pub fn use_router(cx: &ScopeState) -> &RouterContext { 8 | use_router_internal(cx) 9 | .as_ref() 10 | .expect("use_route must have access to a router") 11 | } 12 | -------------------------------------------------------------------------------- /packages/html/src/events/image.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type ImageEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct ImageData { 7 | #[cfg_attr(feature = "serialize", serde(default))] 8 | pub load_error: bool, 9 | } 10 | 11 | impl_event! [ 12 | ImageData; 13 | 14 | /// onerror 15 | onerror 16 | 17 | /// onload 18 | onload 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/html/src/events/transition.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type TransitionEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq)] 6 | pub struct TransitionData { 7 | pub property_name: String, 8 | pub pseudo_element: String, 9 | pub elapsed_time: f32, 10 | } 11 | 12 | impl_event! { 13 | TransitionData; 14 | 15 | /// transitionend 16 | ontransitionend 17 | } 18 | -------------------------------------------------------------------------------- /examples/button.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! { 9 | button { 10 | onclick: |_| async move { 11 | println!("hello, desktop!"); 12 | tokio::time::sleep(std::time::Duration::from_secs(1)).await; 13 | println!("goodbye, desktop!"); 14 | }, 15 | "hello, desktop!" 16 | } 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /packages/desktop/src/events.rs: -------------------------------------------------------------------------------- 1 | //! Convert a serialized event to an event trigger 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | #[derive(Deserialize, Serialize, Debug, Clone)] 6 | pub struct IpcMessage { 7 | method: String, 8 | params: serde_json::Value, 9 | } 10 | 11 | impl IpcMessage { 12 | pub(crate) fn method(&self) -> &str { 13 | self.method.as_str() 14 | } 15 | 16 | pub(crate) fn params(self) -> serde_json::Value { 17 | self.params 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/html/src/events/clipboard.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type ClipboardEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct ClipboardData { 7 | // DOMDataTransfer clipboardData 8 | } 9 | 10 | impl_event![ 11 | ClipboardData; 12 | 13 | /// oncopy 14 | oncopy 15 | 16 | /// oncut 17 | oncut 18 | 19 | /// onpaste 20 | onpaste 21 | ]; 22 | -------------------------------------------------------------------------------- /playwright-tests/liveview/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-playwright-liveview-test" 3 | version = "0.0.1" 4 | edition = "2021" 5 | description = "Playwright test for Dioxus Liveview" 6 | license = "MIT OR Apache-2.0" 7 | publish = false 8 | 9 | [dependencies] 10 | dioxus = { path = "../../packages/dioxus" } 11 | dioxus-liveview = { path = "../../packages/liveview", features = ["axum"] } 12 | tokio = { version = "1.19.2", features = ["full"] } 13 | axum = { version = "0.6.1", features = ["ws"] } 14 | -------------------------------------------------------------------------------- /examples/readme.rs: -------------------------------------------------------------------------------- 1 | //! Example: README.md showcase 2 | //! 3 | //! The example from the README.md. 4 | 5 | use dioxus::prelude::*; 6 | 7 | fn main() { 8 | dioxus_desktop::launch(app); 9 | } 10 | 11 | fn app(cx: Scope) -> Element { 12 | let mut count = use_state(cx, || 0); 13 | 14 | cx.render(rsx! { 15 | h1 { "High-Five counter: {count}" } 16 | button { onclick: move |_| count += 1, "Up high!" } 17 | button { onclick: move |_| count -= 1, "Down low!" } 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/messy_indent.rsx: -------------------------------------------------------------------------------- 1 | fn SaveClipboard(cx: Scope) -> Element { 2 | rsx! { 3 | div { class: "relative w-1/2 {align} max-w-md leading-8", 4 | h2 { class: "mb-6 text-3xl leading-tight md:text-4xl md:leading-tight lg:text-3xl lg:leading-tight font-heading font-mono font-bold", 5 | "{title}" 6 | } 7 | } 8 | }; 9 | 10 | cx.render(rsx! { 11 | div { "hello world", "hello world", "hello world" } 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/dirty_scope.rs: -------------------------------------------------------------------------------- 1 | use std::hash::Hash; 2 | 3 | use crate::ScopeId; 4 | 5 | #[derive(Debug, Clone, Eq, PartialOrd, Ord)] 6 | pub struct DirtyScope { 7 | pub height: u32, 8 | pub id: ScopeId, 9 | } 10 | 11 | impl PartialEq for DirtyScope { 12 | fn eq(&self, other: &Self) -> bool { 13 | self.id == other.id 14 | } 15 | } 16 | 17 | impl Hash for DirtyScope { 18 | fn hash(&self, state: &mut H) { 19 | self.id.hash(state); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/fermi/src/hooks/atom_root.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use crate::AtomRoot; 4 | use dioxus_core::ScopeState; 5 | 6 | // Returns the atom root, initiaizing it at the root of the app if it does not exist. 7 | pub fn use_atom_root(cx: &ScopeState) -> &Rc { 8 | cx.use_hook(|| match cx.consume_context::>() { 9 | Some(root) => root, 10 | None => panic!("No atom root found in context. Did you forget place an AtomRoot component at the top of your app?"), 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /packages/cli/docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Introduction](./introduction.md) 4 | - [Installation](./installation.md) 5 | - [Create a project](./creating.md) 6 | - [Configure a project](./configure.md) 7 | - [Plugin development](./plugin/README.md) 8 | - [API.Log](plugin/interface/log.md) 9 | - [API.Command](plugin/interface/command.md) 10 | - [API.OS](plugin/interface/os.md) 11 | - [API.Directories](plugin/interface/dirs.md) 12 | - [API.Network](plugin/interface/network.md) 13 | - [API.Path](plugin/interface/path.md) -------------------------------------------------------------------------------- /packages/core/tests/safety.rs: -------------------------------------------------------------------------------- 1 | //! Tests related to safety of the library. 2 | 3 | use dioxus::prelude::*; 4 | 5 | /// Ensure no issues with not calling rebuild 6 | #[test] 7 | fn root_node_isnt_null() { 8 | let dom = VirtualDom::new(|cx| render!("Hello world!")); 9 | 10 | let scope = dom.base_scope(); 11 | 12 | // We haven't built the tree, so trying to get out the root node should fail 13 | assert!(scope.try_root_node().is_none()); 14 | 15 | // The height should be 0 16 | assert_eq!(scope.height(), 0); 17 | } 18 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/reallylong.rsx: -------------------------------------------------------------------------------- 1 | pub static Icon3: Component<()> = |cx| { 2 | cx.render(rsx! { 3 | svg { 4 | class: "w-6 h-6", 5 | stroke_linecap: "round", 6 | fill: "none", 7 | stroke_linejoin: "round", 8 | stroke_width: "2", 9 | stroke: "currentColor", 10 | view_box: "0 0 24 24", 11 | path { d: "M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" } 12 | circle { cx: "12", cy: "7", r: "4" } 13 | } 14 | }) 15 | }; 16 | -------------------------------------------------------------------------------- /packages/html/src/events/focus.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type FocusEvent = Event; 4 | 5 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 6 | #[derive(Debug, Clone, PartialEq, Eq)] 7 | pub struct FocusData {/* DOMEventInner: Send + SyncTarget relatedTarget */} 8 | 9 | impl_event! [ 10 | FocusData; 11 | 12 | /// onfocus 13 | onfocus 14 | 15 | // onfocusout 16 | onfocusout 17 | 18 | // onfocusin 19 | onfocusin 20 | 21 | /// onblur 22 | onblur 23 | ]; 24 | -------------------------------------------------------------------------------- /examples/textarea.rs: -------------------------------------------------------------------------------- 1 | // How to use textareas 2 | 3 | use dioxus::prelude::*; 4 | 5 | fn main() { 6 | dioxus_desktop::launch(app); 7 | } 8 | 9 | fn app(cx: Scope) -> Element { 10 | let model = use_state(cx, || String::from("asd")); 11 | 12 | println!("{model}"); 13 | 14 | cx.render(rsx! { 15 | textarea { 16 | class: "border", 17 | rows: "10", 18 | cols: "80", 19 | value: "{model}", 20 | oninput: move |e| model.set(e.value.clone()), 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /packages/extension/README.md: -------------------------------------------------------------------------------- 1 | # Dioxus VSCode Extension 2 | 3 | ![Dioxus Logo](https://dioxuslabs.com/guide/images/dioxuslogo_full.png) 4 | 5 | This extension wraps functionality in Dioxus CLI to be used in your editor! Make sure the dioxus-cli is installed before using this extension. 6 | 7 | ## Current commands: 8 | 9 | ### Convert HTML to RSX 10 | Converts a selection of html to valid rsx. 11 | 12 | ### Convert HTML to Dioxus Component 13 | 14 | Converts a selection of html to a valid Dioxus component with all SVGs factored out into their own module. 15 | -------------------------------------------------------------------------------- /examples/callback.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let login = use_callback!(cx, move |_| async move { 9 | let res = reqwest::get("https://dog.ceo/api/breeds/list/all") 10 | .await 11 | .unwrap() 12 | .text() 13 | .await 14 | .unwrap(); 15 | 16 | println!("{res:#?}, "); 17 | }); 18 | 19 | cx.render(rsx! { 20 | button { onclick: login, "Click me!" } 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /packages/html/src/events/composition.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type CompositionEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct CompositionData { 7 | pub data: String, 8 | } 9 | 10 | impl_event! [ 11 | CompositionData; 12 | 13 | /// oncompositionstart 14 | oncompositionstart 15 | 16 | /// oncompositionend 17 | oncompositionend 18 | 19 | /// oncompositionupdate 20 | oncompositionupdate 21 | ]; 22 | -------------------------------------------------------------------------------- /packages/core/compile_tests/props_safety_temporary_values.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() {} 4 | 5 | fn app(cx: Scope) -> Element { 6 | let count = vec![1, 2, 3]; 7 | 8 | render! { 9 | unsafe_child_component { 10 | borrowed: &count 11 | } 12 | } 13 | } 14 | 15 | #[derive(Props)] 16 | struct Testing<'a> { 17 | borrowed: &'a Vec, 18 | } 19 | 20 | fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { 21 | cx.render(rsx! { 22 | div { "{cx.props.borrowed:?}" } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /examples/PWA-example/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-pwa-example" 3 | version = "0.1.0" 4 | authors = ["Antonio Curavalea "] 5 | edition = "2021" 6 | publish = false 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | dioxus = { path = "../../packages/dioxus", version = "*" } 12 | dioxus-web = { path = "../../packages/web", version = "*" } 13 | 14 | log = "0.4.6" 15 | 16 | # WebAssembly Debug 17 | wasm-logger = "0.2.0" 18 | console_error_panic_hook = "0.1.7" 19 | -------------------------------------------------------------------------------- /examples/clock.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_signals::use_signal; 3 | 4 | fn main() { 5 | dioxus_desktop::launch(app); 6 | } 7 | 8 | fn app(cx: Scope) -> Element { 9 | let mut count = use_signal(cx, || 0); 10 | 11 | use_future!(cx, || async move { 12 | loop { 13 | tokio::time::sleep(std::time::Duration::from_millis(100)).await; 14 | count += 1; 15 | println!("current: {count}"); 16 | } 17 | }); 18 | 19 | cx.render(rsx! { 20 | div { "High-Five counter: {count}" } 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /packages/mobile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-mobile" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2018" 6 | description = "Mobile-compatible renderer for Dioxus" 7 | repository = "https://github.com/DioxusLabs/dioxus/" 8 | homepage = "https://dioxuslabs.com/learn/0.4/getting_started/mobile" 9 | keywords = ["dom", "ui", "gui", "react"] 10 | license = "MIT OR Apache-2.0" 11 | 12 | [dependencies] 13 | dioxus-desktop = { workspace = true } 14 | 15 | [lib] 16 | doctest = false 17 | # tests suspended until package ready 18 | test = false 19 | -------------------------------------------------------------------------------- /examples/generic_component.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Display; 2 | 3 | use dioxus::prelude::*; 4 | 5 | fn main() { 6 | dioxus_desktop::launch(app); 7 | } 8 | 9 | fn app(cx: Scope) -> Element { 10 | cx.render(rsx! { generic_child { 11 | data: 0i32 12 | } }) 13 | } 14 | 15 | #[derive(PartialEq, Props)] 16 | struct GenericChildProps { 17 | data: T, 18 | } 19 | 20 | fn generic_child(cx: Scope>) -> Element { 21 | let data = &cx.props.data; 22 | 23 | cx.render(rsx! { div { 24 | "{data}" 25 | } }) 26 | } 27 | -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/command.md: -------------------------------------------------------------------------------- 1 | # Command Functions 2 | 3 | You can use command functions to execute code and scripts. 4 | 5 | Type definition: 6 | ``` 7 | Stdio: "Inherit" | "Piped" | "Null" 8 | ``` 9 | 10 | ### `exec(commands: [string], stdout: Stdio, stderr: Stdio)` 11 | 12 | You can use this function to run some commands on the current system. 13 | 14 | ```lua 15 | local cmd = plugin.command 16 | 17 | manager.test = function () 18 | cmd.exec({"git", "clone", "https://github.com/DioxusLabs/cli-plugin-library"}) 19 | end 20 | ``` 21 | > Warning: This function doesn't catch exceptions. -------------------------------------------------------------------------------- /packages/fermi/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fermi" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2018" 6 | description = "Global state management for Dioxus" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react", "state-management"] 11 | 12 | 13 | 14 | [dependencies] 15 | dioxus-core = { workspace = true } 16 | im-rc = { version = "15.0.0", features = ["serde"] } 17 | tracing = { workspace = true } 18 | 19 | [dev-dependencies] 20 | closure = "0.3.0" 21 | -------------------------------------------------------------------------------- /packages/core/compile_tests/props_safety_temporary_values.stderr: -------------------------------------------------------------------------------- 1 | error[E0515]: cannot return value referencing local variable `count` 2 | --> compile_tests/props_safety_temporary_values.rs:8:5 3 | | 4 | 8 | / render! { 5 | 9 | | unsafe_child_component { 6 | 10 | | borrowed: &count 7 | | | ------ `count` is borrowed here 8 | 11 | | } 9 | 12 | | } 10 | | |_____^ returns a value referencing data owned by the current function 11 | | 12 | = note: this error originates in the macro `render` (in Nightly builds, run with -Z macro-backtrace for more info) 13 | -------------------------------------------------------------------------------- /packages/extension/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /**@type {import('eslint').Linter.Config} */ 2 | // eslint-disable-next-line no-undef 3 | module.exports = { 4 | root: true, 5 | parser: '@typescript-eslint/parser', 6 | plugins: [ 7 | '@typescript-eslint', 8 | ], 9 | extends: [ 10 | 'eslint:recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | ], 13 | rules: { 14 | 'semi': [2, "always"], 15 | '@typescript-eslint/no-unused-vars': 0, 16 | '@typescript-eslint/no-explicit-any': 0, 17 | '@typescript-eslint/explicit-module-boundary-types': 0, 18 | '@typescript-eslint/no-non-null-assertion': 0, 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /packages/html/src/events/animation.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type AnimationEvent = Event; 4 | 5 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 6 | #[derive(Debug, Clone, PartialEq)] 7 | pub struct AnimationData { 8 | pub animation_name: String, 9 | pub pseudo_element: String, 10 | pub elapsed_time: f32, 11 | } 12 | 13 | impl_event! [ 14 | AnimationData; 15 | 16 | /// onanimationstart 17 | onanimationstart 18 | 19 | /// onanimationend 20 | onanimationend 21 | 22 | /// onanimationiteration 23 | onanimationiteration 24 | ]; 25 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/long_exprs.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | div { 4 | div { 5 | div { 6 | section { class: "body-font overflow-hidden dark:bg-ideblack", 7 | div { class: "container px-6 mx-auto", 8 | div { class: "-my-8 divide-y-2 divide-gray-100", 9 | POSTS.iter().enumerate().map(|(id, post)| rsx! { BlogPostItem { post: post, id: id } }) 10 | } 11 | } 12 | } 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/PWA-example/src/main.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | // init debug tool for WebAssembly 5 | wasm_logger::init(wasm_logger::Config::default()); 6 | console_error_panic_hook::set_once(); 7 | 8 | dioxus_web::launch(app); 9 | } 10 | 11 | fn app(cx: Scope) -> Element { 12 | cx.render(rsx! ( 13 | div { 14 | style: "text-align: center;", 15 | h1 { "🌗 Dioxus 🚀" } 16 | h3 { "Frontend that scales." } 17 | p { "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust." } 18 | } 19 | )) 20 | } 21 | -------------------------------------------------------------------------------- /packages/cli/src/plugin/interface/os.rs: -------------------------------------------------------------------------------- 1 | use mlua::UserData; 2 | 3 | pub struct PluginOS; 4 | impl UserData for PluginOS { 5 | fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { 6 | methods.add_function("current_platform", |_, ()| { 7 | if cfg!(target_os = "windows") { 8 | Ok("windows") 9 | } else if cfg!(target_os = "macos") { 10 | Ok("macos") 11 | } else if cfg!(target_os = "linux") { 12 | Ok("linux") 13 | } else { 14 | panic!("unsupported platformm"); 15 | } 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/disabled.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let disabled = use_state(cx, || false); 9 | 10 | cx.render(rsx! { 11 | div { 12 | button { 13 | onclick: move |_| disabled.set(!disabled), 14 | "click to " 15 | if disabled == true { "enable" } else { "disable" } 16 | " the lower button" 17 | } 18 | 19 | button { 20 | disabled: "{disabled}", 21 | "lower button" 22 | } 23 | } 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /examples/window_zoom.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_desktop::use_window; 3 | 4 | fn main() { 5 | dioxus_desktop::launch(app); 6 | } 7 | 8 | fn app(cx: Scope) -> Element { 9 | let window = use_window(cx); 10 | let level = use_state(cx, || 1.0); 11 | 12 | cx.render(rsx! { 13 | input { 14 | r#type: "number", 15 | value: "{level}", 16 | oninput: |e| { 17 | if let Ok(new_zoom) = e.value.parse::() { 18 | level.set(new_zoom); 19 | window.webview.zoom(new_zoom); 20 | } 21 | } 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /packages/rsx/src/hot_reload/hot_reloading_context.rs: -------------------------------------------------------------------------------- 1 | pub trait HotReloadingContext { 2 | fn map_attribute( 3 | element_name_rust: &str, 4 | attribute_name_rust: &str, 5 | ) -> Option<(&'static str, Option<&'static str>)>; 6 | fn map_element(element_name_rust: &str) -> Option<(&'static str, Option<&'static str>)>; 7 | } 8 | 9 | pub struct Empty; 10 | 11 | impl HotReloadingContext for Empty { 12 | fn map_attribute(_: &str, _: &str) -> Option<(&'static str, Option<&'static str>)> { 13 | None 14 | } 15 | 16 | fn map_element(_: &str) -> Option<(&'static str, Option<&'static str>)> { 17 | None 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/multiwindow.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let window = dioxus_desktop::use_window(cx); 9 | 10 | cx.render(rsx! { 11 | div { 12 | button { 13 | onclick: move |_| { 14 | let dom = VirtualDom::new(popup); 15 | window.new_window(dom, Default::default()); 16 | }, 17 | "New Window" 18 | } 19 | } 20 | }) 21 | } 22 | 23 | fn popup(cx: Scope) -> Element { 24 | cx.render(rsx! { 25 | div { "This is a popup!" } 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /packages/cli/examples/plugin/interface.lua: -------------------------------------------------------------------------------- 1 | local interface = {} 2 | 3 | if plugin_logger ~= nil then 4 | interface.log = plugin_logger 5 | else 6 | interface.log = { 7 | trace = function (info) 8 | print("trace: " .. info) 9 | end, 10 | debug = function (info) 11 | print("debug: " .. info) 12 | end, 13 | info = function (info) 14 | print("info: " .. info) 15 | end, 16 | warn = function (info) 17 | print("warn: " .. info) 18 | end, 19 | error = function (info) 20 | print("error: " .. info) 21 | end, 22 | } 23 | end 24 | 25 | return interface -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-desktop/src/server.rs: -------------------------------------------------------------------------------- 1 | // Run with: 2 | // ```bash 3 | // cargo run --bin server --features ssr 4 | // ``` 5 | 6 | use axum_desktop::*; 7 | use dioxus_fullstack::prelude::*; 8 | 9 | #[tokio::main] 10 | async fn main() { 11 | let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); 12 | 13 | let _ = PostServerData::register_explicit(); 14 | let _ = GetServerData::register_explicit(); 15 | 16 | axum::Server::bind(&addr) 17 | .serve( 18 | axum::Router::new() 19 | .register_server_fns("") 20 | .into_make_service(), 21 | ) 22 | .await 23 | .unwrap(); 24 | } 25 | -------------------------------------------------------------------------------- /packages/signals/examples/selector.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_signals::*; 3 | 4 | fn main() { 5 | dioxus_desktop::launch(App); 6 | } 7 | 8 | #[component] 9 | fn App(cx: Scope) -> Element { 10 | let signal = use_signal(cx, || 0); 11 | let doubled = use_selector(cx, move || signal * 2); 12 | 13 | render! { 14 | button { 15 | onclick: move |_| *signal.write() += 1, 16 | "Increase" 17 | } 18 | Child { 19 | signal: doubled 20 | } 21 | } 22 | } 23 | 24 | #[component] 25 | fn Child(cx: Scope, signal: ReadOnlySignal) -> Element { 26 | render! { 27 | "{signal}" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/cli/docs/src/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The 📦✨ **Dioxus CLI** is a tool to help get Dioxus projects off the ground. 4 | 5 | ## Features 6 | 7 | * Build and pack a Dioxus project 8 | * `html` to `rsx` conversion tool 9 | * Hot Reload for `web` platform 10 | * Create a Dioxus project from `git` repo 11 | * And more! 12 | -------------------------------------------------------------------------------- /packages/cli/src/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {app_title} 5 | 6 | 7 | 8 | {style_include} 9 | 10 | 11 |
12 | 20 | {script_include} 21 | 22 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "axum-hello-world" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus = { workspace = true } 11 | dioxus-fullstack = { workspace = true } 12 | axum = { version = "0.6.12", optional = true } 13 | serde = "1.0.159" 14 | simple_logger = "4.2.0" 15 | tracing-wasm = "0.2.1" 16 | tracing.workspace = true 17 | tracing-subscriber = "0.3.17" 18 | reqwest = "0.11.18" 19 | 20 | [features] 21 | default = [] 22 | ssr = ["axum", "dioxus-fullstack/axum"] 23 | web = ["dioxus-fullstack/web"] 24 | -------------------------------------------------------------------------------- /packages/signals/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-signals" 3 | authors = ["Jonathan Kelley"] 4 | version = "0.0.0" 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-core = { workspace = true } 11 | generational-box = { workspace = true } 12 | tracing = { workspace = true } 13 | simple_logger = "4.2.0" 14 | serde = { version = "1", features = ["derive"], optional = true } 15 | 16 | [dev-dependencies] 17 | dioxus = { workspace = true } 18 | dioxus-desktop = { workspace = true } 19 | tokio = { version = "1", features = ["full"] } 20 | 21 | [features] 22 | default = [] 23 | serialize = ["serde"] -------------------------------------------------------------------------------- /examples/tailwind/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-tailwind" 3 | version = "0.0.0" 4 | authors = [] 5 | edition = "2021" 6 | description = "A tailwindcss example using Dioxus" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | documentation = "https://dioxuslabs.com" 11 | rust-version = "1.60.0" 12 | publish = false 13 | 14 | [dependencies] 15 | dioxus = { path = "../../packages/dioxus" } 16 | 17 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 18 | dioxus-desktop = { path = "../../packages/desktop" } 19 | 20 | [target.'cfg(target_arch = "wasm32")'.dependencies] 21 | dioxus-web = { path = "../../packages/web" } -------------------------------------------------------------------------------- /packages/fullstack/examples/static-hydrated/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "static-hydrated" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-web = { workspace = true, features = ["hydrate"], optional = true } 11 | dioxus = { workspace = true } 12 | dioxus-fullstack = { workspace = true, features = ["router"] } 13 | dioxus-router = { workspace = true} 14 | tokio = { workspace = true, features = ["full"], optional = true } 15 | serde = "1.0.159" 16 | 17 | [features] 18 | default = [] 19 | ssr = ["tokio", "dioxus-fullstack/ssr"] 20 | web = ["dioxus-web"] 21 | -------------------------------------------------------------------------------- /packages/router-macro/src/query.rs: -------------------------------------------------------------------------------- 1 | use quote::quote; 2 | use syn::{Ident, Type}; 3 | 4 | use proc_macro2::TokenStream as TokenStream2; 5 | 6 | #[derive(Debug)] 7 | pub struct QuerySegment { 8 | pub ident: Ident, 9 | pub ty: Type, 10 | } 11 | 12 | impl QuerySegment { 13 | pub fn parse(&self) -> TokenStream2 { 14 | let ident = &self.ident; 15 | let ty = &self.ty; 16 | quote! { 17 | let #ident = <#ty as dioxus_router::routable::FromQuery>::from_query(&*query); 18 | } 19 | } 20 | 21 | pub fn write(&self) -> TokenStream2 { 22 | let ident = &self.ident; 23 | quote! { 24 | write!(f, "?{}", #ident)?; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/signals/examples/context.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | use dioxus_signals::Signal; 5 | 6 | fn main() { 7 | dioxus_desktop::launch(app); 8 | } 9 | 10 | fn app(cx: Scope) -> Element { 11 | // Because signal is never read in this component, this component will not rerun when the signal changes 12 | use_context_provider(cx, || Signal::new(0)); 13 | 14 | render! { 15 | Child {} 16 | } 17 | } 18 | 19 | fn Child(cx: Scope) -> Element { 20 | let signal: Signal = *use_context(cx).unwrap(); 21 | // This component does read from the signal, so when the signal changes it will rerun 22 | render! { 23 | "{signal}" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/xss_safety.rs: -------------------------------------------------------------------------------- 1 | //! XSS Safety 2 | //! 3 | //! This example proves that Dioxus is safe from XSS attacks. 4 | 5 | use dioxus::prelude::*; 6 | 7 | fn main() { 8 | dioxus_desktop::launch(app); 9 | } 10 | 11 | fn app(cx: Scope) -> Element { 12 | let contents = use_state(cx, || { 13 | String::from("") 14 | }); 15 | 16 | cx.render(rsx! { 17 | div { 18 | h1 {"Dioxus is XSS-Safe"} 19 | h3 { "{contents}" } 20 | input { 21 | value: "{contents}", 22 | r#type: "text", 23 | oninput: move |e| contents.set(e.value.clone()), 24 | } 25 | } 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /packages/core/tests/bubble_error.rs: -------------------------------------------------------------------------------- 1 | //! we should properly bubble up errors from components 2 | 3 | use dioxus::prelude::*; 4 | 5 | fn app(cx: Scope) -> Element { 6 | let raw = match cx.generation() % 2 { 7 | 0 => "123.123", 8 | 1 => "123.123.123", 9 | _ => unreachable!(), 10 | }; 11 | 12 | let value = raw.parse::().unwrap_or(123.123); 13 | 14 | cx.render(rsx! { 15 | div { "hello {value}" } 16 | }) 17 | } 18 | 19 | #[test] 20 | fn bubbles_error() { 21 | let mut dom = VirtualDom::new(app); 22 | 23 | { 24 | let _edits = dom.rebuild().santize(); 25 | } 26 | 27 | dom.mark_dirty(ScopeId::ROOT); 28 | 29 | _ = dom.render_immediate(); 30 | } 31 | -------------------------------------------------------------------------------- /packages/rsx-rosetta/examples/html.rs: -------------------------------------------------------------------------------- 1 | use html_parser::Dom; 2 | 3 | fn main() { 4 | let html = r#" 5 |
6 |
hello world!
7 |
hello world!
8 |
hello world!
9 |
hello world!
10 |
hello world!
11 |
hello world!
12 | hello world! 13 |
14 | "# 15 | .trim(); 16 | 17 | let dom = Dom::parse(html).unwrap(); 18 | 19 | let body = rsx_rosetta::rsx_from_html(&dom); 20 | 21 | let out = dioxus_autofmt::write_block_out(body).unwrap(); 22 | 23 | println!("{out}"); 24 | } 25 | -------------------------------------------------------------------------------- /packages/fermi/src/atoms/atomref.rs: -------------------------------------------------------------------------------- 1 | use crate::{AtomId, AtomRoot, Readable}; 2 | use std::cell::RefCell; 3 | 4 | pub struct AtomRefBuilder; 5 | pub struct AtomRef(pub fn(AtomRefBuilder) -> T); 6 | 7 | impl Readable> for &'static AtomRef { 8 | fn read(&self, _root: AtomRoot) -> Option> { 9 | todo!() 10 | } 11 | 12 | fn init(&self) -> RefCell { 13 | RefCell::new(self.0(AtomRefBuilder)) 14 | } 15 | 16 | fn unique_id(&self) -> AtomId { 17 | *self as *const AtomRef as *const () 18 | } 19 | } 20 | 21 | #[test] 22 | fn atom_compiles() { 23 | static TEST_ATOM: AtomRef> = AtomRef(|_| vec![]); 24 | dbg!((&TEST_ATOM).init()); 25 | } 26 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/manual_props.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | Component { 4 | adsasd: "asd", 5 | onclick: move |_| { 6 | let a = a; 7 | }, 8 | div { "thing" } 9 | } 10 | Component { 11 | asdasd: "asdasd", 12 | asdasd: "asdasdasdasdasdasdasdasdasdasd", 13 | ..Props { a: 10, b: 20 } 14 | } 15 | Component { 16 | asdasd: "asdasd", 17 | ..Props { 18 | a: 10, 19 | b: 20, 20 | c: { 21 | fn main() {} 22 | }, 23 | }, 24 | "content" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/dioxus-tui/examples/list.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_tui::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx! { 9 | div { 10 | width: "100%", 11 | height: "100%", 12 | flex_direction: "column", 13 | border_width: "1px", 14 | 15 | h1 { height: "2px", color: "green", 16 | "that's awesome!" 17 | } 18 | 19 | ul { 20 | flex_direction: "column", 21 | padding_left: "3px", 22 | (0..10).map(|i| rsx!( 23 | "> hello {i}" 24 | )) 25 | } 26 | } 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /examples/drops.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let count = if cx.generation() % 2 == 0 { 10 } else { 0 }; 9 | 10 | println!("Generation: {}", cx.generation()); 11 | 12 | if cx.generation() < 10 { 13 | cx.needs_update(); 14 | } 15 | 16 | render! { 17 | (0..count).map(|_| rsx!{ 18 | drop_child {} 19 | }) 20 | } 21 | } 22 | 23 | fn drop_child(cx: Scope) -> Element { 24 | cx.use_hook(|| Drops); 25 | render! { 26 | div{} 27 | } 28 | } 29 | 30 | struct Drops; 31 | 32 | impl Drop for Drops { 33 | fn drop(&mut self) { 34 | println!("Dropped!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/core/tests/error_boundary.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | 5 | #[test] 6 | fn catches_panic() { 7 | let mut dom = VirtualDom::new(app); 8 | _ = dom.rebuild(); 9 | } 10 | 11 | fn app(cx: Scope) -> Element { 12 | cx.render(rsx! { 13 | div { 14 | h1 { "Title" } 15 | 16 | NoneChild {} 17 | ThrowChild {} 18 | } 19 | }) 20 | } 21 | 22 | fn NoneChild(_cx: Scope) -> Element { 23 | None 24 | } 25 | 26 | fn ThrowChild(cx: Scope) -> Element { 27 | cx.throw(std::io::Error::new(std::io::ErrorKind::AddrInUse, "asd"))?; 28 | 29 | let _g: i32 = "123123".parse().throw(cx)?; 30 | 31 | cx.render(rsx! { 32 | div {} 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /examples/signals.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use std::time::Duration; 3 | 4 | fn main() { 5 | dioxus_desktop::launch(app); 6 | } 7 | 8 | fn app(cx: Scope) -> Element { 9 | let mut count = dioxus_signals::use_signal(cx, || 0); 10 | 11 | use_future!(cx, || async move { 12 | loop { 13 | count += 1; 14 | tokio::time::sleep(Duration::from_millis(400)).await; 15 | } 16 | }); 17 | 18 | cx.render(rsx! { 19 | h1 { "High-Five counter: {count}" } 20 | button { onclick: move |_| count += 1, "Up high!" } 21 | button { onclick: move |_| count -= 1, "Down low!" } 22 | 23 | if count.value() > 5 { 24 | rsx!{ h2 { "High five!" } } 25 | } 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /packages/core/tests/boolattrs.rs: -------------------------------------------------------------------------------- 1 | use bumpalo::Bump; 2 | use dioxus::core::{ElementId, Mutation::*}; 3 | use dioxus::prelude::*; 4 | 5 | #[test] 6 | fn bool_test() { 7 | let mut app = VirtualDom::new(|cx| cx.render(rsx!(div { hidden: false }))); 8 | let bump = Bump::new(); 9 | 10 | assert_eq!( 11 | app.rebuild().santize().edits, 12 | [ 13 | LoadTemplate { name: "template", index: 0, id: ElementId(1) }, 14 | SetAttribute { 15 | name: "hidden", 16 | value: (&*bump.alloc(false.into_value(&bump))).into(), 17 | id: ElementId(1,), 18 | ns: None 19 | }, 20 | AppendChildren { m: 1, id: ElementId(0) }, 21 | ] 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/native-core-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-native-core-macro" 3 | version = { workspace = true } 4 | edition = "2021" 5 | description = "Build natively rendered apps with Dioxus" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/DioxusLabs/dioxus/" 8 | homepage = "https://dioxuslabs.com" 9 | keywords = ["dom", "ui", "gui", "react"] 10 | authors = ["Jonathan Kelley", "Evan Almloff"] 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | syn = { version = "2.0", features = ["extra-traits", "full"] } 17 | quote = "1.0" 18 | 19 | [dev-dependencies] 20 | smallvec = "1.6" 21 | rustc-hash = { workspace = true } 22 | anymap = "0.12.1" 23 | dioxus = { workspace = true } 24 | dioxus-native-core = { workspace = true } 25 | -------------------------------------------------------------------------------- /playwright-tests/fullstack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-playwright-fullstack-test" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-web = { path = "../../packages/web", features=["hydrate"], optional = true } 11 | dioxus = { path = "../../packages/dioxus" } 12 | dioxus-fullstack = { path = "../../packages/fullstack" } 13 | axum = { version = "0.6.12", optional = true } 14 | tokio = { version = "1.27.0", features = ["full"], optional = true } 15 | serde = "1.0.159" 16 | execute = "0.2.12" 17 | 18 | [features] 19 | default = [] 20 | ssr = ["axum", "tokio", "dioxus-fullstack/axum"] 21 | web = ["dioxus-web"] 22 | -------------------------------------------------------------------------------- /packages/router-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-router-macro" 3 | version = { workspace = true } 4 | authors = ["Evan Almloff"] 5 | edition = "2021" 6 | description = "Macro for Dioxus Router" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | documentation = "https://dioxuslabs.com" 11 | keywords = ["dom", "ui", "gui", "react", "router"] 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [lib] 15 | proc-macro = true 16 | 17 | [dependencies] 18 | syn = { version = "2.0", features = ["extra-traits", "full"] } 19 | quote = "1.0" 20 | proc-macro2 = "1.0.56" 21 | slab = "0.4" 22 | 23 | [features] 24 | default = [] 25 | -------------------------------------------------------------------------------- /packages/html/src/events/touch.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | pub type TouchEvent = Event; 4 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 5 | #[derive(Debug, Clone, PartialEq, Eq)] 6 | pub struct TouchData { 7 | pub alt_key: bool, 8 | pub ctrl_key: bool, 9 | pub meta_key: bool, 10 | pub shift_key: bool, 11 | // get_modifier_state: bool, 12 | // changedTouches: DOMTouchList, 13 | // targetTouches: DOMTouchList, 14 | // touches: DOMTouchList, 15 | } 16 | 17 | impl_event! { 18 | TouchData; 19 | /// touchstart 20 | ontouchstart 21 | 22 | /// touchmove 23 | ontouchmove 24 | 25 | /// touchend 26 | ontouchend 27 | 28 | /// touchcancel 29 | ontouchcancel 30 | } 31 | -------------------------------------------------------------------------------- /packages/ssr/tests/inner_html.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[test] 4 | fn static_inner_html() { 5 | fn app(cx: Scope) -> Element { 6 | render! { div { dangerous_inner_html: "
1234
" } } 7 | } 8 | 9 | let mut dom = VirtualDom::new(app); 10 | _ = dom.rebuild(); 11 | 12 | assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); 13 | } 14 | 15 | #[test] 16 | fn dynamic_inner_html() { 17 | fn app(cx: Scope) -> Element { 18 | let inner_html = "
1234
"; 19 | render! { div { dangerous_inner_html: "{inner_html}" } } 20 | } 21 | 22 | let mut dom = VirtualDom::new(app); 23 | _ = dom.rebuild(); 24 | 25 | assert_eq!(dioxus_ssr::render(&dom), r#"
1234
"#); 26 | } 27 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/comments.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | // Comments 4 | class: "asdasd", 5 | "hello world" 6 | } 7 | div { 8 | // My comment here 1 9 | // My comment here 2 10 | // My comment here 3 11 | // My comment here 4 12 | class: "asdasd", 13 | 14 | // Comment here 15 | onclick: move |_| { 16 | let a = 10; 17 | let b = 40; 18 | let c = 50; 19 | }, 20 | 21 | // my comment 22 | 23 | // This here 24 | "hi" 25 | } 26 | 27 | // Comment head 28 | div { class: "asd", "Jon" } 29 | 30 | // Comment head 31 | div { 32 | // Collapse 33 | class: "asd", 34 | "Jon" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/core/compile_tests/props_safety.stderr: -------------------------------------------------------------------------------- 1 | error[E0521]: borrowed data escapes outside of function 2 | --> compile_tests/props_safety.rs:8:5 3 | | 4 | 5 | fn app(cx: Scope) -> Element { 5 | | -- 6 | | | 7 | | `cx` is a reference that is only valid in the function body 8 | | has type `&'1 Scoped<'1>` 9 | ... 10 | 8 | / render! { 11 | 9 | | unsafe_child_component { 12 | 10 | | borrowed: count 13 | 11 | | } 14 | 12 | | } 15 | | | ^ 16 | | | | 17 | | |_____`cx` escapes the function body here 18 | | argument requires that `'1` must outlive `'static` 19 | | 20 | = note: this error originates in the macro `render` (in Nightly builds, run with -Z macro-backtrace for more info) 21 | -------------------------------------------------------------------------------- /packages/fermi/src/atoms/atomfamily.rs: -------------------------------------------------------------------------------- 1 | use crate::{AtomId, AtomRoot, Readable, Writable}; 2 | use im_rc::HashMap as ImMap; 3 | 4 | pub struct AtomFamilyBuilder; 5 | pub struct AtomFamily(pub fn(AtomFamilyBuilder) -> ImMap); 6 | 7 | impl Readable> for &'static AtomFamily { 8 | fn read(&self, _root: AtomRoot) -> Option> { 9 | todo!() 10 | } 11 | 12 | fn init(&self) -> ImMap { 13 | self.0(AtomFamilyBuilder) 14 | } 15 | 16 | fn unique_id(&self) -> AtomId { 17 | *self as *const AtomFamily as *const () 18 | } 19 | } 20 | 21 | impl Writable> for &'static AtomFamily { 22 | fn write(&self, _root: AtomRoot, _value: ImMap) { 23 | todo!() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/interpreter/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub static INTERPRETER_JS: &str = include_str!("./interpreter.js"); 2 | pub static COMMON_JS: &str = include_str!("./common.js"); 3 | 4 | #[cfg(feature = "sledgehammer")] 5 | mod sledgehammer_bindings; 6 | #[cfg(feature = "sledgehammer")] 7 | pub use sledgehammer_bindings::*; 8 | 9 | #[cfg(feature = "web")] 10 | mod bindings; 11 | 12 | #[cfg(feature = "web")] 13 | pub use bindings::Interpreter; 14 | 15 | // Common bindings for minimal usage. 16 | #[cfg(feature = "minimal_bindings")] 17 | pub mod minimal_bindings { 18 | use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; 19 | #[wasm_bindgen(module = "/src/common.js")] 20 | extern "C" { 21 | pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/hooks/src/usecontext.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::ScopeState; 2 | 3 | /// Consume some context in the tree, providing a sharable handle to the value 4 | /// 5 | /// Does not regenerate the value if the value is changed at the parent. 6 | pub fn use_context(cx: &ScopeState) -> Option<&T> { 7 | cx.use_hook(|| cx.consume_context::()).as_ref() 8 | } 9 | 10 | /// Provide some context via the tree and return a reference to it 11 | /// 12 | /// Once the context has been provided, it is immutable. Mutations should be done via interior mutability. 13 | pub fn use_context_provider(cx: &ScopeState, f: impl FnOnce() -> T) -> &T { 14 | cx.use_hook(|| { 15 | let val = f(); 16 | cx.provide_context(val.clone()); 17 | val 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /packages/router/src/history/web_scroll.rs: -------------------------------------------------------------------------------- 1 | use gloo::render::{request_animation_frame, AnimationFrame}; 2 | use web_sys::Window; 3 | 4 | #[derive(Clone, Copy, Debug, Default)] 5 | #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] 6 | pub(crate) struct ScrollPosition { 7 | pub x: f64, 8 | pub y: f64, 9 | } 10 | 11 | impl ScrollPosition { 12 | pub(crate) fn of_window(window: &Window) -> Self { 13 | Self { 14 | x: window.scroll_x().unwrap_or_default(), 15 | y: window.scroll_y().unwrap_or_default(), 16 | } 17 | } 18 | 19 | pub(crate) fn scroll_to(&self, window: Window) -> AnimationFrame { 20 | let Self { x, y } = *self; 21 | request_animation_frame(move |_| window.scroll_to_with_x_and_y(x, y)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/heavy_compute.rs: -------------------------------------------------------------------------------- 1 | //! This example shows that you can place heavy work on the main thread, and then 2 | //! 3 | //! You *should* be using `tokio::spawn_blocking` instead. 4 | //! 5 | //! Your app runs in an async runtime (Tokio), so you should avoid blocking 6 | //! the rendering of the VirtualDom. 7 | //! 8 | //! 9 | 10 | use dioxus::prelude::*; 11 | 12 | fn main() { 13 | dioxus_desktop::launch(app); 14 | } 15 | 16 | fn app(cx: Scope) -> Element { 17 | // This is discouraged 18 | std::thread::sleep(std::time::Duration::from_millis(2_000)); 19 | 20 | // This is suggested 21 | tokio::task::spawn_blocking(move || { 22 | std::thread::sleep(std::time::Duration::from_millis(2_000)); 23 | }); 24 | 25 | cx.render(rsx! { 26 | div { "Hello, world!" } 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-router/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "axum-router" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-web = { workspace = true, features = ["hydrate"], optional = true } 11 | dioxus = { workspace = true } 12 | dioxus-router = { workspace = true } 13 | dioxus-fullstack = { workspace = true, features = ["router"] } 14 | axum = { version = "0.6.12", optional = true } 15 | tokio = {workspace = true, features = ["full"], optional = true } 16 | serde = { version = "1.0.159", features = ["derive"] } 17 | 18 | [features] 19 | default = [] 20 | ssr = ["axum", "dioxus-fullstack/axum"] 21 | web = ["dioxus-fullstack/web", "dioxus-router/web"] 22 | -------------------------------------------------------------------------------- /packages/cli/src/assets/autoreload.js: -------------------------------------------------------------------------------- 1 | // Dioxus-CLI 2 | // https://github.com/DioxusLabs/cli 3 | 4 | (function () { 5 | var protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; 6 | var url = protocol + '//' + window.location.host + '/_dioxus/ws'; 7 | var poll_interval = 8080; 8 | var reload_upon_connect = () => { 9 | window.setTimeout( 10 | () => { 11 | var ws = new WebSocket(url); 12 | ws.onopen = () => window.location.reload(); 13 | ws.onclose = reload_upon_connect; 14 | }, 15 | poll_interval); 16 | }; 17 | 18 | var ws = new WebSocket(url); 19 | ws.onmessage = (ev) => { 20 | if (ev.data == "reload") { 21 | window.location.reload(); 22 | } 23 | }; 24 | ws.onclose = reload_upon_connect; 25 | })() -------------------------------------------------------------------------------- /packages/cli/docs/src/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Install the latest development build through git 4 | 5 | To get the latest bug fixes and features, you can install the development version from git. 6 | 7 | ``` 8 | cargo install --git https://github.com/Dioxuslabs/cli 9 | ``` 10 | 11 | This will download `Dioxus-CLI` source from GitHub master branch, 12 | and install it in Cargo's global binary directory (`~/.cargo/bin/` by default). 13 | 14 | ## Install stable through `crates.io` 15 | 16 | The published version of the Dioxus CLI is updated less often, but is more stable than the git version. 17 | 18 | ``` 19 | cargo install dioxus-cli --locked 20 | ``` 21 | 22 | Run `dx --help` for a list of all the available commands. 23 | Furthermore, you can run `dx --help` to get help with a specific command. 24 | -------------------------------------------------------------------------------- /packages/dioxus-tui/examples/border.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_tui::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let radius = use_state(cx, || 0); 9 | 10 | cx.render(rsx! { 11 | div { 12 | width: "100%", 13 | height: "100%", 14 | justify_content: "center", 15 | align_items: "center", 16 | background_color: "hsl(248, 53%, 58%)", 17 | onwheel: move |w| radius.modify(|r| (r + w.delta().strip_units().y as i8).abs()), 18 | 19 | border_style: "solid none solid double", 20 | border_width: "thick", 21 | border_radius: "{radius}px", 22 | border_color: "#0000FF #FF00FF #FF0000 #00FF00", 23 | 24 | "{radius}" 25 | } 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /packages/rsx/src/errors.rs: -------------------------------------------------------------------------------- 1 | macro_rules! missing_trailing_comma { 2 | ($span:expr) => { 3 | return Err(Error::new($span, "missing trailing comma")); 4 | }; 5 | } 6 | 7 | macro_rules! attr_after_element { 8 | ($span:expr) => { 9 | return Err(Error::new($span, "expected element\n = help move the attribute above all the children and text elements")); 10 | }; 11 | } 12 | 13 | macro_rules! component_path_cannot_have_arguments { 14 | ($span:expr) => { 15 | return Err(Error::new( 16 | $span, 17 | "expected a path without arguments\n = try remove the path arguments", 18 | )); 19 | }; 20 | } 21 | 22 | macro_rules! invalid_component_path { 23 | ($span:expr) => { 24 | return Err(Error::new($span, "Invalid component path syntax")); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /.docker/README.md: -------------------------------------------------------------------------------- 1 | # Why this? 2 | 3 | This part is used to test whole package before pushing it 4 | 5 | # How to use it? 6 | 7 | Just run in the folder: 8 | `bash run_local_tests.sh`. If nothing fails, then you can push your code to the repo. 9 | or run: 10 | `bash run_local_tests.sh --with-full-docker-cleanup` 11 | for cleaning up images as well 12 | 13 | # How is it composed of? 14 | 15 | 1. `Dockerfile_pre_test` will build the base image for the tests to be run into 16 | 2. `Dockerfile_test` will run the actual tests based on 1. 17 | 3. `run_local_tests.sh` to wrap this up 18 | 19 | # Warning 20 | 21 | The task requires some amount of CPU work and disk space (5GB per tests). Some clean up is included in the script. 22 | 23 | # Requirements 24 | 25 | * [docker](https://docs.docker.com/engine/install/) 26 | * bash 27 | * rsync -------------------------------------------------------------------------------- /packages/autofmt/tests/wrong.rs: -------------------------------------------------------------------------------- 1 | macro_rules! twoway { 2 | ($val:literal => $name:ident) => { 3 | #[test] 4 | fn $name() { 5 | let src_right = include_str!(concat!("./wrong/", $val, ".rsx")); 6 | let src_wrong = include_str!(concat!("./wrong/", $val, ".wrong.rsx")); 7 | let formatted = dioxus_autofmt::fmt_file(src_wrong); 8 | let out = dioxus_autofmt::apply_formats(src_wrong, formatted); 9 | 10 | // normalize line endings 11 | let out = out.replace("\r", ""); 12 | let src_right = src_right.replace("\r", ""); 13 | 14 | pretty_assertions::assert_eq!(&src_right, &out); 15 | } 16 | }; 17 | } 18 | 19 | twoway!("comments" => comments); 20 | 21 | twoway!("multi" => multi); 22 | 23 | twoway!("multiexpr" => multiexpr); 24 | -------------------------------------------------------------------------------- /packages/core-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-core-macro" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2021" 6 | description = "Core macro for Dioxus Virtual DOM" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react"] 11 | 12 | [lib] 13 | proc-macro = true 14 | 15 | [dependencies] 16 | proc-macro2 = { version = "1.0" } 17 | quote = "1.0" 18 | syn = { version = "2.0", features = ["full", "extra-traits"] } 19 | dioxus-rsx = { workspace = true } 20 | dioxus-core = { workspace = true } 21 | constcat = "0.3.0" 22 | 23 | # testing 24 | [dev-dependencies] 25 | dioxus = { workspace = true } 26 | rustversion = "1.0" 27 | trybuild = "1.0" 28 | 29 | [features] 30 | default = [] 31 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-desktop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "axum-desktop" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | [lib] 8 | 9 | [dependencies] 10 | dioxus-desktop = { workspace = true, optional = true } 11 | dioxus = { workspace = true } 12 | dioxus-router = { workspace = true } 13 | dioxus-fullstack = { workspace = true } 14 | axum = { version = "0.6.12", optional = true } 15 | tokio = { workspace = true, features = ["full"], optional = true } 16 | serde = "1.0.159" 17 | 18 | [features] 19 | default = [] 20 | ssr = ["axum", "tokio", "dioxus-fullstack/axum"] 21 | desktop = ["dioxus-desktop"] 22 | 23 | [[bin]] 24 | name = "client" 25 | path = "src/client.rs" 26 | required-features = ["desktop"] 27 | 28 | [[bin]] 29 | name = "server" 30 | path = "src/server.rs" 31 | required-features = ["ssr"] 32 | -------------------------------------------------------------------------------- /packages/router/src/components/default_errors.rs: -------------------------------------------------------------------------------- 1 | #[allow(deprecated)] 2 | use crate::hooks::use_router; 3 | use dioxus::prelude::*; 4 | 5 | /// The default component to render when an external navigation fails. 6 | #[allow(non_snake_case)] 7 | pub fn FailureExternalNavigation(cx: Scope) -> Element { 8 | #[allow(deprecated)] 9 | let router = use_router(cx); 10 | 11 | render! { 12 | h1 { "External Navigation Failure!" } 13 | p { 14 | "The application tried to programmatically navigate to an external page. This " 15 | "operation has failed. Click the link below to complete the navigation manually." 16 | } 17 | a { 18 | onclick: move |_| { 19 | router.clear_error() 20 | }, 21 | "Click here to go back" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/error_handle.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(App); 5 | } 6 | 7 | #[component] 8 | fn App(cx: Scope) -> Element { 9 | let val = use_state(cx, || "0.0001"); 10 | 11 | let num = match val.parse::() { 12 | Err(_) => return cx.render(rsx!("Parsing failed")), 13 | Ok(num) => num, 14 | }; 15 | 16 | cx.render(rsx! { 17 | h1 { "The parsed value is {num}" } 18 | button { 19 | onclick: move |_| val.set("invalid"), 20 | "Set an invalid number" 21 | } 22 | (0..5).map(|i| rsx! { 23 | DemoC { x: i } 24 | }) 25 | }) 26 | } 27 | 28 | #[component] 29 | fn DemoC(cx: Scope, x: i32) -> Element { 30 | cx.render(rsx! { 31 | h1 { 32 | "asdasdasdasd {x}" 33 | } 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /examples/tasks.rs: -------------------------------------------------------------------------------- 1 | //! Example: README.md showcase 2 | //! 3 | //! The example from the README.md. 4 | 5 | use dioxus::prelude::*; 6 | use std::time::Duration; 7 | 8 | fn main() { 9 | dioxus_desktop::launch(app); 10 | } 11 | 12 | fn app(cx: Scope) -> Element { 13 | let count = use_state(cx, || 0); 14 | 15 | use_future(cx, (), move |_| { 16 | let mut count = count.clone(); 17 | async move { 18 | loop { 19 | tokio::time::sleep(Duration::from_millis(1000)).await; 20 | count += 1; 21 | } 22 | } 23 | }); 24 | 25 | cx.render(rsx! { 26 | div { 27 | h1 { "Current count: {count}" } 28 | button { 29 | onclick: move |_| count.set(0), 30 | "Reset the count" 31 | } 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /packages/autofmt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-autofmt" 3 | version = { workspace = true } 4 | edition = "2021" 5 | authors = ["Jonathan Kelley"] 6 | description = "Autofomatter for Dioxus RSX" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react"] 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | dioxus-rsx = { workspace = true } 15 | proc-macro2 = { version = "1.0.6", features = ["span-locations"] } 16 | quote = "1.0" 17 | syn = { version = "2.0", features = ["full", "extra-traits", "visit"] } 18 | serde = { version = "1.0.136", features = ["derive"] } 19 | prettyplease = { workspace = true } 20 | 21 | [dev-dependencies] 22 | pretty_assertions = "1.2.1" 23 | -------------------------------------------------------------------------------- /packages/web/src/ricpolyfill.js: -------------------------------------------------------------------------------- 1 | const requestIdleCallback = 2 | (typeof self !== 'undefined' && 3 | self.requestIdleCallback && 4 | self.requestIdleCallback.bind(window)) || 5 | function (cb) { 6 | const start = Date.now(); 7 | return setTimeout(() => { 8 | cb({ 9 | didTimeout: false, 10 | timeRemaining: function () { 11 | return Math.max(0, 50 - (Date.now() - start)); 12 | }, 13 | }); 14 | }, 1); 15 | }; 16 | 17 | const cancelIdleCallback = 18 | (typeof self !== 'undefined' && 19 | self.cancelIdleCallback && 20 | self.cancelIdleCallback.bind(window)) || 21 | function (id) { 22 | return clearTimeout(id); 23 | }; 24 | 25 | if (typeof window !== 'undefined') { 26 | window.requestIdleCallback = requestIdleCallback; 27 | window.cancelIdleCallback = cancelIdleCallback; 28 | } 29 | -------------------------------------------------------------------------------- /packages/fullstack/examples/warp-hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "warp-hello-world" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-web = { workspace = true, features=["hydrate"], optional = true } 11 | dioxus = { workspace = true } 12 | dioxus-fullstack = { workspace = true } 13 | tokio = { workspace = true, features = ["full"], optional = true } 14 | serde = "1.0.159" 15 | warp = { version = "0.3.3", optional = true } 16 | execute = "0.2.12" 17 | reqwest = "0.11.18" 18 | simple_logger = "4.2.0" 19 | tracing-wasm = "0.2.1" 20 | tracing.workspace = true 21 | tracing-subscriber = "0.3.17" 22 | 23 | [features] 24 | default = [] 25 | ssr = ["warp", "tokio", "dioxus-fullstack/warp"] 26 | web = ["dioxus-web"] 27 | -------------------------------------------------------------------------------- /packages/fullstack/examples/salvo-hello-world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "salvo-hello-world" 3 | version = "0.1.0" 4 | edition = "2021" 5 | publish = false 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | dioxus-web = { workspace = true, features=["hydrate"], optional = true } 11 | dioxus = { workspace = true } 12 | dioxus-fullstack = { workspace = true } 13 | tokio = { workspace = true, features = ["full"], optional = true } 14 | serde = "1.0.159" 15 | salvo = { version = "0.37.9", optional = true } 16 | execute = "0.2.12" 17 | reqwest = "0.11.18" 18 | simple_logger = "4.2.0" 19 | tracing-wasm = "0.2.1" 20 | tracing.workspace = true 21 | tracing-subscriber = "0.3.17" 22 | 23 | [features] 24 | default = [] 25 | ssr = ["salvo", "tokio", "dioxus-fullstack/salvo"] 26 | web = ["dioxus-web"] 27 | -------------------------------------------------------------------------------- /packages/server-macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus_server_macro" 3 | version = { workspace = true } 4 | edition = "2021" 5 | repository = "https://github.com/DioxusLabs/dioxus/" 6 | homepage = "https://dioxuslabs.com/docs/0.4/guide/en/getting_started/fullstack.html" 7 | keywords = ["dom", "ui", "gui", "react", "liveview"] 8 | authors = ["Jonathan Kelley", "Evan Almloff"] 9 | license = "MIT OR Apache-2.0" 10 | description = "Server function macros for Dioxus" 11 | 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | proc-macro2 = "^1.0.63" 17 | quote = "^1.0.26" 18 | syn = { version = "2", features = ["full"] } 19 | convert_case = "^0.6.0" 20 | server_fn_macro = "^0.4.6" 21 | 22 | [lib] 23 | proc-macro = true 24 | 25 | [features] 26 | default = [] 27 | ssr = ["server_fn_macro/ssr"] 28 | -------------------------------------------------------------------------------- /examples/PWA-example/Dioxus.toml: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | # App (Project) Name 4 | name = "dioxus-pwa-example" 5 | 6 | # Dioxus App Default Platform 7 | # desktop, web, mobile, ssr 8 | default_platform = "web" 9 | 10 | # `build` & `serve` dist path 11 | out_dir = "dist" 12 | 13 | # resource (public) file folder 14 | asset_dir = "public" 15 | 16 | [web.app] 17 | 18 | # HTML title tag content 19 | title = "dioxus | ⛺" 20 | 21 | [web.watcher] 22 | 23 | # when watcher trigger, regenerate the `index.html` 24 | reload_html = true 25 | 26 | # which files or dirs will be watcher monitoring 27 | watch_path = ["src", "public"] 28 | 29 | # include `assets` in web platform 30 | [web.resource] 31 | 32 | # CSS style file 33 | style = [] 34 | 35 | # Javascript code file 36 | script = [] 37 | 38 | [web.resource.dev] 39 | 40 | # Javascript code file 41 | # serve: [dev-server] only 42 | script = [] 43 | -------------------------------------------------------------------------------- /packages/liveview/src/adapters/salvo_adapter.rs: -------------------------------------------------------------------------------- 1 | use futures_util::{SinkExt, StreamExt}; 2 | use salvo::ws::{Message, WebSocket}; 3 | 4 | use crate::{LiveViewError, LiveViewSocket}; 5 | 6 | /// Convert a salvo websocket into a LiveViewSocket 7 | /// 8 | /// This is required to launch a LiveView app using the warp web framework 9 | pub fn salvo_socket(ws: WebSocket) -> impl LiveViewSocket { 10 | ws.map(transform_rx) 11 | .with(transform_tx) 12 | .sink_map_err(|_| LiveViewError::SendingFailed) 13 | } 14 | 15 | fn transform_rx(message: Result) -> Result, LiveViewError> { 16 | let as_bytes = message.map_err(|_| LiveViewError::SendingFailed)?; 17 | 18 | Ok(as_bytes.into()) 19 | } 20 | 21 | async fn transform_tx(message: Vec) -> Result { 22 | Ok(Message::text(String::from_utf8_lossy(&message).to_string())) 23 | } 24 | -------------------------------------------------------------------------------- /examples/PWA-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {app_title} 5 | 12 | 13 | 14 | 15 | 16 | {style_include} 17 | 18 | 19 |
20 | 28 | {script_include} 29 | 30 | -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/dirs.md: -------------------------------------------------------------------------------- 1 | # Dirs Functions 2 | 3 | Dirs functions are for getting various directory paths. Not to be confused with `plugin.path`. 4 | 5 | ### `plugin_dir() -> string` 6 | 7 | Get the plugin's root directory path. 8 | 9 | ```lua 10 | local path = plugin.dirs.plugin_dir() 11 | -- example: ~/Development/DioxusCli/plugin/test-plugin/ 12 | ``` 13 | 14 | ### `bin_dir() -> string` 15 | 16 | Get the plugin's binary directory path. Put binary files like `tailwind-cli` or `sass-cli` in this directory. 17 | 18 | ```lua 19 | local path = plugin.dirs.bin_dir() 20 | -- example: ~/Development/DioxusCli/plugin/test-plugin/bin/ 21 | ``` 22 | 23 | ### `temp_dir() -> string` 24 | 25 | Get the plugin's temporary directory path. Put any temporary files here. 26 | 27 | ```lua 28 | local path = plugin.dirs.bin_dir() 29 | -- example: ~/Development/DioxusCli/plugin/test-plugin/temp/ 30 | ``` -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/log.md: -------------------------------------------------------------------------------- 1 | # Log Functions 2 | 3 | You can use log functions to print various logging information. 4 | 5 | ### `trace(info: string)` 6 | 7 | Print trace log info. 8 | 9 | ```lua 10 | local log = plugin.log 11 | log.trace("trace information") 12 | ``` 13 | 14 | ### `debug(info: string)` 15 | 16 | Print debug log info. 17 | 18 | ```lua 19 | local log = plugin.log 20 | log.debug("debug information") 21 | ``` 22 | 23 | ### `info(info: string)` 24 | 25 | Print info log info. 26 | 27 | ```lua 28 | local log = plugin.log 29 | log.info("info information") 30 | ``` 31 | 32 | ### `warn(info: string)` 33 | 34 | Print warning log info. 35 | 36 | ```lua 37 | local log = plugin.log 38 | log.warn("warn information") 39 | ``` 40 | 41 | ### `error(info: string)` 42 | 43 | Print error log info. 44 | 45 | ```lua 46 | local log = plugin.log 47 | log.error("error information") 48 | ``` -------------------------------------------------------------------------------- /packages/core/compile_tests/props_safety.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() {} 4 | 5 | fn app(cx: Scope) -> Element { 6 | let count: &RefCell> = cx.use_hook(|| RefCell::new(Vec::new())); 7 | 8 | render! { 9 | unsafe_child_component { 10 | borrowed: count 11 | } 12 | } 13 | } 14 | 15 | #[derive(Props)] 16 | struct Testing<'a> { 17 | borrowed: &'a RefCell>>, 18 | } 19 | 20 | fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> { 21 | let Testing { borrowed } = cx.props; 22 | let borrowed_temporary_data = 23 | cx.use_hook(|| String::from("This data is only valid for the lifetime of the child")); 24 | 25 | borrowed 26 | .borrow_mut() 27 | .push(render! {"{borrowed_temporary_data}"}); 28 | 29 | cx.render(rsx! { 30 | div { "Hello, world!" } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /packages/ssr/tests/bool_attr.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[test] 4 | fn static_boolean_attributs() { 5 | fn app(cx: Scope) -> Element { 6 | render! { 7 | div { hidden: "false" } 8 | div { hidden: "true" } 9 | } 10 | } 11 | 12 | let mut dom = VirtualDom::new(app); 13 | _ = dom.rebuild(); 14 | 15 | assert_eq!( 16 | dioxus_ssr::render(&dom), 17 | r#"
"# 18 | ); 19 | } 20 | 21 | #[test] 22 | fn dynamic_boolean_attributs() { 23 | fn app(cx: Scope) -> Element { 24 | render! { 25 | div { hidden: false } 26 | div { hidden: true } 27 | } 28 | } 29 | 30 | let mut dom = VirtualDom::new(app); 31 | _ = dom.rebuild(); 32 | 33 | assert_eq!( 34 | dioxus_ssr::render(&dom), 35 | r#"
"# 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /examples/scroll_to_top.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let header_element = use_ref(cx, || None); 9 | 10 | cx.render(rsx!( 11 | div { 12 | h1 { 13 | onmounted: move |cx| { 14 | header_element.set(Some(cx.inner().clone())); 15 | }, 16 | "Scroll to top example" 17 | } 18 | 19 | for i in 0..100 { 20 | div { "Item {i}" } 21 | } 22 | 23 | button { 24 | onclick: move |_| { 25 | if let Some(header) = header_element.read().as_ref() { 26 | header.scroll_to(ScrollBehavior::Smooth); 27 | } 28 | }, 29 | "Scroll to top" 30 | } 31 | } 32 | )) 33 | } 34 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/commentshard.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | // Comments 3 | div { 4 | // Comments 5 | class: "asdasd", 6 | 7 | // Comments 8 | "hello world" 9 | 10 | // Comments 11 | expr1, 12 | 13 | // Comments 14 | expr2, 15 | 16 | // Comments 17 | // Comments 18 | // Comments 19 | // Comments 20 | // Comments 21 | expr3, 22 | 23 | div { 24 | // todo some work in here 25 | } 26 | 27 | div { 28 | // todo some work in here 29 | // todo some work in here 30 | // 31 | // todo some work in here 32 | } 33 | 34 | div { 35 | // todo some work in here 36 | class: "hello world", 37 | 38 | // todo some work in here 39 | class: "hello world" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/src/scheduler/suspense.rs: -------------------------------------------------------------------------------- 1 | use futures_util::task::ArcWake; 2 | 3 | use super::SchedulerMsg; 4 | use crate::ElementId; 5 | use crate::{innerlude::Mutations, Element, ScopeId}; 6 | use std::future::Future; 7 | use std::sync::Arc; 8 | use std::task::Waker; 9 | use std::{ 10 | cell::{Cell, RefCell}, 11 | collections::HashSet, 12 | }; 13 | 14 | /// A boundary in the VirtualDom that captures all suspended components below it 15 | pub struct SuspenseContext { 16 | pub(crate) id: ScopeId, 17 | pub(crate) waiting_on: RefCell>, 18 | } 19 | 20 | impl SuspenseContext { 21 | /// Create a new boundary for suspense 22 | pub fn new(id: ScopeId) -> Self { 23 | Self { 24 | id, 25 | waiting_on: Default::default(), 26 | } 27 | } 28 | 29 | pub fn mark_suspend(&self, id: ScopeId) { 30 | self.waiting_on.borrow_mut().insert(id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/hooks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-hooks" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2018" 6 | description = "Basic useful hooks for Dioxus." 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react"] 11 | 12 | [features] 13 | default = [] 14 | nightly-features = [] 15 | 16 | [dependencies] 17 | dioxus-core = { workspace = true } 18 | futures-channel = { workspace = true } 19 | tracing = { workspace = true } 20 | thiserror = { workspace = true } 21 | slab = { workspace = true } 22 | dioxus-debug-cell = "0.1.1" 23 | 24 | [dev-dependencies] 25 | futures-util = { workspace = true, default-features = false } 26 | dioxus-core = { workspace = true } 27 | dioxus = { workspace = true } 28 | web-sys = { version = "0.3.64", features = ["Document", "Window", "Element"] } 29 | -------------------------------------------------------------------------------- /packages/native-core/src/node_watcher.rs: -------------------------------------------------------------------------------- 1 | //! Helpers for watching for changes in the DOM tree. 2 | 3 | use crate::{node::FromAnyValue, node_ref::AttributeMask, prelude::*}; 4 | 5 | /// A trait for watching for changes in the DOM tree. 6 | pub trait NodeWatcher { 7 | /// Called after a node is added to the tree. 8 | fn on_node_added(&mut self, _node: NodeMut) {} 9 | /// Called before a node is removed from the tree. 10 | fn on_node_removed(&mut self, _node: NodeMut) {} 11 | /// Called after a node is moved to a new parent. 12 | fn on_node_moved(&mut self, _node: NodeMut) {} 13 | } 14 | 15 | /// A trait for watching for changes to attributes of an element. 16 | pub trait AttributeWatcher { 17 | /// Called before update_state is called on the RealDom 18 | fn on_attributes_changed(&self, _node: NodeMut, _attributes: &AttributeMask) {} 19 | } 20 | -------------------------------------------------------------------------------- /packages/rsx-rosetta/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsx-rosetta" 3 | version = { workspace = true } 4 | edition = "2021" 5 | authors = ["Jonathan Kelley"] 6 | description = "Autofomatter for Dioxus RSX" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | documentation = "https://dioxuslabs.com" 11 | keywords = ["dom", "ui", "gui", "react"] 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | dioxus-autofmt = { workspace = true } 17 | dioxus-rsx = { workspace = true } 18 | html_parser.workspace = true 19 | proc-macro2 = "1.0.49" 20 | quote = "1.0.23" 21 | syn = { version = "2.0", features = ["full"] } 22 | convert_case = "0.5.0" 23 | 24 | # [features] 25 | # default = ["html"] 26 | 27 | # eventually more output options 28 | 29 | [dev-dependencies] 30 | pretty_assertions = "1.2.1" 31 | -------------------------------------------------------------------------------- /examples/tailwind/Dioxus.toml: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | # App (Project) Name 4 | name = "Tailwind CSS + Dioxus" 5 | 6 | # Dioxus App Default Platform 7 | # desktop, web, mobile, ssr 8 | default_platform = "web" 9 | 10 | # `build` & `serve` dist path 11 | out_dir = "dist" 12 | 13 | # resource (public) file folder 14 | asset_dir = "public" 15 | 16 | [web.app] 17 | 18 | # HTML title tag content 19 | title = "dioxus | ⛺" 20 | 21 | [web.watcher] 22 | 23 | # when watcher trigger, regenerate the `index.html` 24 | reload_html = true 25 | 26 | # which files or dirs will be watcher monitoring 27 | watch_path = ["src", "public"] 28 | 29 | # include `assets` in web platform 30 | [web.resource] 31 | 32 | # CSS style file 33 | style = ["/tailwind.css"] 34 | 35 | # Javascript code file 36 | script = [] 37 | 38 | [web.resource.dev] 39 | 40 | # serve: [dev-server] only 41 | 42 | # CSS style file 43 | style = [] 44 | 45 | # Javascript code file 46 | script = [] 47 | -------------------------------------------------------------------------------- /packages/check/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-check" 3 | version = { workspace = true } 4 | edition = "2021" 5 | authors = ["Dioxus Labs"] 6 | description = "Checks Dioxus RSX files for issues" 7 | license = "MIT/Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react"] 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | dioxus-rsx = { workspace = true } 15 | proc-macro2 = { version = "1.0.6", features = ["span-locations"] } 16 | quote = "1.0" 17 | syn = { version = "1.0.11", features = ["full", "extra-traits", "visit"] } 18 | serde = { version = "1.0.136", features = ["derive"] } 19 | owo-colors = { version = "3.5.0", features = ["supports-colors"] } 20 | prettyplease = { workspace = true } 21 | 22 | [dev-dependencies] 23 | indoc = "2.0.3" 24 | pretty_assertions = "1.2.1" 25 | -------------------------------------------------------------------------------- /packages/cli/src/plugin/interface/log.rs: -------------------------------------------------------------------------------- 1 | use log; 2 | use mlua::UserData; 3 | 4 | pub struct PluginLogger; 5 | impl UserData for PluginLogger { 6 | fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { 7 | methods.add_function("trace", |_, info: String| { 8 | log::trace!("{}", info); 9 | Ok(()) 10 | }); 11 | methods.add_function("info", |_, info: String| { 12 | log::info!("{}", info); 13 | Ok(()) 14 | }); 15 | methods.add_function("debug", |_, info: String| { 16 | log::debug!("{}", info); 17 | Ok(()) 18 | }); 19 | methods.add_function("warn", |_, info: String| { 20 | log::warn!("{}", info); 21 | Ok(()) 22 | }); 23 | methods.add_function("error", |_, info: String| { 24 | log::error!("{}", info); 25 | Ok(()) 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/PWA-example/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dioxus", 3 | "icons": [ 4 | { 5 | "src": "logo_192.png", 6 | "type": "image/png", 7 | "sizes": "192x192" 8 | }, 9 | { 10 | "src": "logo_512.png", 11 | "type": "image/png", 12 | "sizes": "512x512", 13 | "purpose": "any" 14 | }, 15 | { 16 | "src": "logo_512.png", 17 | "type": "image/png", 18 | "sizes": "any", 19 | "purpose": "any" 20 | } 21 | ], 22 | "start_url": "/", 23 | "id": "/", 24 | "display": "standalone", 25 | "display_override": ["window-control-overlay", "standalone"], 26 | "scope": "/", 27 | "theme_color": "#000000", 28 | "background_color": "#ffffff", 29 | "short_name": "Dioxus", 30 | "description": "Dioxus is a portable, performant, and ergonomic framework for building cross-platform user interfaces in Rust.", 31 | "dir": "ltr", 32 | "lang": "en", 33 | "orientation": "portrait" 34 | } -------------------------------------------------------------------------------- /packages/fullstack/examples/static-hydrated/Dioxus.toml: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | # App (Project) Name 4 | name = "Dioxus" 5 | 6 | # Dioxus App Default Platform 7 | # desktop, web, mobile, ssr 8 | default_platform = "web" 9 | 10 | # `build` & `serve` dist path 11 | out_dir = "docs" 12 | 13 | # resource (public) file folder 14 | asset_dir = "public" 15 | 16 | [web.app] 17 | 18 | # HTML title tag content 19 | title = "dioxus | ⛺" 20 | 21 | [web.watcher] 22 | 23 | # when watcher trigger, regenerate the `index.html` 24 | reload_html = true 25 | 26 | # which files or dirs will be watcher monitoring 27 | watch_path = ["src", "public"] 28 | 29 | # include `assets` in web platform 30 | [web.resource] 31 | 32 | # CSS style file 33 | style = ["tailwind.css"] 34 | 35 | # Javascript code file 36 | script = [] 37 | 38 | [web.resource.dev] 39 | 40 | # serve: [dev-server] only 41 | 42 | # CSS style file 43 | style = [] 44 | 45 | # Javascript code file 46 | script = [] 47 | -------------------------------------------------------------------------------- /packages/cli/Dioxus.toml: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | # App name 4 | name = "project_name" 5 | 6 | # The Dioxus platform to default to 7 | default_platform = "web" 8 | 9 | # `build` & `serve` output path 10 | out_dir = "dist" 11 | 12 | # The static resource path 13 | asset_dir = "public" 14 | 15 | [web.app] 16 | 17 | # HTML title tag content 18 | title = "project_name" 19 | 20 | [web.watcher] 21 | 22 | # When watcher is triggered, regenerate the `index.html` 23 | reload_html = true 24 | 25 | # Which files or dirs will be monitored 26 | watch_path = ["src", "public"] 27 | 28 | # Include style or script assets 29 | [web.resource] 30 | 31 | # CSS style file 32 | style = [] 33 | 34 | # Javascript code file 35 | script = [] 36 | 37 | [web.resource.dev] 38 | 39 | # Same as [web.resource], but for development servers 40 | 41 | # CSS style file 42 | style = [] 43 | 44 | # JavaScript files 45 | script = [] 46 | 47 | [[web.proxy]] 48 | backend = "http://localhost:8000/api/" -------------------------------------------------------------------------------- /packages/cli/.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # .github/workflows/build.yml 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | release: 9 | name: release ${{ matrix.target }} 10 | runs-on: ubuntu-latest 11 | strategy: 12 | fail-fast: false 13 | matrix: 14 | include: 15 | - target: x86_64-unknown-linux-gnu 16 | archive: tar.gz tar.xz 17 | - target: x86_64-unknown-linux-musl 18 | archive: tar.gz tar.xz 19 | - target: x86_64-apple-darwin 20 | archive: tar.gz tar.xz 21 | - target: x86_64-pc-windows-gnu 22 | archive: zip 23 | 24 | steps: 25 | - uses: actions/checkout@master 26 | - name: Compile and release 27 | uses: rust-build/rust-build.action@latest 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | RUSTTARGET: ${{ matrix.target }} 31 | ARCHIVE_TYPES: ${{ matrix.archive }} 32 | -------------------------------------------------------------------------------- /packages/liveview/src/adapters/axum_adapter.rs: -------------------------------------------------------------------------------- 1 | use crate::{LiveViewError, LiveViewSocket}; 2 | use axum::extract::ws::{Message, WebSocket}; 3 | use futures_util::{SinkExt, StreamExt}; 4 | 5 | /// Convert a warp websocket into a LiveViewSocket 6 | /// 7 | /// This is required to launch a LiveView app using the warp web framework 8 | pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket { 9 | ws.map(transform_rx) 10 | .with(transform_tx) 11 | .sink_map_err(|_| LiveViewError::SendingFailed) 12 | } 13 | 14 | fn transform_rx(message: Result) -> Result, LiveViewError> { 15 | message 16 | .map_err(|_| LiveViewError::SendingFailed)? 17 | .into_text() 18 | .map(|s| s.into_bytes()) 19 | .map_err(|_| LiveViewError::SendingFailed) 20 | } 21 | 22 | async fn transform_tx(message: Vec) -> Result { 23 | Ok(Message::Text(String::from_utf8_lossy(&message).to_string())) 24 | } 25 | -------------------------------------------------------------------------------- /packages/liveview/src/adapters/warp_adapter.rs: -------------------------------------------------------------------------------- 1 | use crate::{LiveViewError, LiveViewSocket}; 2 | use futures_util::{SinkExt, StreamExt}; 3 | use warp::ws::{Message, WebSocket}; 4 | 5 | /// Convert a warp websocket into a LiveViewSocket 6 | /// 7 | /// This is required to launch a LiveView app using the warp web framework 8 | pub fn warp_socket(ws: WebSocket) -> impl LiveViewSocket { 9 | ws.map(transform_rx) 10 | .with(transform_tx) 11 | .sink_map_err(|_| LiveViewError::SendingFailed) 12 | } 13 | 14 | fn transform_rx(message: Result) -> Result, LiveViewError> { 15 | // destructure the message into the buffer we got from warp 16 | let msg = message 17 | .map_err(|_| LiveViewError::SendingFailed)? 18 | .into_bytes(); 19 | 20 | Ok(msg) 21 | } 22 | 23 | async fn transform_tx(message: Vec) -> Result { 24 | Ok(Message::text(String::from_utf8_lossy(&message).to_string())) 25 | } 26 | -------------------------------------------------------------------------------- /packages/ssr/tests/styles.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[test] 4 | fn static_styles() { 5 | fn app(cx: Scope) -> Element { 6 | render! { div { width: "100px" } } 7 | } 8 | 9 | let mut dom = VirtualDom::new(app); 10 | _ = dom.rebuild(); 11 | 12 | assert_eq!( 13 | dioxus_ssr::render(&dom), 14 | r#"
"# 15 | ); 16 | } 17 | 18 | #[test] 19 | fn partially_dynamic_styles() { 20 | let dynamic = 123; 21 | 22 | assert_eq!( 23 | dioxus_ssr::render_lazy(rsx! { 24 | div { width: "100px", height: "{dynamic}px" } 25 | }), 26 | r#"
"# 27 | ); 28 | } 29 | 30 | #[test] 31 | fn dynamic_styles() { 32 | let dynamic = 123; 33 | 34 | assert_eq!( 35 | dioxus_ssr::render_lazy(rsx! { 36 | div { width: "{dynamic}px" } 37 | }), 38 | r#"
"# 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /packages/core-macro/tests/ifmt.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core_macro::*; 2 | 3 | #[test] 4 | fn formatting_compiles() { 5 | let x = (0, 1); 6 | // escape sequences work 7 | assert_eq!( 8 | format_args_f!("{x:?} {{}}}}").to_string(), 9 | format!("{x:?} {{}}}}") 10 | ); 11 | assert_eq!( 12 | format_args_f!("{{{{}} {x:?}").to_string(), 13 | format!("{{{{}} {x:?}") 14 | ); 15 | 16 | // paths in formating works 17 | assert_eq!(format_args_f!("{x.0}").to_string(), format!("{}", x.0)); 18 | 19 | // function calls in formatings work 20 | assert_eq!( 21 | format_args_f!("{blah(&x):?}").to_string(), 22 | format!("{:?}", blah(&x)) 23 | ); 24 | 25 | // allows duplicate format args 26 | assert_eq!( 27 | format_args_f!("{x:?} {x:?}").to_string(), 28 | format!("{x:?} {x:?}") 29 | ); 30 | } 31 | 32 | fn blah(hi: &(i32, i32)) -> String { 33 | format_args_f!("{hi.0} {hi.1}").to_string() 34 | } 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve Dioxus 4 | --- 5 | 6 | **Problem** 7 | 8 | 9 | 10 | **Steps To Reproduce** 11 | 12 | Steps to reproduce the behavior: 13 | 14 | - 15 | - 16 | - 17 | 18 | **Expected behavior** 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment:** 27 | - Dioxus version: [e.g. v0.17, `master`] 28 | - Rust version: [e.g. 1.43.0, `nightly`] 29 | - OS info: [e.g. MacOS] 30 | - App platform: [e.g. `web`, `desktop`] 31 | 32 | **Questionnaire** 33 | 34 | - [ ] I'm interested in fixing this myself but don't know where to start 35 | - [ ] I would like to fix and I have a solution 36 | - [ ] I don't have time to fix this right now, but maybe later -------------------------------------------------------------------------------- /packages/cli/src/cli/clean.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// Clean build artifacts. 4 | #[derive(Clone, Debug, Parser)] 5 | #[clap(name = "clean")] 6 | pub struct Clean {} 7 | 8 | impl Clean { 9 | pub fn clean(self, bin: Option) -> Result<()> { 10 | let crate_config = crate::CrateConfig::new(bin)?; 11 | 12 | let output = Command::new("cargo") 13 | .arg("clean") 14 | .stdout(Stdio::piped()) 15 | .stderr(Stdio::piped()) 16 | .output()?; 17 | 18 | if !output.status.success() { 19 | return custom_error!("Cargo clean failed."); 20 | } 21 | 22 | let out_dir = crate_config 23 | .dioxus_config 24 | .application 25 | .out_dir 26 | .unwrap_or_else(|| PathBuf::from("dist")); 27 | if crate_config.crate_dir.join(&out_dir).is_dir() { 28 | remove_dir_all(crate_config.crate_dir.join(&out_dir))?; 29 | } 30 | 31 | Ok(()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/form.rs: -------------------------------------------------------------------------------- 1 | //! Forms 2 | //! 3 | //! Dioxus forms deviate slightly from html, automatically returning all named inputs 4 | //! in the "values" field 5 | 6 | use dioxus::prelude::*; 7 | 8 | fn main() { 9 | dioxus_desktop::launch(app); 10 | } 11 | 12 | fn app(cx: Scope) -> Element { 13 | cx.render(rsx! { 14 | div { 15 | h1 { "Form" } 16 | form { 17 | onsubmit: move |ev| println!("Submitted {:?}", ev.values), 18 | oninput: move |ev| println!("Input {:?}", ev.values), 19 | input { r#type: "text", name: "username" } 20 | input { r#type: "text", name: "full-name" } 21 | input { r#type: "password", name: "password" } 22 | input { r#type: "radio", name: "color", value: "red" } 23 | input { r#type: "radio", name: "color", value: "blue" } 24 | button { r#type: "submit", value: "Submit", "Submit the form" } 25 | } 26 | } 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /packages/cli/src/plugin/interface/network.rs: -------------------------------------------------------------------------------- 1 | use std::{io::Cursor, path::PathBuf}; 2 | 3 | use mlua::UserData; 4 | 5 | pub struct PluginNetwork; 6 | impl UserData for PluginNetwork { 7 | fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { 8 | methods.add_function("download_file", |_, args: (String, String)| { 9 | let url = args.0; 10 | let path = args.1; 11 | 12 | let resp = reqwest::blocking::get(url); 13 | if let Ok(resp) = resp { 14 | let mut content = Cursor::new(resp.bytes().unwrap()); 15 | let file = std::fs::File::create(PathBuf::from(path)); 16 | if file.is_err() { 17 | return Ok(false); 18 | } 19 | let mut file = file.unwrap(); 20 | let res = std::io::copy(&mut content, &mut file); 21 | return Ok(res.is_ok()); 22 | } 23 | 24 | Ok(false) 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/simple_list.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | cx.render(rsx!( 9 | div { 10 | // Use Map directly to lazily pull elements 11 | (0..10).map(|f| rsx! { "{f}" }), 12 | 13 | // Collect into an intermediate collection if necessary, and call into_iter 14 | ["a", "b", "c", "d", "e", "f"] 15 | .into_iter() 16 | .map(|f| rsx! { "{f}" }) 17 | .collect::>() 18 | .into_iter(), 19 | 20 | // Use optionals 21 | Some(rsx! { "Some" }), 22 | 23 | // use a for loop where the body itself is RSX 24 | for name in 0..10 { 25 | div {"{name}"} 26 | } 27 | 28 | // Or even use an unterminated conditional 29 | if true { 30 | rsx!{ "hello world!" } 31 | } 32 | } 33 | )) 34 | } 35 | -------------------------------------------------------------------------------- /examples/nested_listeners.rs: -------------------------------------------------------------------------------- 1 | //! Nested Listeners 2 | //! 3 | //! This example showcases how to control event bubbling from child to parents. 4 | //! 5 | //! Both web and desktop support bubbling and bubble cancelation. 6 | 7 | use dioxus::prelude::*; 8 | 9 | fn main() { 10 | dioxus_desktop::launch(app); 11 | } 12 | 13 | fn app(cx: Scope) -> Element { 14 | cx.render(rsx! { 15 | div { 16 | onclick: move |_| println!("clicked! top"), 17 | "- div" 18 | button { 19 | onclick: move |_| println!("clicked! bottom propagate"), 20 | "Propagate" 21 | } 22 | button { 23 | onclick: move |evt| { 24 | println!("clicked! bottom no bubbling"); 25 | evt.stop_propagation(); 26 | }, 27 | "Dont propagate" 28 | } 29 | button { 30 | "Does not handle clicks - only propagate" 31 | } 32 | } 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /packages/signals/examples/dependancies.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use dioxus::prelude::*; 4 | use dioxus_signals::*; 5 | 6 | fn main() { 7 | dioxus_desktop::launch(app); 8 | } 9 | 10 | fn app(cx: Scope) -> Element { 11 | let signal = use_signal(cx, || 0); 12 | 13 | use_future!(cx, || async move { 14 | loop { 15 | tokio::time::sleep(std::time::Duration::from_secs(1)).await; 16 | *signal.write() += 1; 17 | } 18 | }); 19 | 20 | let local_state = use_state(cx, || 0); 21 | let computed = 22 | use_selector_with_dependencies(cx, (local_state.get(),), move |(local_state,)| { 23 | local_state * 2 + signal.value() 24 | }); 25 | println!("Running app"); 26 | 27 | render! { 28 | button { 29 | onclick: move |_| { 30 | local_state.set(local_state.get() + 1); 31 | }, 32 | "Add one" 33 | } 34 | div { 35 | "{computed}" 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/ssr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-ssr" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2018" 6 | description = "Dioxus render-to-string" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | keywords = ["dom", "ui", "gui", "react", "ssr"] 10 | 11 | [dependencies] 12 | dioxus-core = { workspace = true, features = ["serialize"] } 13 | askama_escape = "0.10.3" 14 | thiserror = "1.0.23" 15 | rustc-hash = "1.1.0" 16 | lru = "0.10.0" 17 | tracing = { workspace = true } 18 | http = "0.2.9" 19 | tokio = { version = "1.28", features = ["full"], optional = true } 20 | 21 | [dev-dependencies] 22 | dioxus = { workspace = true } 23 | thiserror = { workspace = true } 24 | tracing = { workspace = true } 25 | fern = { version = "0.6.0", features = ["colored"] } 26 | anyhow = "1.0" 27 | argh = "0.1.4" 28 | serde = "1.0.120" 29 | serde_json = "1.0.61" 30 | fs_extra = "1.2.0" 31 | 32 | [features] 33 | default = ["incremental"] 34 | incremental = ["dep:tokio"] 35 | -------------------------------------------------------------------------------- /examples/eval.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_desktop::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let eval_provider = use_eval(cx); 9 | 10 | let future = use_future(cx, (), |_| { 11 | to_owned![eval_provider]; 12 | async move { 13 | let eval = eval_provider( 14 | r#" 15 | dioxus.send("Hi from JS!"); 16 | let msg = await dioxus.recv(); 17 | console.log(msg); 18 | return "hello world"; 19 | "#, 20 | ) 21 | .unwrap(); 22 | 23 | eval.send("Hi from Rust!".into()).unwrap(); 24 | let res = eval.recv().await.unwrap(); 25 | println!("{:?}", eval.await); 26 | res 27 | } 28 | }); 29 | 30 | match future.value() { 31 | Some(v) => cx.render(rsx!( 32 | p { "{v}" } 33 | )), 34 | _ => cx.render(rsx!( 35 | p { "hello" } 36 | )), 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/cli/.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: github pages 2 | 3 | on: 4 | push: 5 | paths: 6 | - docs/** 7 | branches: 8 | - master 9 | 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-20.04 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Setup mdBook 19 | uses: peaceiris/actions-mdbook@v1 20 | with: 21 | mdbook-version: '0.4.10' 22 | # mdbook-version: 'latest' 23 | 24 | - run: cd docs && mdbook build 25 | 26 | - name: Deploy 🚀 27 | uses: JamesIves/github-pages-deploy-action@v4.2.3 28 | with: 29 | branch: gh-pages # The branch the action should deploy to. 30 | folder: docs/book # The folder the action should deploy. 31 | target-folder: docs/nightly/cli 32 | repository-name: dioxuslabs/docsite 33 | clean: false 34 | token: ${{ secrets.DEPLOY_KEY }} # let's pretend I don't need it for now 35 | -------------------------------------------------------------------------------- /packages/dioxus-tui/examples/task.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | fn main() { 4 | dioxus_tui::launch(app); 5 | } 6 | 7 | fn app(cx: Scope) -> Element { 8 | let count = use_state(cx, || 0); 9 | 10 | use_future(cx, (), move |_| { 11 | let count = count.to_owned(); 12 | let update = cx.schedule_update(); 13 | async move { 14 | loop { 15 | count.with_mut(|f| *f += 1); 16 | tokio::time::sleep(std::time::Duration::from_millis(1000)).await; 17 | update(); 18 | } 19 | } 20 | }); 21 | 22 | cx.render(rsx! { 23 | div { width: "100%", 24 | div { width: "50%", height: "5px", background_color: "blue", justify_content: "center", align_items: "center", 25 | "Hello {count}!" 26 | } 27 | div { width: "50%", height: "10px", background_color: "red", justify_content: "center", align_items: "center", 28 | "Hello {count}!" 29 | } 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /packages/core/src/scheduler/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::ScopeId; 2 | use slab::Slab; 3 | 4 | mod task; 5 | mod wait; 6 | 7 | pub use task::*; 8 | 9 | /// The type of message that can be sent to the scheduler. 10 | /// 11 | /// These messages control how the scheduler will process updates to the UI. 12 | #[derive(Debug)] 13 | pub(crate) enum SchedulerMsg { 14 | /// Immediate updates from Components that mark them as dirty 15 | Immediate(ScopeId), 16 | 17 | /// A task has woken and needs to be progressed 18 | TaskNotified(TaskId), 19 | } 20 | 21 | use std::{cell::RefCell, rc::Rc}; 22 | 23 | pub(crate) struct Scheduler { 24 | pub sender: futures_channel::mpsc::UnboundedSender, 25 | 26 | /// Tasks created with cx.spawn 27 | pub tasks: RefCell>, 28 | } 29 | 30 | impl Scheduler { 31 | pub fn new(sender: futures_channel::mpsc::UnboundedSender) -> Rc { 32 | Rc::new(Scheduler { 33 | sender, 34 | tasks: RefCell::new(Slab::new()), 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | bearly 2 | Clippy 3 | tide_ssr 4 | Liveview 5 | Dioxus 6 | VDoms 7 | Tauri 8 | webview 9 | polyfills 10 | transpiling 11 | fullstack 12 | Serverless 13 | vnode 14 | fn 15 | Dodrio 16 | fc 17 | Jemalloc 18 | Cloudfare 19 | webapps 20 | downcasting 21 | vec 22 | deref 23 | derefs 24 | Derefing 25 | rei 26 | RefMut 27 | diffed 28 | datafetching 29 | partialeq 30 | rsx 31 | Ctx 32 | fmt 33 | Reqwest 34 | Gloo 35 | mobx 36 | img 37 | svg 38 | Actix 39 | OrdMap 40 | datastructures 41 | onclick 42 | virtualdom 43 | namespaced 44 | namespacing 45 | impl 46 | destructured 47 | linting 48 | lodash 49 | crates.io 50 | utilties 51 | js 52 | Dyon 53 | ssr 54 | docusarus 55 | docsite 56 | dom 57 | textarea 58 | noderefs 59 | wasm 60 | 7ns 61 | attr 62 | derefed 63 | Tokio 64 | asynchronicity 65 | constified 66 | SegVec 67 | contentful 68 | Jank 69 | noderef 70 | reborrow 71 | VirtualDoms 72 | bootstrapper 73 | WebkitGtk 74 | laymans 75 | iter 76 | cloneable 77 | fudamental 78 | clonable 79 | oninput 80 | Webview 81 | idanarye 82 | Katex 83 | mrxiaozhuox 84 | Fruitie 85 | Vercel 86 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dioxus", 3 | "remoteUser": "vscode", 4 | "build": { 5 | "dockerfile": "./Dockerfile", 6 | "context": "." 7 | }, 8 | "features": { 9 | "ghcr.io/devcontainers/features/common-utils:2": { 10 | "installZsh": "true", 11 | "username": "vscode", 12 | "uid": "1000", 13 | "gid": "1000", 14 | "upgradePackages": "true" 15 | } 16 | }, 17 | "containerEnv": { 18 | "RUST_LOG": "INFO" 19 | }, 20 | "customizations": { 21 | "vscode": { 22 | "settings": { 23 | "files.watcherExclude": { 24 | "**/target/**": true 25 | }, 26 | "[rust]": { 27 | "editor.formatOnSave": true 28 | } 29 | }, 30 | "extensions": [ 31 | "rust-lang.rust-analyzer", 32 | "tamasfe.even-better-toml", 33 | "serayuzgur.crates" 34 | ] 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /packages/fermi/src/hooks/read.rs: -------------------------------------------------------------------------------- 1 | use crate::{use_atom_root, AtomId, AtomRoot, Readable}; 2 | use dioxus_core::{ScopeId, ScopeState}; 3 | use std::rc::Rc; 4 | 5 | pub fn use_read(cx: &ScopeState, f: impl Readable) -> &V { 6 | use_read_rc(cx, f).as_ref() 7 | } 8 | 9 | pub fn use_read_rc(cx: &ScopeState, f: impl Readable) -> &Rc { 10 | let root = use_atom_root(cx); 11 | 12 | struct UseReadInner { 13 | root: Rc, 14 | id: AtomId, 15 | scope_id: ScopeId, 16 | value: Option>, 17 | } 18 | 19 | impl Drop for UseReadInner { 20 | fn drop(&mut self) { 21 | self.root.unsubscribe(self.id, self.scope_id) 22 | } 23 | } 24 | 25 | let inner = cx.use_hook(|| UseReadInner { 26 | value: None, 27 | root: root.clone(), 28 | scope_id: cx.scope_id(), 29 | id: f.unique_id(), 30 | }); 31 | 32 | let value = inner.root.register(f, cx.scope_id()); 33 | 34 | inner.value = Some(value); 35 | inner.value.as_ref().unwrap() 36 | } 37 | -------------------------------------------------------------------------------- /examples/custom_html.rs: -------------------------------------------------------------------------------- 1 | //! This example shows how to use a custom index.html and custom extensions 2 | //! to add things like stylesheets, scripts, and third-party JS libraries. 3 | 4 | use dioxus::prelude::*; 5 | use dioxus_desktop::Config; 6 | 7 | fn main() { 8 | dioxus_desktop::launch_cfg( 9 | app, 10 | Config::new().with_custom_head("".into()), 11 | ); 12 | 13 | dioxus_desktop::launch_cfg( 14 | app, 15 | Config::new().with_custom_index( 16 | r#" 17 | 18 | 19 | 20 | Dioxus app 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | "# 29 | .into(), 30 | ), 31 | ); 32 | } 33 | 34 | fn app(cx: Scope) -> Element { 35 | cx.render(rsx! { 36 | div { 37 | h1 {"hello world!"} 38 | } 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /packages/core/tests/create_element.rs: -------------------------------------------------------------------------------- 1 | // use dioxus::core::Mutation::*; 2 | use dioxus::prelude::*; 3 | 4 | #[test] 5 | fn multiroot() { 6 | let mut dom = VirtualDom::new(|cx| { 7 | cx.render(rsx! { 8 | div { "Hello a" } 9 | div { "Hello b" } 10 | div { "Hello c" } 11 | }) 12 | }); 13 | 14 | // note: we dont test template edits anymore 15 | let _templates = dom.rebuild().santize().templates; 16 | 17 | // assert_eq!( 18 | // dom.rebuild().santize().templates, 19 | // [ 20 | // CreateElement { name: "div" }, 21 | // CreateStaticText { value: "Hello a" }, 22 | // AppendChildren { m: 1 }, 23 | // CreateElement { name: "div" }, 24 | // CreateStaticText { value: "Hello b" }, 25 | // AppendChildren { m: 1 }, 26 | // CreateElement { name: "div" }, 27 | // CreateStaticText { value: "Hello c" }, 28 | // AppendChildren { m: 1 }, 29 | // SaveTemplate { name: "template", m: 3 } 30 | // ] 31 | // ) 32 | } 33 | -------------------------------------------------------------------------------- /packages/dioxus/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use dioxus_core as core; 2 | 3 | #[cfg(feature = "hooks")] 4 | pub use dioxus_hooks as hooks; 5 | 6 | pub mod events { 7 | #[cfg(feature = "html")] 8 | pub use dioxus_html::prelude::*; 9 | } 10 | 11 | #[cfg(feature = "html")] 12 | pub use dioxus_html as html; 13 | 14 | #[cfg(feature = "macro")] 15 | pub use dioxus_rsx as rsx; 16 | 17 | #[cfg(feature = "macro")] 18 | pub use dioxus_core_macro as core_macro; 19 | 20 | pub mod prelude { 21 | #[cfg(feature = "hooks")] 22 | pub use crate::hooks::*; 23 | 24 | pub use dioxus_core::prelude::*; 25 | 26 | #[cfg(feature = "macro")] 27 | #[allow(deprecated)] 28 | pub use dioxus_core_macro::{component, format_args_f, inline_props, render, rsx, Props}; 29 | 30 | #[cfg(feature = "html")] 31 | pub use dioxus_html as dioxus_elements; 32 | 33 | #[cfg(feature = "html")] 34 | pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes}; 35 | 36 | #[cfg(all(not(target_arch = "wasm32"), feature = "hot-reload"))] 37 | pub use dioxus_hot_reload::{self, hot_reload_init}; 38 | } 39 | -------------------------------------------------------------------------------- /packages/extension/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "args": [ 13 | "--extensionDevelopmentPath=${workspaceFolder}" 14 | ], 15 | "outFiles": [ 16 | "${workspaceFolder}/out/**/*.js" 17 | ] 18 | // "preLaunchTask": "${defaultBuildTask}" 19 | }, 20 | { 21 | "name": "Extension Tests", 22 | "type": "extensionHost", 23 | "request": "launch", 24 | "args": [ 25 | "--extensionDevelopmentPath=${workspaceFolder}", 26 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 27 | ], 28 | "outFiles": [ 29 | "${workspaceFolder}/out/test/**/*.js" 30 | ], 31 | "preLaunchTask": "${defaultBuildTask}" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /packages/rsx/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-rsx" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley", "Evan Almloff"] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | documentation = "https://dioxuslabs.com" 11 | keywords = ["dom", "ui", "gui", "react"] 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | proc-macro2 = { version = "1.0", features = ["span-locations"] } 17 | dioxus-core = { workspace = true} 18 | syn = { version = "2.0", features = ["full", "extra-traits"] } 19 | quote = { version = "1.0" } 20 | serde = { version = "1.0", features = ["derive"], optional = true } 21 | internment = { version = "0.7.0", optional = true } 22 | krates = { version = "0.12.6", optional = true } 23 | 24 | [features] 25 | hot_reload = ["krates", "internment"] 26 | serde = ["dep:serde"] 27 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /examples/simple_router.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | use dioxus_router::prelude::*; 4 | 5 | #[derive(Routable, Clone, PartialEq)] 6 | enum Route { 7 | #[layout(Nav)] 8 | #[route("/")] 9 | Homepage {}, 10 | 11 | #[route("/blog/:id")] 12 | Blog { id: String }, 13 | } 14 | 15 | #[component] 16 | fn Homepage(cx: Scope) -> Element { 17 | render! { h1 { "Welcome home" } } 18 | } 19 | 20 | #[component] 21 | fn Blog(cx: Scope, id: String) -> Element { 22 | render! { 23 | h1 { "How to make: " } 24 | p { "{id}" } 25 | } 26 | } 27 | 28 | #[component] 29 | fn Nav(cx: Scope) -> Element { 30 | render! { 31 | nav { 32 | li { Link { to: Route::Homepage { }, "Go home" } } 33 | li { Link { to: Route::Blog { id: "Brownies".to_string() }, "Learn Brownies" } } 34 | li { Link { to: Route::Blog { id: "Cookies".to_string() }, "Learn Cookies" } } 35 | } 36 | div { Outlet:: {} } 37 | } 38 | } 39 | 40 | fn main() { 41 | dioxus_desktop::launch(|cx| render!(Router:: {})); 42 | } 43 | -------------------------------------------------------------------------------- /packages/core/tests/suspense.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[test] 4 | fn it_works() { 5 | // wait just a moment, not enough time for the boundary to resolve 6 | 7 | tokio::runtime::Builder::new_current_thread() 8 | .build() 9 | .unwrap() 10 | .block_on(async { 11 | let mut dom = VirtualDom::new(app); 12 | _ = dom.rebuild(); 13 | dom.wait_for_suspense().await; 14 | let out = dioxus_ssr::pre_render(&dom); 15 | 16 | assert_eq!(out, "
Waiting for... child
"); 17 | 18 | dbg!(out); 19 | }); 20 | } 21 | 22 | fn app(cx: Scope) -> Element { 23 | cx.render(rsx!( 24 | div { 25 | "Waiting for... " 26 | suspended_child {} 27 | } 28 | )) 29 | } 30 | 31 | fn suspended_child(cx: Scope) -> Element { 32 | let val = use_state(cx, || 0); 33 | 34 | if **val < 3 { 35 | let mut val = val.clone(); 36 | cx.spawn(async move { 37 | val += 1; 38 | }); 39 | return cx.suspend()?; 40 | } 41 | 42 | render!("child") 43 | } 44 | -------------------------------------------------------------------------------- /packages/cli/docs/src/creating.md: -------------------------------------------------------------------------------- 1 | # Create a Project 2 | 3 | Once you have the Dioxus CLI installed, you can use it to create your own project! 4 | 5 | ## Initializing a default project 6 | 7 | First, run the `dx create` command to create a new project: 8 | ``` 9 | dx create hello-dioxus 10 | ``` 11 | 12 | > It will clone this [template](https://github.com/DioxusLabs/dioxus-template). 13 | > This default template is used for `web` platform application. 14 | > 15 | > You can choose to create your project from a different template by passing the `template` argument: 16 | > ``` 17 | > dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template 18 | > ``` 19 | 20 | Next, navigate into your new project: 21 | 22 | ``` 23 | cd hello-dioxus 24 | ``` 25 | 26 | > Make sure the WASM target is installed before running the projects. 27 | > You can install the WASM target for rust using rustup: 28 | > ``` 29 | > rustup target add wasm32-unknown-unknown 30 | > ``` 31 | 32 | Finally, serve your project: 33 | ``` 34 | dx serve 35 | ``` 36 | 37 | By default, the CLI serves your website at [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/). 38 | -------------------------------------------------------------------------------- /examples/ssr.rs: -------------------------------------------------------------------------------- 1 | //! Example: SSR 2 | //! 3 | //! This example shows how we can render the Dioxus Virtualdom using SSR. 4 | 5 | use dioxus::prelude::*; 6 | 7 | fn main() { 8 | // We can render VirtualDoms 9 | let mut vdom = VirtualDom::new(app); 10 | let _ = vdom.rebuild(); 11 | println!("{}", dioxus_ssr::render(&vdom)); 12 | 13 | // Or we can render rsx! calls themselves 14 | println!( 15 | "{}", 16 | dioxus_ssr::render_lazy(rsx! { 17 | div { 18 | h1 { "Hello, world!" } 19 | } 20 | }) 21 | ); 22 | 23 | // We can configure the SSR rendering to add ids for rehydration 24 | println!("{}", dioxus_ssr::pre_render(&vdom)); 25 | 26 | // We can render to a buf directly too 27 | let mut file = String::new(); 28 | let mut renderer = dioxus_ssr::Renderer::default(); 29 | renderer.render_to(&mut file, &vdom).unwrap(); 30 | println!("{file}"); 31 | } 32 | 33 | fn app(cx: Scope) -> Element { 34 | cx.render(rsx!( 35 | div { 36 | h1 { "Title" } 37 | p { "Body" } 38 | } 39 | )) 40 | } 41 | -------------------------------------------------------------------------------- /packages/core/src/bump_frame.rs: -------------------------------------------------------------------------------- 1 | use crate::nodes::RenderReturn; 2 | use bumpalo::Bump; 3 | use std::cell::{Cell, UnsafeCell}; 4 | 5 | pub(crate) struct BumpFrame { 6 | pub bump: UnsafeCell, 7 | pub node: Cell<*const RenderReturn<'static>>, 8 | } 9 | 10 | impl BumpFrame { 11 | pub(crate) fn new(capacity: usize) -> Self { 12 | let bump = Bump::with_capacity(capacity); 13 | Self { 14 | bump: UnsafeCell::new(bump), 15 | node: Cell::new(std::ptr::null()), 16 | } 17 | } 18 | 19 | /// Creates a new lifetime out of thin air 20 | pub(crate) unsafe fn try_load_node<'b>(&self) -> Option<&'b RenderReturn<'b>> { 21 | let node = self.node.get(); 22 | 23 | if node.is_null() { 24 | return None; 25 | } 26 | 27 | unsafe { std::mem::transmute(&*node) } 28 | } 29 | 30 | pub(crate) fn bump(&self) -> &Bump { 31 | unsafe { &*self.bump.get() } 32 | } 33 | 34 | #[allow(clippy::mut_from_ref)] 35 | pub(crate) unsafe fn bump_mut(&self) -> &mut Bump { 36 | unsafe { &mut *self.bump.get() } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/web/src/eval.js: -------------------------------------------------------------------------------- 1 | export class Dioxus { 2 | constructor(sendCallback, returnCallback) { 3 | this.sendCallback = sendCallback; 4 | this.returnCallback = returnCallback; 5 | this.promiseResolve = null; 6 | this.received = []; 7 | } 8 | 9 | // Receive message from Rust 10 | recv() { 11 | return new Promise((resolve, _reject) => { 12 | // If data already exists, resolve immediately 13 | let data = this.received.shift(); 14 | if (data) { 15 | resolve(data); 16 | return; 17 | } 18 | 19 | // Otherwise set a resolve callback 20 | this.promiseResolve = resolve; 21 | }); 22 | } 23 | 24 | // Send message to rust. 25 | send(data) { 26 | this.sendCallback(data); 27 | } 28 | 29 | // Internal rust send 30 | rustSend(data) { 31 | // If a promise is waiting for data, resolve it, and clear the resolve callback 32 | if (this.promiseResolve) { 33 | this.promiseResolve(data); 34 | this.promiseResolve = null; 35 | return; 36 | } 37 | 38 | // Otherwise add the data to a queue 39 | this.received.push(data); 40 | } 41 | } -------------------------------------------------------------------------------- /packages/router/src/utils/use_router_internal.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::{ScopeId, ScopeState}; 2 | 3 | use crate::prelude::*; 4 | 5 | /// A private hook to subscribe to the router. 6 | /// 7 | /// Used to reduce redundancy within other components/hooks. Safe to call multiple times for a 8 | /// single component, but not recommended. Multiple subscriptions will be discarded. 9 | /// 10 | /// # Return values 11 | /// - [`None`], when the current component isn't a descendant of a [`Link`] component. 12 | /// - Otherwise [`Some`]. 13 | pub(crate) fn use_router_internal(cx: &ScopeState) -> &Option { 14 | let inner = cx.use_hook(|| { 15 | let router = cx.consume_context::()?; 16 | 17 | let id = cx.scope_id(); 18 | router.subscribe(id); 19 | 20 | Some(Subscription { router, id }) 21 | }); 22 | cx.use_hook(|| inner.as_ref().map(|s| s.router.clone())) 23 | } 24 | 25 | struct Subscription { 26 | router: RouterContext, 27 | id: ScopeId, 28 | } 29 | 30 | impl Drop for Subscription { 31 | fn drop(&mut self) { 32 | self.router.unsubscribe(self.id); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/PWA-example/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dioxus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/html/src/events/drag.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::Event; 2 | 3 | use crate::MouseData; 4 | 5 | pub type DragEvent = Event; 6 | 7 | /// The DragEvent interface is a DOM event that represents a drag and drop interaction. The user initiates a drag by 8 | /// placing a pointer device (such as a mouse) on the touch surface and then dragging the pointer to a new location 9 | /// (such as another DOM element). Applications are free to interpret a drag and drop interaction in an 10 | /// application-specific way. 11 | #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] 12 | #[derive(Debug, Clone, PartialEq, Eq)] 13 | pub struct DragData { 14 | /// Inherit mouse data 15 | pub mouse: MouseData, 16 | } 17 | 18 | impl_event! { 19 | DragData; 20 | 21 | /// ondrag 22 | ondrag 23 | 24 | /// ondragend 25 | ondragend 26 | 27 | /// ondragenter 28 | ondragenter 29 | 30 | /// ondragexit 31 | ondragexit 32 | 33 | /// ondragleave 34 | ondragleave 35 | 36 | /// ondragover 37 | ondragover 38 | 39 | /// ondragstart 40 | ondragstart 41 | 42 | /// ondrop 43 | ondrop 44 | } 45 | -------------------------------------------------------------------------------- /packages/rink/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "plasmo" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley, Evan Almloff"] 5 | edition = "2021" 6 | description = "TUI-based renderer for Dioxus" 7 | repository = "https://github.com/DioxusLabs/dioxus/" 8 | homepage = "https://dioxuslabs.com" 9 | keywords = ["dom", "ui", "gui", "react", "terminal"] 10 | license = "MIT OR Apache-2.0" 11 | 12 | [dependencies] 13 | dioxus-html = { workspace = true } 14 | dioxus-native-core = { workspace = true, features = ["layout-attributes"] } 15 | dioxus-native-core-macro = { workspace = true } 16 | 17 | tui = "0.17.0" 18 | crossterm = "0.26.1" 19 | anyhow = "1.0.42" 20 | tokio = { workspace = true, features = ["full"] } 21 | futures = "0.3.19" 22 | taffy = "0.3.12" 23 | smallvec = "1.6" 24 | rustc-hash = { workspace = true } 25 | anymap = "1.0.0-beta.2" 26 | futures-channel = { workspace = true } 27 | shipyard = { version = "0.6.2", features = ["proc", "std"], default-features = false } 28 | once_cell = "1.17.1" 29 | 30 | [dev-dependencies] 31 | tokio = { version = "1" } 32 | criterion = "0.3.5" 33 | 34 | [features] 35 | default = [] 36 | parallel = ["shipyard/parallel"] 37 | -------------------------------------------------------------------------------- /packages/web/examples/timeout_count.rs: -------------------------------------------------------------------------------- 1 | // https://jakelazaroff.com/words/were-react-hooks-a-mistake/ 2 | use dioxus::prelude::*; 3 | 4 | fn main() { 5 | dioxus_web::launch(app); 6 | } 7 | 8 | fn app(cx: Scope) -> Element { 9 | let count = use_ref(cx, || 0); 10 | let started = use_state(cx, || false); 11 | 12 | let start = move || { 13 | if !*started.get() { 14 | let count = count.clone(); // clone reference rather than value 15 | let alert = move || gloo_dialogs::alert(&format!("Your score was {}!", count.read())); 16 | gloo_timers::callback::Timeout::new(5_000, alert).forget(); 17 | } 18 | started.set(true); // this cannot be done inside condition or infinite loop 19 | }; 20 | 21 | cx.render(rsx! { 22 | button { 23 | onclick: move |_event| { 24 | start(); 25 | *count.write() += 1; 26 | }, 27 | // format is needed as {count} does not seemed to work in `if` within content 28 | if **started { format!("Current score: {}", count.write()) } else { "Start".to_string() } 29 | } 30 | }) 31 | } 32 | -------------------------------------------------------------------------------- /examples/optional_props.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | //! Example: README.md showcase 4 | //! 5 | //! The example from the README.md. 6 | 7 | use dioxus::prelude::*; 8 | 9 | fn main() { 10 | dioxus_desktop::launch(app); 11 | } 12 | 13 | fn app(cx: Scope) -> Element { 14 | cx.render(rsx! { 15 | Button { 16 | a: "asd".to_string(), 17 | c: "asd".to_string(), 18 | d: Some("asd".to_string()), 19 | e: "asd".to_string(), 20 | } 21 | }) 22 | } 23 | 24 | type SthElse = Option; 25 | 26 | #[derive(Props, PartialEq)] 27 | struct ButtonProps { 28 | a: String, 29 | 30 | #[props(default)] 31 | b: String, 32 | 33 | c: Option, 34 | 35 | #[props(!optional)] 36 | d: Option, 37 | 38 | #[props(optional)] 39 | e: SthElse, 40 | } 41 | 42 | fn Button(cx: Scope) -> Element { 43 | cx.render(rsx! { 44 | button { 45 | "{cx.props.a} | " 46 | "{cx.props.b:?} | " 47 | "{cx.props.c:?} | " 48 | "{cx.props.d:?} | " 49 | "{cx.props.e:?}" 50 | } 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/long.rsx: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | 3 | #[component] 4 | pub fn Explainer<'a>( 5 | cx: Scope<'a>, 6 | invert: bool, 7 | title: &'static str, 8 | content: Element<'a>, 9 | flasher: Element<'a>, 10 | ) -> Element { 11 | // pt-5 sm:pt-24 lg:pt-24 12 | 13 | let mut right = rsx! { 14 | div { class: "relative w-1/2", flasher } 15 | }; 16 | 17 | let align = match invert { 18 | true => "mr-auto ml-16", 19 | false => "ml-auto mr-16", 20 | }; 21 | 22 | let mut left = rsx! { 23 | div { class: "relative w-1/2 {align} max-w-md leading-8", 24 | h2 { class: "mb-6 text-3xl leading-tight md:text-4xl md:leading-tight lg:text-3xl lg:leading-tight font-heading font-mono font-bold", 25 | "{title}" 26 | } 27 | content 28 | } 29 | }; 30 | 31 | if *invert { 32 | std::mem::swap(&mut left, &mut right); 33 | } 34 | 35 | cx.render(rsx! { 36 | div { class: "flex flex-wrap items-center dark:text-white py-16 border-t font-light", 37 | left, 38 | right 39 | } 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /packages/interpreter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-interpreter-js" 3 | version = { workspace = true } 4 | edition = "2018" 5 | authors = ["Jonathan Kelley"] 6 | description = "JS Intepreter for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | documentation = "https://docs.rs/dioxus" 11 | keywords = ["dom", "ui", "gui", "react", "wasm"] 12 | 13 | [dependencies] 14 | wasm-bindgen = { workspace = true, optional = true } 15 | js-sys = { version = "0.3.56", optional = true } 16 | web-sys = { version = "0.3.56", optional = true, features = ["Element", "Node"] } 17 | sledgehammer_bindgen = { version = "0.2.1", optional = true } 18 | sledgehammer_utils = { version = "0.2", optional = true } 19 | serde = { version = "1.0", features = ["derive"], optional = true } 20 | 21 | [features] 22 | default = [] 23 | serialize = ["serde"] 24 | web = ["wasm-bindgen", "js-sys", "web-sys"] 25 | sledgehammer = ["wasm-bindgen", "js-sys", "web-sys", "sledgehammer_bindgen", "sledgehammer_utils"] 26 | minimal_bindings = [] 27 | -------------------------------------------------------------------------------- /packages/router-macro/src/layout.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::quote; 3 | use syn::Path; 4 | 5 | use crate::nest::{Nest, NestId}; 6 | 7 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 8 | pub struct LayoutId(pub usize); 9 | 10 | #[derive(Debug)] 11 | pub struct Layout { 12 | pub comp: Path, 13 | pub active_nests: Vec, 14 | } 15 | 16 | impl Layout { 17 | pub fn routable_match(&self, nests: &[Nest]) -> TokenStream { 18 | let comp_name = &self.comp; 19 | let dynamic_segments = self 20 | .active_nests 21 | .iter() 22 | .flat_map(|id| nests[id.0].dynamic_segments()); 23 | 24 | quote! { 25 | render! { 26 | #comp_name { #(#dynamic_segments: #dynamic_segments,)* } 27 | } 28 | } 29 | } 30 | } 31 | 32 | impl Layout { 33 | pub fn parse(input: syn::parse::ParseStream, active_nests: Vec) -> syn::Result { 34 | // Then parse the component name 35 | let _ = input.parse::(); 36 | let comp: Path = input.parse()?; 37 | 38 | Ok(Self { comp, active_nests }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/extension/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 DioxusLabs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /playwright-tests/fullstack.spec.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const { test, expect } = require('@playwright/test'); 3 | 4 | test('button click', async ({ page }) => { 5 | await page.goto('http://localhost:3333'); 6 | 7 | // Expect the page to contain the counter text. 8 | const main = page.locator('#main'); 9 | await expect(main).toContainText('hello axum! 12345'); 10 | 11 | // Click the increment button. 12 | let button = page.locator('button.increment-button'); 13 | await button.click(); 14 | 15 | // Expect the page to contain the updated counter text. 16 | await expect(main).toContainText('hello axum! 12346'); 17 | }); 18 | 19 | test('fullstack communication', async ({ page }) => { 20 | await page.goto('http://localhost:3333'); 21 | 22 | // Expect the page to contain the counter text. 23 | const main = page.locator('#main'); 24 | await expect(main).toContainText('Server said: ...'); 25 | 26 | // Click the increment button. 27 | let button = page.locator('button.server-button'); 28 | await button.click(); 29 | 30 | // Expect the page to contain the updated counter text. 31 | await expect(main).toContainText('Server said: Hello from the server!'); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/core/src/subtree.rs: -------------------------------------------------------------------------------- 1 | /* 2 | This is a WIP module 3 | 4 | Subtrees allow the virtualdom to split up the mutation stream into smaller chunks which can be directed to different parts of the dom. 5 | It's core to implementing multiwindow desktop support, portals, and alternative inline renderers like react-three-fiber. 6 | 7 | The primary idea is to give each renderer a linear element tree managed by Dioxus to maximize performance and minimize memory usage. 8 | This can't be done if two renderers need to share the same native tree. 9 | With subtrees, we have an entirely different slab of elements 10 | 11 | */ 12 | 13 | use std::borrow::Cow; 14 | 15 | use slab::Slab; 16 | 17 | use crate::{ElementPath, ScopeId}; 18 | 19 | /// A collection of elements confined to a single scope under a chunk of the tree 20 | /// 21 | /// All elements in this collection are guaranteed to be in the same scope and share the same numbering 22 | /// 23 | /// This unit can be multithreaded 24 | /// Whenever multiple subtrees are present, we can perform **parallel diffing** 25 | pub struct Subtree { 26 | id: usize, 27 | namespace: Cow<'static, str>, 28 | root: ScopeId, 29 | elements: Slab, 30 | } 31 | -------------------------------------------------------------------------------- /packages/dioxus-tui/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-tui" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley, Evan Almloff"] 5 | edition = "2021" 6 | description = "TUI-based renderer for Dioxus" 7 | repository = "https://github.com/DioxusLabs/dioxus/" 8 | homepage = "https://dioxuslabs.com/learn/0.4/getting_started/tui" 9 | keywords = ["dom", "ui", "gui", "react", "terminal"] 10 | license = "MIT OR Apache-2.0" 11 | 12 | [dependencies] 13 | dioxus = { workspace = true } 14 | dioxus-core = { workspace = true, features = ["serialize"] } 15 | dioxus-html = { workspace = true } 16 | dioxus-native-core = { workspace = true, features = ["dioxus"] } 17 | dioxus-native-core-macro = { workspace = true } 18 | dioxus-hot-reload = { workspace = true, optional = true } 19 | plasmo = { workspace = true } 20 | 21 | crossterm = "0.26.0" 22 | tokio = { workspace = true, features = ["full"] } 23 | futures = "0.3.19" 24 | taffy = "0.3.12" 25 | 26 | [dev-dependencies] 27 | dioxus = { workspace = true } 28 | tokio = { version = "1" } 29 | criterion = "0.3.5" 30 | 31 | [[bench]] 32 | name = "update" 33 | harness = false 34 | 35 | [features] 36 | default = ["hot-reload"] 37 | hot-reload = ["dioxus-hot-reload"] 38 | -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/path.md: -------------------------------------------------------------------------------- 1 | # Path Functions 2 | 3 | You can use path functions to perform operations on valid path strings. 4 | 5 | ### `join(path: string, extra: string) -> string` 6 | 7 | 10 | Extend a path; you can extend both directory and file paths. 11 | 12 | ```lua 13 | local current_path = "~/hello/dioxus" 14 | local new_path = plugin.path.join(current_path, "world") 15 | -- new_path = "~/hello/dioxus/world" 16 | ``` 17 | 18 | ### `parent(path: string) -> string` 19 | 20 | Return the parent path of the specified path. The parent path is always a directory. 21 | 22 | ```lua 23 | local current_path = "~/hello/dioxus" 24 | local new_path = plugin.path.parent(current_path) 25 | -- new_path = "~/hello/" 26 | ``` 27 | 28 | ### `exists(path: string) -> boolean` 29 | 30 | Check if the specified path exists, as either a file or a directory. 31 | 32 | ### `is_file(path: string) -> boolean` 33 | 34 | Check if the specified path is a file. 35 | 36 | ### `is_dir(path: string) -> boolean` 37 | 38 | Check if the specified path is a directory. -------------------------------------------------------------------------------- /examples/inlineprops.rs: -------------------------------------------------------------------------------- 1 | //! Run with `cargo-expand` to see what each one expands to. 2 | //! This file is named `inlineprops.rs`, because there used to be a `#[inline_props]` macro to 3 | //! do this. However, it's now deprecated (and will likely be removed in a future major version), 4 | //! so please use `#[component]` instead! 5 | use dioxus::prelude::*; 6 | 7 | #[component] 8 | fn Thing1(cx: Scope, _a: T) -> Element { 9 | cx.render(rsx! { "" }) 10 | } 11 | 12 | #[component] 13 | fn Thing2(cx: Scope, _a: u32) -> Element<'a> { 14 | cx.render(rsx! { "" }) 15 | } 16 | 17 | #[component] 18 | fn Thing3<'a, T>(cx: Scope<'a>, _a: &'a T) -> Element<'a> { 19 | cx.render(rsx! { "" }) 20 | } 21 | 22 | #[component] 23 | fn Thing4<'a>(cx: Scope<'a>, _a: &'a u32) -> Element<'a> { 24 | cx.render(rsx! { "" }) 25 | } 26 | 27 | fn main() { 28 | dioxus_desktop::launch(App); 29 | } 30 | 31 | #[component] 32 | fn App(cx: Scope) -> Element { 33 | let state = use_state(cx, || 1); 34 | 35 | cx.render(rsx! { 36 | div { 37 | Thing1 { _a: 1 }, 38 | Thing2 { _a: 1 }, 39 | Thing3 { _a: state }, 40 | Thing4 { _a: state }, 41 | } 42 | }) 43 | } 44 | -------------------------------------------------------------------------------- /packages/hot-reload/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-hot-reload" 3 | authors = ["Jonathan Kelley", "Evan Almloff"] 4 | version = { workspace = true } 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/DioxusLabs/dioxus/" 8 | homepage = "https://dioxuslabs.com/learn/0.4/migration/hot_reload" 9 | description = "Hot reloading utilities for Dioxus" 10 | keywords = ["dom", "ui", "gui", "react", "hot-reloading"] 11 | 12 | [dependencies] 13 | dioxus-rsx = { workspace = true } 14 | dioxus-core = { workspace = true, features = ["serialize"] } 15 | dioxus-html = { workspace = true } 16 | 17 | interprocess-docfix = { version = "1.2.2" } 18 | notify = { version = "5.0.0", optional = true } 19 | chrono = { version = "0.4.24", default-features = false, features = ["clock"], optional = true } 20 | serde_json = "1.0.91" 21 | serde = { version = "1", features = ["derive"] } 22 | execute = { version = "0.2.11", optional = true } 23 | once_cell = { version = "1.17.0", optional = true } 24 | ignore = { version = "0.4.19", optional = true } 25 | 26 | [features] 27 | default = [] 28 | file_watcher = ["ignore", "chrono", "notify", "execute", "once_cell", "ignore", "dioxus-html/hot-reload-context"] 29 | -------------------------------------------------------------------------------- /packages/cli/docs/src/plugin/interface/network.md: -------------------------------------------------------------------------------- 1 | # Network Functions 2 | 3 | You can use Network functions to download & read some data from the internet. 4 | 5 | ### `download_file(url: string, path: string) -> boolean` 6 | 7 | Downloads a file from the specified URL, 8 | and returns a `boolean` that represents the download status (true: success, false: failure). 9 | 10 | You need to pass a target URL and a local path (where you want to save this file). 11 | 12 | ```lua 13 | -- this file will download to plugin temp directory 14 | local status = plugin.network.download_file( 15 | "http://xxx.com/xxx.zip", 16 | plugin.dirs.temp_dir() 17 | ) 18 | if status != true then 19 | log.error("Download Failed") 20 | end 21 | ``` 22 | 23 | ### `clone_repo(url: string, path: string) -> boolean` 24 | 25 | Clone a repository from the given URL into the given path. 26 | Returns a `boolean` that represents the clone status (true: success, false: failure). 27 | The system executing this function must have git installed. 28 | 29 | ```lua 30 | local status = plugin.network.clone_repo( 31 | "http://github.com/mrxiaozhuox/dioxus-starter", 32 | plugin.dirs.bin_dir() 33 | ) 34 | if status != true then 35 | log.error("Clone Failed") 36 | end 37 | ``` -------------------------------------------------------------------------------- /packages/autofmt/tests/samples.rs: -------------------------------------------------------------------------------- 1 | macro_rules! twoway { 2 | ( 3 | $( 4 | 5 | // doc attrs 6 | $( #[doc = $doc:expr] )* 7 | $name:ident, 8 | )* 9 | ) => { 10 | $( 11 | $( #[doc = $doc] )* 12 | #[test] 13 | fn $name() { 14 | let src = include_str!(concat!("./samples/", stringify!($name), ".rsx")); 15 | let formatted = dioxus_autofmt::fmt_file(src); 16 | let out = dioxus_autofmt::apply_formats(src, formatted); 17 | // normalize line endings 18 | let out = out.replace("\r", ""); 19 | let src = src.replace("\r", ""); 20 | pretty_assertions::assert_eq!(&src, &out); 21 | } 22 | )* 23 | }; 24 | } 25 | 26 | twoway![ 27 | attributes, 28 | collapse_expr, 29 | comments, 30 | commentshard, 31 | complex, 32 | emoji, 33 | ifchain_forloop, 34 | immediate_expr, 35 | key, 36 | long_exprs, 37 | long, 38 | manual_props, 39 | messy_indent, 40 | multirsx, 41 | raw_strings, 42 | reallylong, 43 | simple, 44 | t2, 45 | tiny, 46 | tinynoopt, 47 | trailing_expr, 48 | ]; 49 | -------------------------------------------------------------------------------- /packages/cli/src/cli/plugin.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "plugin")] 2 | 3 | use super::*; 4 | 5 | /// Manage plugins for dioxus cli 6 | #[derive(Clone, Debug, Deserialize, Subcommand)] 7 | #[clap(name = "plugin")] 8 | pub enum Plugin { 9 | /// Return all dioxus-cli support tools. 10 | List {}, 11 | /// Get default app install path. 12 | AppPath {}, 13 | /// Install a new tool. 14 | Add { name: String }, 15 | } 16 | 17 | impl Plugin { 18 | pub async fn plugin(self) -> Result<()> { 19 | match self { 20 | Plugin::List {} => { 21 | for item in crate::plugin::PluginManager::plugin_list() { 22 | println!("- {item}"); 23 | } 24 | } 25 | Plugin::AppPath {} => { 26 | let plugin_dir = crate::plugin::PluginManager::init_plugin_dir(); 27 | if let Some(v) = plugin_dir.to_str() { 28 | println!("{}", v); 29 | } else { 30 | log::error!("Plugin path get failed."); 31 | } 32 | } 33 | Plugin::Add { name: _ } => { 34 | log::info!("You can use `dx plugin app-path` to get Installation position"); 35 | } 36 | } 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/cli/tests/svg.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 8 | 9 | 10 | 15 | 16 | 17 | 22 | 23 | 24 | 29 | 30 |
-------------------------------------------------------------------------------- /packages/desktop/src/waker.rs: -------------------------------------------------------------------------------- 1 | use crate::desktop_context::{EventData, UserWindowEvent}; 2 | use futures_util::task::ArcWake; 3 | use std::sync::Arc; 4 | use wry::application::{event_loop::EventLoopProxy, window::WindowId}; 5 | 6 | /// Create a waker that will send a poll event to the event loop. 7 | /// 8 | /// This lets the VirtualDom "come up for air" and process events while the main thread is blocked by the WebView. 9 | /// 10 | /// All other IO lives in the Tokio runtime, 11 | pub fn tao_waker(proxy: &EventLoopProxy, id: WindowId) -> std::task::Waker { 12 | struct DomHandle { 13 | proxy: EventLoopProxy, 14 | id: WindowId, 15 | } 16 | 17 | // this should be implemented by most platforms, but ios is missing this until 18 | // https://github.com/tauri-apps/wry/issues/830 is resolved 19 | unsafe impl Send for DomHandle {} 20 | unsafe impl Sync for DomHandle {} 21 | 22 | impl ArcWake for DomHandle { 23 | fn wake_by_ref(arc_self: &Arc) { 24 | _ = arc_self 25 | .proxy 26 | .send_event(UserWindowEvent(EventData::Poll, arc_self.id)); 27 | } 28 | } 29 | 30 | futures_util::task::waker(Arc::new(DomHandle { 31 | id, 32 | proxy: proxy.clone(), 33 | })) 34 | } 35 | -------------------------------------------------------------------------------- /packages/hooks/src/usecallback.rs: -------------------------------------------------------------------------------- 1 | use dioxus_core::ScopeState; 2 | use std::future::Future; 3 | 4 | #[macro_export] 5 | macro_rules! use_callback { 6 | // ($cx:ident, || || $($rest:tt)*) => { use_callback( $cx, (), |_| $($rest)* ) }; 7 | // ($cx:ident, || || $($rest:tt)*) => { use_callback( $cx, (), |_| $($rest)* ) }; 8 | ($cx:ident, || $($rest:tt)*) => { 9 | use_callback( 10 | $cx, 11 | move || $($rest)* 12 | ) 13 | }; 14 | ($cx:ident, |$($args:tt),* | $($rest:tt)*) => { 15 | use_callback( 16 | $cx, 17 | move || $($rest)* 18 | ) 19 | }; 20 | ($cx:ident, $($rest:tt)*) => { 21 | use_callback( 22 | $cx, 23 | move || $($rest)* 24 | ) 25 | }; 26 | } 27 | pub fn use_callback(cx: &ScopeState, make: impl FnOnce() -> R) -> impl FnMut(T) + '_ 28 | where 29 | R: FnMut(T) -> F + 'static, 30 | F: Future + 'static, 31 | { 32 | let mut hook = make(); 33 | 34 | move |evt| cx.spawn(hook(evt)) 35 | } 36 | 37 | fn _it_works(cx: &ScopeState) { 38 | let _p = use_callback(cx, || { 39 | |()| async { 40 | // 41 | } 42 | }); 43 | 44 | // let p = use_callback!(cx, || |evt| async { 45 | // // 46 | // }); 47 | } 48 | -------------------------------------------------------------------------------- /packages/core/tests/README.md: -------------------------------------------------------------------------------- 1 | # Testing of Dioxus core 2 | 3 | 4 | Diffing 5 | - [x] create elements 6 | - [x] create text 7 | - [x] create fragments 8 | - [x] create empty fragments (placeholders) 9 | - [x] diff elements 10 | - [x] diff from element/text to fragment 11 | - [x] diff from element/text to empty fragment 12 | - [x] diff to element with children works too 13 | - [x] replace with works forward 14 | - [x] replace with works backward 15 | - [x] un-keyed diffing 16 | - [x] keyed diffing 17 | - [x] keyed diffing out of order 18 | - [x] keyed diffing with prefix/suffix 19 | - [x] suspended nodes work 20 | 21 | Lifecycle 22 | - [] Components mount properly 23 | - [] Components create new child components 24 | - [] Replaced components unmount old components and mount new 25 | - [] Post-render effects are called 26 | 27 | Shared Context 28 | - [] Shared context propagates downwards 29 | - [] unwrapping shared context if it doesn't exist works too 30 | 31 | Suspense 32 | - [] use_suspense generates suspended nodes 33 | 34 | 35 | Hooks 36 | - [] Drop order is maintained 37 | - [] Shared hook state is okay 38 | - [] use_hook works 39 | - [] use_ref works 40 | - [] use_noderef works 41 | - [] use_provide_state 42 | - [] use_consume_state 43 | 44 | 45 | VirtualDOM API 46 | - [] work 47 | - [] rebuild 48 | - [] change props 49 | -------------------------------------------------------------------------------- /packages/fermi/src/callback.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::all, unused)] 2 | 3 | use std::rc::Rc; 4 | 5 | use dioxus_core::prelude::*; 6 | 7 | use crate::{AtomRoot, Readable, Writable}; 8 | 9 | #[derive(Clone)] 10 | pub struct CallbackApi { 11 | root: Rc, 12 | } 13 | 14 | impl CallbackApi { 15 | // get the current value of the atom 16 | pub fn get(&self, atom: impl Readable) -> &V { 17 | todo!() 18 | } 19 | 20 | // get the current value of the atom in its RC container 21 | pub fn get_rc(&self, atom: impl Readable) -> &Rc { 22 | todo!() 23 | } 24 | 25 | // set the current value of the atom 26 | pub fn set(&self, atom: impl Writable, value: V) { 27 | todo!() 28 | } 29 | } 30 | 31 | pub fn use_atom_context(cx: &ScopeState) -> &CallbackApi { 32 | todo!() 33 | } 34 | 35 | macro_rules! use_callback { 36 | (&$cx:ident, [$($cap:ident),*], move || $body:expr) => { 37 | move || { 38 | $( 39 | #[allow(unused_mut)] 40 | let mut $cap = $cap.to_owned(); 41 | )* 42 | $cx.spawn($body); 43 | } 44 | }; 45 | } 46 | 47 | #[macro_export] 48 | macro_rules! to_owned { 49 | ($($es:ident),+) => {$( 50 | #[allow(unused_mut)] 51 | let mut $es = $es.to_owned(); 52 | )*} 53 | } 54 | -------------------------------------------------------------------------------- /examples/control_focus.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | use dioxus::prelude::*; 4 | 5 | fn main() { 6 | dioxus_desktop::launch(app); 7 | } 8 | 9 | fn app(cx: Scope) -> Element { 10 | let elements: &UseRef>> = use_ref(cx, Vec::new); 11 | let running = use_state(cx, || true); 12 | 13 | use_future!(cx, |(elements, running)| async move { 14 | let mut focused = 0; 15 | if *running.current() { 16 | loop { 17 | tokio::time::sleep(std::time::Duration::from_millis(10)).await; 18 | if let Some(element) = elements.read().get(focused) { 19 | element.set_focus(true); 20 | } else { 21 | focused = 0; 22 | } 23 | focused += 1; 24 | } 25 | } 26 | }); 27 | 28 | cx.render(rsx!( 29 | div { 30 | h1 { "Input Roulette" } 31 | for i in 0..100 { 32 | input { 33 | value: "{i}", 34 | onmounted: move |cx| { 35 | elements.write().push(cx.inner().clone()); 36 | }, 37 | oninput: move |_| { 38 | running.set(false); 39 | } 40 | } 41 | } 42 | } 43 | )) 44 | } 45 | -------------------------------------------------------------------------------- /packages/fullstack/src/hooks/server_cached.rs: -------------------------------------------------------------------------------- 1 | use serde::{de::DeserializeOwned, Serialize}; 2 | 3 | /// This allows you to send data from the server to the client. The data is serialized into the HTML on the server and hydrated on the client. 4 | /// 5 | /// When you run this function on the client, you need to be careful to insure the order you run it initially is the same order you run it on the server. 6 | /// 7 | /// If Dioxus fullstack cannot find the data on the client, it will run the closure again to get the data. 8 | /// 9 | /// # Example 10 | /// ```rust 11 | /// use dioxus::prelude::*; 12 | /// use dioxus_fullstack::prelude::*; 13 | /// 14 | /// fn app(cx: Scope) -> Element { 15 | /// let state1 = use_state(cx, || from_server(|| { 16 | /// 1234 17 | /// })); 18 | /// } 19 | /// ``` 20 | pub fn server_cached(server_fn: impl Fn() -> O) -> O { 21 | #[cfg(feature = "ssr")] 22 | { 23 | let data = server_fn(); 24 | let sc = crate::prelude::server_context(); 25 | if let Err(err) = sc.push_html_data(&data) { 26 | tracing::error!("Failed to push HTML data: {}", err); 27 | } 28 | data 29 | } 30 | #[cfg(not(feature = "ssr"))] 31 | { 32 | crate::html_storage::deserialize::take_server_data().unwrap_or_else(server_fn) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/liveview/src/main.js: -------------------------------------------------------------------------------- 1 | function main() { 2 | let root = window.document.getElementById("main"); 3 | if (root != null) { 4 | window.ipc = new IPC(root); 5 | } 6 | } 7 | 8 | class IPC { 9 | constructor(root) { 10 | // connect to the websocket 11 | window.interpreter = new Interpreter(root, new InterpreterConfig(false)); 12 | 13 | let ws = new WebSocket(WS_ADDR); 14 | 15 | function ping() { 16 | ws.send("__ping__"); 17 | } 18 | 19 | ws.onopen = () => { 20 | // we ping every 30 seconds to keep the websocket alive 21 | setInterval(ping, 30000); 22 | ws.send(serializeIpcMessage("initialize")); 23 | }; 24 | 25 | ws.onerror = (err) => { 26 | // todo: retry the connection 27 | }; 28 | 29 | ws.onmessage = (message) => { 30 | // Ignore pongs 31 | if (message.data != "__pong__") { 32 | const event = JSON.parse(message.data); 33 | switch (event.type) { 34 | case "edits": 35 | let edits = event.data; 36 | window.interpreter.handleEdits(edits); 37 | break; 38 | case "query": 39 | Function("Eval", `"use strict";${event.data};`)(); 40 | break; 41 | } 42 | } 43 | }; 44 | 45 | this.ws = ws; 46 | } 47 | 48 | postMessage(msg) { 49 | this.ws.send(msg); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/fermi/src/atoms/atom.rs: -------------------------------------------------------------------------------- 1 | use crate::{AtomId, AtomRoot, Readable, Writable}; 2 | 3 | pub struct Atom(pub fn(AtomBuilder) -> T); 4 | pub struct AtomBuilder; 5 | 6 | impl Readable for &'static Atom { 7 | fn read(&self, _root: AtomRoot) -> Option { 8 | todo!() 9 | } 10 | fn init(&self) -> V { 11 | self.0(AtomBuilder) 12 | } 13 | fn unique_id(&self) -> AtomId { 14 | *self as *const Atom as *const () 15 | } 16 | } 17 | 18 | impl Writable for &'static Atom { 19 | fn write(&self, _root: AtomRoot, _value: V) { 20 | todo!() 21 | } 22 | } 23 | 24 | #[test] 25 | fn atom_compiles() { 26 | static TEST_ATOM: Atom<&str> = Atom(|_| "hello"); 27 | dbg!((&TEST_ATOM).init()); 28 | } 29 | 30 | #[test] 31 | fn atom_is_unique() { 32 | static TEST_ATOM_1: Atom<&str> = Atom(|_| "hello"); 33 | static TEST_ATOM_2: Atom<&str> = Atom(|_| "hello"); 34 | assert_eq!((&TEST_ATOM_1).unique_id(), (&TEST_ATOM_1).unique_id()); 35 | assert_ne!((&TEST_ATOM_1).unique_id(), (&TEST_ATOM_2).unique_id()); 36 | } 37 | 38 | #[test] 39 | fn atom_is_unique_2() { 40 | struct S(String); 41 | static TEST_ATOM_1: Atom> = Atom(|_| Vec::new()); 42 | static TEST_ATOM_2: Atom> = Atom(|_| Vec::new()); 43 | assert_ne!((&TEST_ATOM_1).unique_id(), (&TEST_ATOM_2).unique_id()); 44 | } 45 | -------------------------------------------------------------------------------- /examples/hydration.rs: -------------------------------------------------------------------------------- 1 | //! Example: real-world usage of hydration 2 | //! ------------------------------------ 3 | //! 4 | //! This example shows how to pre-render a page using dioxus SSR and then how to rehydrate it on the client side. 5 | //! 6 | //! To accomplish hydration on the web, you'll want to set up a slightly more sophisticated build & bundle strategy. In 7 | //! the official docs, we have a guide for using DioxusStudio as a build tool with pre-rendering and hydration. 8 | //! 9 | //! In this example, we pre-render the page to HTML and then pass it into the desktop configuration. This serves as a 10 | //! proof-of-concept for the hydration feature, but you'll probably only want to use hydration for the web. 11 | 12 | use dioxus::prelude::*; 13 | use dioxus_desktop::Config; 14 | 15 | fn main() { 16 | let mut vdom = VirtualDom::new(app); 17 | let _ = vdom.rebuild(); 18 | let content = dioxus_ssr::pre_render(&vdom); 19 | 20 | dioxus_desktop::launch_cfg(app, Config::new().with_prerendered(content)); 21 | } 22 | 23 | fn app(cx: Scope) -> Element { 24 | let val = use_state(cx, || 0); 25 | 26 | cx.render(rsx! { 27 | div { 28 | h1 { "hello world. Count: {val}" } 29 | button { 30 | onclick: move |_| *val.make_mut() += 1, 31 | "click to increment" 32 | } 33 | } 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /examples/window_focus.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_desktop::tao::event::WindowEvent; 3 | use dioxus_desktop::use_wry_event_handler; 4 | use dioxus_desktop::wry::application::event::Event as WryEvent; 5 | use dioxus_desktop::{Config, WindowCloseBehaviour}; 6 | 7 | fn main() { 8 | let cfg = Config::new().with_close_behaviour(WindowCloseBehaviour::CloseWindow); 9 | 10 | dioxus_desktop::launch_cfg(app, cfg); 11 | } 12 | 13 | fn app(cx: Scope) -> Element { 14 | let focused = use_state(cx, || false); 15 | 16 | use_wry_event_handler(cx, { 17 | to_owned![focused]; 18 | move |event, _| { 19 | if let WryEvent::WindowEvent { 20 | event: WindowEvent::Focused(new_focused), 21 | .. 22 | } = event 23 | { 24 | focused.set(*new_focused); 25 | } 26 | } 27 | }); 28 | 29 | cx.render(rsx! { 30 | div{ 31 | width: "100%", 32 | height: "100%", 33 | display: "flex", 34 | flex_direction: "column", 35 | align_items: "center", 36 | { 37 | if *focused.get() { 38 | "This window is focused!" 39 | } else { 40 | "This window is not focused!" 41 | } 42 | } 43 | } 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /packages/core/tests/miri_full_app.rs: -------------------------------------------------------------------------------- 1 | use dioxus::prelude::*; 2 | use dioxus_core::ElementId; 3 | use std::rc::Rc; 4 | 5 | #[test] 6 | fn miri_rollover() { 7 | let mut dom = VirtualDom::new(App); 8 | 9 | _ = dom.rebuild(); 10 | 11 | for _ in 0..3 { 12 | dom.handle_event("click", Rc::new(MouseData::default()), ElementId(2), true); 13 | dom.process_events(); 14 | _ = dom.render_immediate(); 15 | } 16 | } 17 | 18 | #[component] 19 | fn App(cx: Scope) -> Element { 20 | let mut idx = use_state(cx, || 0); 21 | let onhover = |_| println!("go!"); 22 | 23 | cx.render(rsx! { 24 | div { 25 | button { 26 | onclick: move |_| { 27 | idx += 1; 28 | println!("Clicked"); 29 | }, 30 | "+" 31 | } 32 | button { onclick: move |_| idx -= 1, "-" } 33 | ul { 34 | (0..**idx).map(|i| rsx! { 35 | ChildExample { i: i, onhover: onhover } 36 | }) 37 | } 38 | } 39 | }) 40 | } 41 | 42 | #[component] 43 | fn ChildExample<'a>(cx: Scope<'a>, i: i32, onhover: EventHandler<'a, MouseEvent>) -> Element { 44 | cx.render(rsx! { 45 | li { 46 | onmouseover: move |e| onhover.call(e), 47 | "{i}" 48 | } 49 | }) 50 | } 51 | -------------------------------------------------------------------------------- /packages/fullstack/examples/axum-desktop/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | use dioxus::prelude::*; 3 | use dioxus_fullstack::prelude::*; 4 | 5 | pub fn app(cx: Scope) -> Element { 6 | let mut count = use_state(cx, || 0); 7 | let text = use_state(cx, || "...".to_string()); 8 | 9 | cx.render(rsx! { 10 | h1 { "High-Five counter: {count}" } 11 | button { onclick: move |_| count += 1, "Up high!" } 12 | button { onclick: move |_| count -= 1, "Down low!" } 13 | button { 14 | onclick: move |_| { 15 | to_owned![text]; 16 | async move { 17 | if let Ok(data) = get_server_data().await { 18 | println!("Client received: {}", data); 19 | text.set(data.clone()); 20 | post_server_data(data).await.unwrap(); 21 | } 22 | } 23 | }, 24 | "Run a server function" 25 | } 26 | "Server said: {text}" 27 | }) 28 | } 29 | 30 | #[server(PostServerData)] 31 | async fn post_server_data(data: String) -> Result<(), ServerFnError> { 32 | println!("Server received: {}", data); 33 | 34 | Ok(()) 35 | } 36 | 37 | #[server(GetServerData)] 38 | async fn get_server_data() -> Result { 39 | Ok("Hello from the server!".to_string()) 40 | } 41 | -------------------------------------------------------------------------------- /packages/signals/tests/effect.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused, non_upper_case_globals, non_snake_case)] 2 | use std::collections::HashMap; 3 | use std::rc::Rc; 4 | 5 | use dioxus::prelude::*; 6 | use dioxus_core::ElementId; 7 | use dioxus_signals::*; 8 | 9 | #[test] 10 | fn effects_rerun() { 11 | simple_logger::SimpleLogger::new().init().unwrap(); 12 | 13 | #[derive(Default)] 14 | struct RunCounter { 15 | component: usize, 16 | effect: usize, 17 | } 18 | 19 | let counter = Rc::new(RefCell::new(RunCounter::default())); 20 | let mut dom = VirtualDom::new_with_props( 21 | |cx| { 22 | let counter = cx.props; 23 | counter.borrow_mut().component += 1; 24 | 25 | let mut signal = use_signal(cx, || 0); 26 | cx.use_hook(move || { 27 | to_owned![counter]; 28 | Effect::new(move || { 29 | counter.borrow_mut().effect += 1; 30 | println!("Signal: {:?}", signal); 31 | }) 32 | }); 33 | signal += 1; 34 | 35 | render! { 36 | div {} 37 | } 38 | }, 39 | counter.clone(), 40 | ); 41 | 42 | let _ = dom.rebuild().santize(); 43 | 44 | let current_counter = counter.borrow(); 45 | assert_eq!(current_counter.component, 1); 46 | assert_eq!(current_counter.effect, 2); 47 | } 48 | -------------------------------------------------------------------------------- /packages/html/src/native_bind/native_file_engine.rs: -------------------------------------------------------------------------------- 1 | use std::any::Any; 2 | use std::path::PathBuf; 3 | 4 | use crate::FileEngine; 5 | use tokio::fs::File; 6 | use tokio::io::AsyncReadExt; 7 | 8 | pub struct NativeFileEngine { 9 | files: Vec, 10 | } 11 | 12 | impl NativeFileEngine { 13 | pub fn new(files: Vec) -> Self { 14 | Self { files } 15 | } 16 | } 17 | 18 | #[async_trait::async_trait(?Send)] 19 | impl FileEngine for NativeFileEngine { 20 | fn files(&self) -> Vec { 21 | self.files 22 | .iter() 23 | .filter_map(|f| Some(f.to_str()?.to_string())) 24 | .collect() 25 | } 26 | 27 | async fn read_file(&self, file: &str) -> Option> { 28 | let mut file = File::open(file).await.ok()?; 29 | 30 | let mut contents = Vec::new(); 31 | file.read_to_end(&mut contents).await.ok()?; 32 | 33 | Some(contents) 34 | } 35 | 36 | async fn read_file_to_string(&self, file: &str) -> Option { 37 | let mut file = File::open(file).await.ok()?; 38 | 39 | let mut contents = String::new(); 40 | file.read_to_string(&mut contents).await.ok()?; 41 | 42 | Some(contents) 43 | } 44 | 45 | async fn get_native_file(&self, file: &str) -> Option> { 46 | let file = File::open(file).await.ok()?; 47 | Some(Box::new(file)) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/native-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-native-core" 3 | version = { workspace = true } 4 | edition = "2021" 5 | license = "MIT OR Apache-2.0" 6 | repository = "https://github.com/DioxusLabs/dioxus/" 7 | homepage = "https://dioxuslabs.com" 8 | description = "Build natively rendered apps with Dioxus" 9 | keywords = ["dom", "ui", "gui", "react"] 10 | authors = ["Jonathan Kelley", "Evan Almloff"] 11 | 12 | [dependencies] 13 | dioxus-core = { workspace = true, optional = true } 14 | 15 | keyboard-types = "0.7" 16 | smallvec = "1.6" 17 | rustc-hash = { workspace = true } 18 | anymap = "1.0.0-beta.2" 19 | slab = { workspace = true } 20 | parking_lot = { version = "0.12.1", features = ["send_guard"] } 21 | dashmap = "5.4.0" 22 | 23 | # for parsing attributes 24 | taffy = { version = "0.3.12", optional = true } 25 | lightningcss = { version = "1.0.0-alpha.39", optional = true } 26 | 27 | rayon = "1.6.1" 28 | shipyard = { version = "0.6.2", features = ["proc", "std"], default-features = false } 29 | 30 | [dev-dependencies] 31 | rand = "0.8.5" 32 | dioxus = { workspace = true } 33 | tokio = { workspace = true, features = ["full"] } 34 | dioxus-native-core = { workspace = true, features = ["dioxus"] } 35 | dioxus-native-core-macro = { workspace = true } 36 | 37 | [features] 38 | default = [] 39 | layout-attributes = ["dep:taffy", "dep:lightningcss"] 40 | dioxus = ["dioxus-core"] 41 | parallel = ["shipyard/parallel"] 42 | -------------------------------------------------------------------------------- /packages/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dioxus-core" 3 | version = { workspace = true } 4 | authors = ["Jonathan Kelley"] 5 | edition = "2018" 6 | description = "Core functionality for Dioxus - a concurrent renderer-agnostic Virtual DOM for interactive user experiences" 7 | license = "MIT OR Apache-2.0" 8 | repository = "https://github.com/DioxusLabs/dioxus/" 9 | homepage = "https://dioxuslabs.com" 10 | keywords = ["dom", "ui", "gui", "react"] 11 | 12 | [dependencies] 13 | # Bumpalo is used as a micro heap backing each component 14 | bumpalo = { version = "3.6", features = ["collections", "boxed"] } 15 | 16 | # faster hashmaps 17 | rustc-hash = { workspace = true } 18 | 19 | # Used in diffing 20 | longest-increasing-subsequence = "0.1.0" 21 | 22 | futures-util = { workspace = true, default-features = false, features = [ 23 | "alloc", 24 | ] } 25 | 26 | slab = { workspace = true } 27 | 28 | futures-channel = { workspace = true } 29 | 30 | smallbox = "0.8.1" 31 | tracing = { workspace = true } 32 | 33 | # Serialize the Edits for use in Webview/Liveview instances 34 | serde = { version = "1", features = ["derive"], optional = true } 35 | 36 | [dev-dependencies] 37 | tokio = { workspace = true, features = ["full"] } 38 | dioxus = { workspace = true } 39 | pretty_assertions = "1.3.0" 40 | rand = "0.8.5" 41 | dioxus-ssr = { workspace = true } 42 | trybuild = "1.0" 43 | 44 | [features] 45 | default = [] 46 | serialize = ["serde"] 47 | -------------------------------------------------------------------------------- /packages/generational-box/README.md: -------------------------------------------------------------------------------- 1 | # Generational Box 2 | 3 | Generational Box is a runtime for Rust that allows any static type to implement `Copy`. It can be combined with a global runtime to create an ergonomic state solution like `dioxus-signals`. This crate contains no `unsafe` code. 4 | 5 | Three main types manage state in Generational Box: 6 | 7 | - Store: Handles recycling generational boxes that have been dropped. Your application should have one store or one store per thread. 8 | - Owner: Handles dropping generational boxes. The owner acts like a runtime lifetime guard. Any states that you create with an owner will be dropped when that owner is dropped. 9 | - GenerationalBox: The core Copy state type. The generational box will be dropped when the owner is dropped. 10 | 11 | Example: 12 | 13 | ```rust 14 | // Create a store for this thread 15 | let store = Store::default(); 16 | 17 | { 18 | // Create an owner for some state for a scope 19 | let owner = store.owner(); 20 | 21 | // Create some non-copy data, move it into a owner, and work with copy data 22 | let data: String = "hello world".to_string(); 23 | let key = owner.insert(data); 24 | 25 | // The generational box can be read from and written to like a RefCell 26 | let value = key.read(); 27 | assert_eq!(*value, "hello world"); 28 | } 29 | // Reading value at this point will cause a panic 30 | ``` 31 | 32 | ## How it works 33 | 34 | Internally -------------------------------------------------------------------------------- /examples/counter.rs: -------------------------------------------------------------------------------- 1 | //! Comparison example with leptos' counter example 2 | //! https://github.com/leptos-rs/leptos/blob/main/examples/counters/src/lib.rs 3 | 4 | use dioxus::prelude::*; 5 | 6 | fn main() { 7 | dioxus_desktop::launch(app); 8 | } 9 | 10 | fn app(cx: Scope) -> Element { 11 | let counters = use_state(cx, || vec![0, 0, 0]); 12 | let sum: usize = counters.iter().copied().sum(); 13 | 14 | render! { 15 | div { 16 | button { onclick: move |_| counters.make_mut().push(0), "Add counter" } 17 | button { onclick: move |_| { counters.make_mut().pop(); }, "Remove counter" } 18 | p { "Total: {sum}" } 19 | for (i, counter) in counters.iter().enumerate() { 20 | li { 21 | button { onclick: move |_| counters.make_mut()[i] -= 1, "-1" } 22 | input { 23 | value: "{counter}", 24 | oninput: move |e| { 25 | if let Ok(value) = e.value.parse::() { 26 | counters.make_mut()[i] = value; 27 | } 28 | } 29 | } 30 | button { onclick: move |_| counters.make_mut()[i] += 1, "+1" } 31 | button { onclick: move |_| { counters.make_mut().remove(i); }, "x" } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/autofmt/tests/samples/attributes.rsx: -------------------------------------------------------------------------------- 1 | rsx! { 2 | div { 3 | key: "ddd", 4 | class: "asd", 5 | class: "asd", 6 | class: "asd", 7 | class: "asd", 8 | class: "asd", 9 | class: "asd", 10 | blah: 123, 11 | onclick: move |_| { 12 | let blah = 120; 13 | true 14 | }, 15 | onclick: move |_| { 16 | let blah = 120; 17 | true 18 | }, 19 | onclick: move |_| { 20 | let blah = 120; 21 | true 22 | }, 23 | onclick: move |_| { 24 | let blah = 120; 25 | true 26 | }, 27 | div { 28 | div { "hi" } 29 | h2 { class: "asd" } 30 | } 31 | Component {} 32 | Component {} 33 | } 34 | 35 | // Long attributes 36 | div { 37 | a: "1234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910", 38 | a: "123", 39 | a: "123", 40 | a: "123", 41 | a: "123", 42 | a: "123", 43 | a: "123", 44 | a: "123", 45 | a: "123" 46 | } 47 | 48 | div { 49 | a: "123", 50 | a: "123", 51 | a: "123", 52 | a: "123", 53 | a: "123", 54 | a: "123", 55 | a: "123", 56 | a: "123", 57 | a: "123" 58 | } 59 | } 60 | --------------------------------------------------------------------------------