From 51d7affc54ac34ea007227e590188940b2490c96 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sat, 31 May 2025 12:52:19 +0100 Subject: [PATCH] Upgrade to Blitz 0.1.0-alpha.2 (#4227) * Update to use latest Blitz net traits * Pass url to flush_style_attribute * Add system-fonts feature to dioxus-native * Native: cleanup log output * Make dioxus-native work with Blitz simplified Document and Renderer traits * Native: upgrade to event refactor * Upgrade to blitz 0.1.0-alpha.2 * Add typo exception Signed-off-by: Nico Burns * Ensure root_id is set to
element --------- Signed-off-by: Nico Burns --- Cargo.lock | 355 ++++----- _typos.toml | 2 + packages/native/Cargo.toml | 22 +- packages/native/src/assets.rs | 45 +- packages/native/src/dioxus_application.rs | 50 +- packages/native/src/dioxus_document.rs | 693 +++++------------- packages/native/src/event.rs | 23 - .../src/{event_handler.rs => events.rs} | 0 packages/native/src/lib.rs | 41 +- packages/native/src/mutation_writer.rs | 645 +++++----------- 10 files changed, 654 insertions(+), 1222 deletions(-) delete mode 100644 packages/native/src/event.rs rename packages/native/src/{event_handler.rs => events.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 35e844eaf..e7111fc79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,6 +379,47 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" +[[package]] +name = "anyrender" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff8da5f4a3e508ed376118a7e04ed992df07630fb47d7b3dce8d1f92427975d" +dependencies = [ + "kurbo", + "peniko", + "raw-window-handle 0.6.2", +] + +[[package]] +name = "anyrender_svg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4197139c97b2d204e44fd79c58e16f1c6023d18fe3db1e3eebfa335f78e39072" +dependencies = [ + "anyrender", + "image", + "kurbo", + "peniko", + "thiserror 2.0.12", + "usvg", +] + +[[package]] +name = "anyrender_vello" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e99c7f0936960037aa11d64bf7c9c5cf2f624dd9faf8c57a6581b056e08852" +dependencies = [ + "anyrender", + "futures-intrusive", + "kurbo", + "peniko", + "pollster", + "raw-window-handle 0.6.2", + "vello", + "wgpu 24.0.5", +] + [[package]] name = "app_units" version = "0.7.8" @@ -1563,24 +1604,26 @@ dependencies = [ [[package]] name = "blitz-dom" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae8889dde80e2aaceec27455c63446ca841cb7217a4f5489691295da922792b" +checksum = "7dc174ecca5c3e94b162335be4c9e17b35a0b421898ea559cb7f5926ff0fe5c6" dependencies = [ "accesskit", "app_units", "atomic_refcell", "blitz-traits", - "color 0.2.4", + "color", "cursor-icon", "euclid", "html-escape", "image", "keyboard-types", - "markup5ever 0.15.0", + "markup5ever 0.16.1", + "objc2 0.6.1", "parley", - "peniko 0.3.2", - "selectors 0.27.0", + "peniko", + "percent-encoding", + "selectors 0.28.0", "slab", "smallvec", "string_cache", @@ -1597,49 +1640,49 @@ dependencies = [ [[package]] name = "blitz-net" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc80023b8f6758d7f61bda68440917b72cbe2fe6187cbe1b7837e73b2522dfe" +checksum = "96b2788c54be9856d8a13a8bfcf0f184573d7169fdb6bf3f867cef87eca48874" dependencies = [ "blitz-traits", "data-url 0.3.1", "reqwest 0.12.15", - "thiserror 1.0.69", "tokio", ] [[package]] -name = "blitz-renderer-vello" -version = "0.1.0-alpha.1" +name = "blitz-paint" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fdafaf87eb502da99667fad2ae9757d01c8bd83772f6b7b6a78c48c3ab6ff5" +checksum = "3dd45f19bf9db46e67282bd24e764904c9624458fc4f71ec6566cc916e43ef36" dependencies = [ + "anyrender", + "anyrender_svg", "blitz-dom", "blitz-traits", - "color 0.2.4", + "color", "euclid", - "futures-intrusive", - "image", + "kurbo", "parley", - "pollster", - "raw-window-handle 0.6.2", + "peniko", "stylo", "taffy", - "vello", - "vello_svg", - "wgpu 23.0.1", + "tracing", + "usvg", ] [[package]] name = "blitz-shell" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0a6122f3619a746dddd21883edaae5f791d6e9f401dbdf7f7756caa4f69453" +checksum = "ac5e9acd11cd37fee6819686eb4893ae175e2c2563865fb823a9811418a90541" dependencies = [ "accesskit", "accesskit_winit", "android-activity", + "anyrender", "blitz-dom", + "blitz-paint", "blitz-traits", "futures-util", "keyboard-types", @@ -1650,15 +1693,15 @@ dependencies = [ [[package]] name = "blitz-traits" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9972442314e8bf9dd65af7aee0634a2d575972587d404520c7c6986abbd523d3" +checksum = "1d0ce7b7e5e2f49321dc4cec28ea7e83b7af0a287eb705674e36a9ac8f9691b9" dependencies = [ "bitflags 2.9.1", "bytes", + "cursor-icon", "http 1.3.1", "keyboard-types", - "raw-window-handle 0.6.2", "smol_str", "url", ] @@ -2457,12 +2500,6 @@ dependencies = [ "unicode-width 0.2.0", ] -[[package]] -name = "color" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7f99105610438d4b3ee7ae8e453c2990e325c806a14d71e8ea937d584c5289" - [[package]] name = "color" version = "0.3.1" @@ -4300,9 +4337,11 @@ dependencies = [ name = "dioxus-native" version = "0.7.0-alpha.0" dependencies = [ + "anyrender", + "anyrender_vello", "blitz-dom", "blitz-net", - "blitz-renderer-vello", + "blitz-paint", "blitz-shell", "blitz-traits", "dioxus-asset-resolver", @@ -5343,15 +5382,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" -[[package]] -name = "font-types" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa6a5e5a77b5f3f7f9e32879f484aa5b3632ddfbe568a16266c904a6f32cdaf" -dependencies = [ - "bytemuck", -] - [[package]] name = "font-types" version = "0.9.0" @@ -5396,20 +5426,21 @@ dependencies = [ [[package]] name = "fontique" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5fcb214137f01bc842c4fd633236255c51f8a24c6d3923eb8361c6d0940737" +checksum = "64763d1f274c8383333851435b6cdf071c31cfcdb39fd5860d20943205a007a7" dependencies = [ "bytemuck", "fontconfig-cache-parser", "hashbrown 0.15.3", "icu_locid", "memmap2", + "objc2 0.6.1", "objc2-core-foundation", "objc2-core-text", "objc2-foundation 0.3.1", - "peniko 0.3.2", - "read-fonts 0.25.3", + "peniko", + "read-fonts", "roxmltree", "smallvec", "windows 0.58.0", @@ -6469,9 +6500,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.14.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51fa363f025f5c111e03f13eda21162faeacb6911fe8caa0c0349f9cf0c4483" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" dependencies = [ "js-sys", "slotmap", @@ -8676,16 +8707,13 @@ dependencies = [ [[package]] name = "markup5ever" -version = "0.15.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a7b81dfb91586d0677086d40a6d755070e0799b71bb897485bac408dfd5c69" +checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" dependencies = [ "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", ] [[package]] @@ -8824,9 +8852,9 @@ dependencies = [ [[package]] name = "metal" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ "bitflags 2.9.1", "block", @@ -9014,22 +9042,23 @@ dependencies = [ [[package]] name = "naga" -version = "23.1.0" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" dependencies = [ "arrayvec", "bit-set 0.8.0", "bitflags 2.9.1", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "codespan-reporting 0.11.1", "hexf-parse", "indexmap 2.9.0", "log", "rustc-hash 1.1.0", "spirv", + "strum 0.26.3", "termcolor", - "thiserror 1.0.69", + "thiserror 2.0.12", "unicode-xid", ] @@ -9900,6 +9929,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-stream" version = "0.2.0" @@ -10123,14 +10161,14 @@ dependencies = [ [[package]] name = "parley" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d1c2b33b240c246f06cfceac48dc6c96040cb177d2aa5348899982b298b5577" +checksum = "e28dadbe655332fd7d996794ec8d0c376695f6ca47bc75aa01e0967c7f28e42a" dependencies = [ "fontique", "hashbrown 0.15.3", - "peniko 0.3.2", - "skrifa 0.26.6", + "peniko", + "skrifa", "swash", ] @@ -10234,25 +10272,13 @@ dependencies = [ "base64ct", ] -[[package]] -name = "peniko" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1f594c54ccdc9bd177a726885f066bf28d20e17169e31a8a1456217b1316b4" -dependencies = [ - "color 0.2.4", - "kurbo", - "peniko 0.4.0", - "smallvec", -] - [[package]] name = "peniko" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f9529efd019889b2a205193c14ffb6e2839b54ed9d2720674f10f4b04d87ac9" dependencies = [ - "color 0.3.1", + "color", "kurbo", "smallvec", ] @@ -11379,16 +11405,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "read-fonts" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f9e8a4f503e5c8750e4cd3b32a4e090035c46374b305a15c70bad833dca05f" -dependencies = [ - "bytemuck", - "font-types 0.8.4", -] - [[package]] name = "read-fonts" version = "0.29.1" @@ -11396,7 +11412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e85935612710191461ec9df47b4b5880dd6359d4fad3b2f2ed696215f6f3146" dependencies = [ "bytemuck", - "font-types 0.9.0", + "font-types", ] [[package]] @@ -12238,9 +12254,9 @@ dependencies = [ [[package]] name = "selectors" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b75e048a93e14929e68e37b82e207db957cbb368375a80ed3ca28ac75080856" +checksum = "db3079aef7a4383aff1e60eca2818995d3de8168e85ae4b6ea8fb2804b182c54" dependencies = [ "bitflags 2.9.1", "cssparser 0.35.0", @@ -12342,7 +12358,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "ordered-float", + "ordered-float 2.10.1", "serde", ] @@ -12743,16 +12759,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" -[[package]] -name = "skrifa" -version = "0.26.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc1aa86c26dbb1b63875a7180aa0819709b33348eb5b1491e4321fae388179d" -dependencies = [ - "bytemuck", - "read-fonts 0.25.3", -] - [[package]] name = "skrifa" version = "0.31.1" @@ -12760,7 +12766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9c3bb8cab5196b98d70c866ce1ea81ab516104d5b396f84ae80f8766b5d5b4e" dependencies = [ "bytemuck", - "read-fonts 0.29.1", + "read-fonts", ] [[package]] @@ -13393,9 +13399,9 @@ dependencies = [ [[package]] name = "stylo" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfacf8821bb157fbd6cebaa682f22bcebddc38e4165cdedba0061dae24b241c2" +checksum = "d6034deda3e062865c4011d70a97ba8691bb00777f14c4575bee41451e46594d" dependencies = [ "app_units", "arrayvec", @@ -13409,12 +13415,11 @@ dependencies = [ "fxhash", "icu_segmenter", "indexmap 2.9.0", - "itertools 0.10.5", + "itertools 0.14.0", "itoa 1.0.15", "lazy_static", "log", "malloc_size_of_derive", - "markup5ever 0.15.0", "matches", "mime", "new_debug_unreachable", @@ -13426,7 +13431,7 @@ dependencies = [ "precomputed-hash", "rayon", "rayon-core", - "selectors 0.27.0", + "selectors 0.28.0", "serde", "servo_arc 0.4.0", "smallbitvec", @@ -13448,13 +13453,14 @@ dependencies = [ "url", "void", "walkdir", + "web_atoms", ] [[package]] name = "stylo_atoms" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b943c983729930ee70141ab6515604bb33ff5de8d7626024072c38a27c8023bb" +checksum = "4b7dacdd62700078300263cece93a9c41823305d461ee5b3b65a51d6cdce3d38" dependencies = [ "string_cache", "string_cache_codegen", @@ -13462,15 +13468,15 @@ dependencies = [ [[package]] name = "stylo_config" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e53afe5289d75063564e60aa59c591a2c496d3425f2bb2a3002251785e2058" +checksum = "3fe07c673f8989e237e544c17723a8831d37d80b1a55437ac67bec8fe877e3cb" [[package]] name = "stylo_derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e745b58d581ba8eb932825e684634eae9be848fd49c086b3f17ccb7d6c417594" +checksum = "9a2c2bf677324ef587e97b8f5fc055f97a50bd26493411100e1442824ab289b8" dependencies = [ "darling", "proc-macro2", @@ -13481,9 +13487,9 @@ dependencies = [ [[package]] name = "stylo_dom" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06606e83c4feb986ea601a2c7d625aa5c303ecfc9526494480f6e599b8d6956e" +checksum = "183a89dc60a136308a1c83056660692bb598b3a99db2ac79b1b53f935cf3c87d" dependencies = [ "bitflags 2.9.1", "stylo_malloc_size_of", @@ -13491,14 +13497,14 @@ dependencies = [ [[package]] name = "stylo_malloc_size_of" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93db6fdbcde7f037f7810873374d85a2b3d37686b046577943818167a6e52d3f" +checksum = "150243bffdabaeafc7370354f6102559fec103b63d84875383fb657dd9c8549c" dependencies = [ "app_units", "cssparser 0.35.0", "euclid", - "selectors 0.27.0", + "selectors 0.28.0", "servo_arc 0.4.0", "smallbitvec", "smallvec", @@ -13509,15 +13515,15 @@ dependencies = [ [[package]] name = "stylo_static_prefs" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decb57071c4b4d5690a9719fb04a07cf2fab0fa3df99a830ef735192a1a98e5d" +checksum = "9600d11cdad6c275426272f35fbe085c4362be1d67bb9775f378fd2be7942d3a" [[package]] name = "stylo_taffy" -version = "0.1.0-alpha.1" +version = "0.1.0-alpha.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6da84b2bae9d25a2156b7cf89acab90683ac4d25dcb3fe1817dc9e77a20ce2f" +checksum = "1c0f66aad13b557aafcf971220a04150228604da2b377f0b2aa6a03113adfac7" dependencies = [ "stylo", "taffy", @@ -13525,16 +13531,16 @@ dependencies = [ [[package]] name = "stylo_traits" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f611ebeee90c0d255bf4d4fadc05f964ef019f8aaed307108fa859c826f2753" +checksum = "2a24b6eb257a1e68e184e113a3a426dd9e38e4a0017b805fcf43a44c939e5642" dependencies = [ "app_units", "bitflags 2.9.1", "cssparser 0.35.0", "euclid", "malloc_size_of_derive", - "selectors 0.27.0", + "selectors 0.28.0", "serde", "servo_arc 0.4.0", "stylo_atoms", @@ -13634,7 +13640,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f745de914febc7c9ab4388dfaf94bbc87e69f57bb41133a9b0c84d4be49856f3" dependencies = [ - "skrifa 0.31.1", + "skrifa", "yazi", "zeno", ] @@ -15635,60 +15641,48 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vello" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d5b0bafa35e0c2e4132104576d6bcec4bf7cd0044f1760e92ecae0d4d9bc0e7" +checksum = "df026e62e8b0d12d55ff5e91ae9114a20f82d9b856bedfdbf3abd5d1472dceed" dependencies = [ "bytemuck", "futures-intrusive", "log", - "peniko 0.3.2", + "peniko", "png", - "skrifa 0.26.6", + "skrifa", "static_assertions", "thiserror 2.0.12", "vello_encoding", "vello_shaders", - "wgpu 23.0.1", + "wgpu 24.0.5", ] [[package]] name = "vello_encoding" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbbdec68dea2b39ece9f82ab15ec4cf2c4f8600ce6926df0638290702d95b3f7" +checksum = "3c5702642f6ea77eedc12d119e1eebead0dba3cf91fe5c5d1f3efc12bf0cfaf1" dependencies = [ "bytemuck", "guillotiere", - "peniko 0.3.2", - "skrifa 0.26.6", + "peniko", + "skrifa", "smallvec", ] [[package]] name = "vello_shaders" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0179d74cf9131dfd7882323751d2544f3aefdfda9d16c39bbe2729799410d2" +checksum = "381790a3779021edd9f88267c1b13b49546cb0fb164f329ee2f2587869ddf459" dependencies = [ "bytemuck", - "naga 23.1.0", + "naga 24.0.0", "thiserror 2.0.12", "vello_encoding", ] -[[package]] -name = "vello_svg" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a0fd265f55b496a8048a43c769bf15487f2be9f6642086b3468c64677cc8c87" -dependencies = [ - "image", - "thiserror 2.0.12", - "usvg", - "vello", -] - [[package]] name = "version-compare" version = "0.2.0" @@ -16245,6 +16239,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" +dependencies = [ + "phf 0.11.3", + "phf_codegen 0.11.3", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "webbrowser" version = "1.0.4" @@ -16399,16 +16405,17 @@ dependencies = [ [[package]] name = "wgpu" -version = "23.0.1" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f70000db37c469ea9d67defdc13024ddf9a5f1b89cb2941b812ad7cde1735a" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" dependencies = [ "arrayvec", - "cfg_aliases 0.1.1", + "bitflags 2.9.1", + "cfg_aliases 0.2.1", "document-features", "js-sys", "log", - "naga 23.1.0", + "naga 24.0.0", "parking_lot", "profiling", "raw-window-handle 0.6.2", @@ -16417,9 +16424,9 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "wgpu-core 23.0.1", - "wgpu-hal 23.0.1", - "wgpu-types 23.0.0", + "wgpu-core 24.0.5", + "wgpu-hal 24.0.4", + "wgpu-types 24.0.0", ] [[package]] @@ -16450,27 +16457,27 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "23.0.1" +version = "24.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63c3c478de8e7e01786479919c8769f62a22eec16788d8c2ac77ce2c132778a" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" dependencies = [ "arrayvec", "bit-vec 0.8.0", "bitflags 2.9.1", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "document-features", "indexmap 2.9.0", "log", - "naga 23.1.0", + "naga 24.0.0", "once_cell", "parking_lot", "profiling", "raw-window-handle 0.6.2", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", - "wgpu-hal 23.0.1", - "wgpu-types 23.0.0", + "thiserror 2.0.12", + "wgpu-hal 24.0.4", + "wgpu-types 24.0.0", ] [[package]] @@ -16520,9 +16527,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "23.0.1" +version = "24.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89364b8a0b211adc7b16aeaf1bd5ad4a919c1154b44c9ce27838213ba05fd821" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" dependencies = [ "android_system_properties", "arrayvec", @@ -16531,9 +16538,9 @@ dependencies = [ "bitflags 2.9.1", "block", "bytemuck", - "cfg_aliases 0.1.1", + "cfg_aliases 0.2.1", "core-graphics-types 0.1.3", - "glow 0.14.2", + "glow 0.16.0", "glutin_wgl_sys 0.6.1", "gpu-alloc", "gpu-allocator 0.27.0", @@ -16543,11 +16550,12 @@ dependencies = [ "libc", "libloading 0.8.7", "log", - "metal 0.29.0", - "naga 23.1.0", + "metal 0.31.0", + "naga 24.0.0", "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", + "ordered-float 4.6.0", "parking_lot", "profiling", "range-alloc", @@ -16555,10 +16563,10 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror 1.0.69", + "thiserror 2.0.12", "wasm-bindgen", "web-sys", - "wgpu-types 23.0.0", + "wgpu-types 24.0.0", "windows 0.58.0", "windows-core 0.58.0", ] @@ -16576,12 +16584,13 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "23.0.0" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610f6ff27778148c31093f3b03abc4840f9636d58d597ca2f5977433acfe0068" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" dependencies = [ "bitflags 2.9.1", "js-sys", + "log", "web-sys", ] diff --git a/_typos.toml b/_typos.toml index 60852f0a8..bf85d1085 100644 --- a/_typos.toml +++ b/_typos.toml @@ -8,6 +8,8 @@ seeked = "seeked" # https://developer.apple.com/forums/thread/108953 # udid = unique device identifier udid = "udid" +# Part of Blitz's API +unparented = "unparented" [files] extend-exclude = ["translations/*", "CHANGELOG.md", "*.js"] diff --git a/packages/native/Cargo.toml b/packages/native/Cargo.toml index eefded90c..b25646377 100644 --- a/packages/native/Cargo.toml +++ b/packages/native/Cargo.toml @@ -11,27 +11,25 @@ keywords = ["dom", "ui", "gui", "react"] [features] -default = ["accessibility", "hot-reload", "menu", "tracing", "net", "svg"] -svg = ["blitz-dom/svg", "blitz-renderer-vello/svg"] +default = ["accessibility", "hot-reload", "menu", "tracing", "net", "svg", "system-fonts"] +svg = ["blitz-dom/svg", "blitz-paint/svg"] net = ["dep:tokio", "dep:blitz-net"] accessibility = ["blitz-shell/accessibility", "blitz-dom/accessibility"] menu = ["blitz-shell/menu"] tracing = ["dep:tracing", "blitz-shell/tracing", "blitz-dom/tracing"] hot-reload = ["dep:dioxus-cli-config", "dep:dioxus-devtools"] +system-fonts = ["blitz-dom/system_fonts"] autofocus = [] [dependencies] # Blitz dependencies -blitz-renderer-vello = { version = "0.1.0-alpha.1", default-features = false } -blitz-dom = { version = "0.1.0-alpha.1", default-features = false } -blitz-net = { version = "0.1.0-alpha.1", optional = true } -blitz-traits = { version = "0.1.0-alpha.1" } -blitz-shell = { version = "0.1.0-alpha.1", default-features = false } -# blitz-renderer-vello = { git = "https://github.com/dioxuslabs/blitz", rev="c1a7ecf06d1760a268e0046dc0e43f6c796ddc3c", default-features = false } -# blitz-dom = { git = "https://github.com/dioxuslabs/blitz", rev="c1a7ecf06d1760a268e0046dc0e43f6c796ddc3c", default-features = false } -# blitz-net = { git = "https://github.com/dioxuslabs/blitz", rev="c1a7ecf06d1760a268e0046dc0e43f6c796ddc3c", optional = true } -# blitz-traits = { git = "https://github.com/dioxuslabs/blitz", rev="c1a7ecf06d1760a268e0046dc0e43f6c796ddc3c" } -# blitz-shell = { git = "https://github.com/dioxuslabs/blitz", rev="c1a7ecf06d1760a268e0046dc0e43f6c796ddc3c", default-features = false } +anyrender = { version = "0.1", default-features = false } +anyrender_vello = { version = "0.1", default-features = false } +blitz-dom = { version = "0.1.0-alpha.2", default-features = false } +blitz-net = { version = "0.1.0-alpha.2", optional = true } +blitz-paint = { version = "0.1.0-alpha.2", optional = true } +blitz-traits = { version = "0.1.0-alpha.2" } +blitz-shell = { version = "0.1.0-alpha.2", default-features = false } # DioxusLabs dependencies dioxus-core = { workspace = true } diff --git a/packages/native/src/assets.rs b/packages/native/src/assets.rs index b887ca6b7..cde085662 100644 --- a/packages/native/src/assets.rs +++ b/packages/native/src/assets.rs @@ -1,24 +1,18 @@ use blitz_shell::BlitzShellNetCallback; use std::sync::Arc; -use blitz_dom::{ - net::{CssHandler, ImageHandler, Resource}, - util::ImageType, - BaseDocument, -}; +use blitz_dom::net::Resource; use blitz_shell::BlitzShellEvent; use blitz_traits::net::{NetCallback, NetProvider}; use winit::event_loop::EventLoopProxy; -use crate::NodeId; - pub struct DioxusNativeNetProvider { - callback: Arc + 'static>, - inner_net_provider: Arc + 'static>, + callback: Arc + 'static>, + inner_net_provider: Arc + 'static>, } impl DioxusNativeNetProvider { - pub fn shared(proxy: EventLoopProxy) -> Arc> { - Arc::new(Self::new(proxy)) as Arc> + pub fn shared(proxy: EventLoopProxy) -> Arc> { + Arc::new(Self::new(proxy)) as Arc> } pub fn new(proxy: EventLoopProxy) -> Self { @@ -31,14 +25,12 @@ impl DioxusNativeNetProvider { } } -impl NetProvider for DioxusNativeNetProvider { - type Data = Resource; - +impl NetProvider for DioxusNativeNetProvider { fn fetch( &self, doc_id: usize, request: blitz_traits::net::Request, - handler: blitz_traits::net::BoxedHandler, + handler: blitz_traits::net::BoxedHandler, ) { if request.url.scheme() == "dioxus" { match dioxus_asset_resolver::serve_asset_from_raw_path(request.url.path()) { @@ -55,26 +47,3 @@ impl NetProvider for DioxusNativeNetProvider { } } } - -pub fn fetch_linked_stylesheet(doc: &BaseDocument, node_id: NodeId, queued_url: String) { - let url = doc.resolve_url(&queued_url); - doc.net_provider.fetch( - doc.id(), - blitz_traits::net::Request::get(url.clone()), - Box::new(CssHandler { - node: node_id, - source_url: url, - guard: doc.guard.clone(), - provider: doc.net_provider.clone(), - }), - ); -} - -pub fn fetch_image(doc: &BaseDocument, node_id: usize, queued_image: String) { - let src = doc.resolve_url(&queued_image); - doc.net_provider.fetch( - doc.id(), - blitz_traits::net::Request::get(src), - Box::new(ImageHandler::new(node_id, ImageType::Image)), - ); -} diff --git a/packages/native/src/dioxus_application.rs b/packages/native/src/dioxus_application.rs index 3c65cc683..db80b8618 100644 --- a/packages/native/src/dioxus_application.rs +++ b/packages/native/src/dioxus_application.rs @@ -1,4 +1,4 @@ -use blitz_renderer_vello::BlitzVelloRenderer; +use anyrender_vello::VelloWindowRenderer; use blitz_shell::BlitzApplication; use dioxus_core::{ScopeId, VirtualDom}; use dioxus_history::{History, MemoryHistory}; @@ -10,13 +10,34 @@ use winit::window::WindowId; use crate::{ assets::DioxusNativeNetProvider, contexts::DioxusNativeDocument, - mutation_writer::MutationWriter, BlitzShellEvent, DioxusDocument, DioxusNativeEvent, - WindowConfig, + mutation_writer::MutationWriter, BlitzShellEvent, DioxusDocument, WindowConfig, }; +/// Dioxus-native specific event type +pub enum DioxusNativeEvent { + /// A hotreload event, basically telling us to update our templates. + #[cfg(all( + feature = "hot-reload", + debug_assertions, + not(target_os = "android"), + not(target_os = "ios") + ))] + DevserverEvent(dioxus_devtools::DevserverMsg), + + /// Create a new head element from the Link and Title elements + /// + /// todo(jon): these should probabkly be synchronous somehow + CreateHeadElement { + window: WindowId, + name: String, + attributes: Vec<(String, String)>, + contents: Option, + }, +} + pub struct DioxusNativeApplication { pending_vdom: Option, - inner: BlitzApplication, + inner: BlitzApplication, proxy: EventLoopProxy, } @@ -29,7 +50,7 @@ impl DioxusNativeApplication { } } - pub fn add_window(&mut self, window_config: WindowConfig) { + pub fn add_window(&mut self, window_config: WindowConfig) { self.inner.add_window(window_config); } @@ -48,7 +69,8 @@ impl DioxusNativeApplication { DioxusNativeEvent::DevserverEvent(event) => match event { dioxus_devtools::DevserverMsg::HotReload(hotreload_message) => { for window in self.inner.windows.values_mut() { - dioxus_devtools::apply_changes(&window.doc.vdom, hotreload_message); + let doc = window.downcast_doc_mut::(); + dioxus_devtools::apply_changes(&doc.vdom, hotreload_message); window.poll(); } } @@ -66,7 +88,8 @@ impl DioxusNativeApplication { window, } => { if let Some(window) = self.inner.windows.get_mut(window) { - window.doc.create_head_element(name, attributes, contents); + let doc = window.downcast_doc_mut::(); + doc.create_head_element(name, attributes, contents); window.poll(); } } @@ -103,7 +126,7 @@ impl ApplicationHandler for DioxusNativeApplication { // Create document + window from the baked virtualdom let doc = DioxusDocument::new(vdom, net_provider); - let window = WindowConfig::new(doc); + let window = WindowConfig::new(Box::new(doc) as _); // little hack since View::init is not public - fix this once alpha-2 is out let old_windows = self.inner.windows.keys().copied().collect::>(); @@ -114,7 +137,8 @@ impl ApplicationHandler for DioxusNativeApplication { // todo(jon): we should actually mess with the pending windows instead of passing along the contexts for window_id in new_windows.difference(&old_windows) { let window = self.inner.windows.get_mut(window_id).unwrap(); - window.doc.vdom.in_runtime(|| { + let doc = window.downcast_doc_mut::(); + doc.vdom.in_runtime(|| { let shared: Rc = Rc::new(DioxusNativeDocument::new(self.proxy.clone(), *window_id)); ScopeId::ROOT.provide_context(shared); @@ -122,14 +146,12 @@ impl ApplicationHandler for DioxusNativeApplication { // Add history let history_provider: Rc = Rc::new(MemoryHistory::default()); - window - .doc - .vdom + doc.vdom .in_runtime(|| ScopeId::ROOT.provide_context(history_provider)); // Queue rebuild - let mut writer = MutationWriter::new(&mut window.doc.inner, &mut window.doc.vdom_state); - window.doc.vdom.rebuild(&mut writer); + let mut writer = MutationWriter::new(&mut doc.inner, &mut doc.vdom_state); + doc.vdom.rebuild(&mut writer); drop(writer); // And then request redraw diff --git a/packages/native/src/dioxus_document.rs b/packages/native/src/dioxus_document.rs index 76ee1a4b8..37f35f63e 100644 --- a/packages/native/src/dioxus_document.rs +++ b/packages/native/src/dioxus_document.rs @@ -1,29 +1,36 @@ //! Integration between Dioxus and Blitz - +use blitz_dom::Attribute; +use futures_util::{pin_mut, FutureExt}; +use std::ops::{Deref, DerefMut}; use std::{any::Any, collections::HashMap, rc::Rc, sync::Arc}; use blitz_dom::{ - local_name, namespace_url, - net::Resource, - node::{Attribute, NodeSpecificData}, - ns, Atom, BaseDocument, ElementNodeData, Node, NodeData, QualName, DEFAULT_CSS, + net::Resource, BaseDocument, Document, EventDriver, EventHandler, Node, DEFAULT_CSS, +}; +use blitz_traits::{ + events::UiEvent, net::NetProvider, ColorScheme, DomEvent, DomEventData, EventState, Viewport, }; -use blitz_traits::{net::NetProvider, ColorScheme, Document, DomEvent, DomEventData, Viewport}; use dioxus_core::{ElementId, Event, VirtualDom}; -use dioxus_html::{set_event_converter, FormValue, PlatformEventData}; -use futures_util::{pin_mut, FutureExt}; +use dioxus_html::{set_event_converter, PlatformEventData}; -use super::event_handler::{BlitzKeyboardData, NativeClickData, NativeConverter, NativeFormData}; +use crate::events::{BlitzKeyboardData, NativeClickData, NativeConverter, NativeFormData}; use crate::mutation_writer::{DioxusState, MutationWriter}; +use crate::qual_name; use crate::NodeId; -pub(crate) fn qual_name(local_name: &str, namespace: Option<&str>) -> QualName { - QualName { - prefix: None, - ns: namespace.map(Atom::from).unwrap_or(ns!(html)), - local: Atom::from(local_name), - } +fn wrap_event_data(value: T) -> Rc { + Rc::new(PlatformEventData::new(Box::new(value))) +} + +/// Get the value of the "dioxus-data-id" attribute parsed aa usize +fn get_dioxus_id(node: &Node) -> Option { + node.element_data()? + .attrs + .iter() + .find(|attr| *attr.name.local == *"data-dioxus-id") + .and_then(|attr| attr.value.parse::().ok()) + .map(ElementId) } pub struct DioxusDocument { @@ -41,25 +48,106 @@ pub struct DioxusDocument { pub(crate) main_element_id: NodeId, } -// Implement DocumentLike and required traits for DioxusDocument +impl DioxusDocument { + pub fn new(vdom: VirtualDom, net_provider: Option>>) -> Self { + let viewport = Viewport::new(0, 0, 1.0, ColorScheme::Light); + let mut doc = BaseDocument::new(viewport); -impl AsRef for DioxusDocument { - fn as_ref(&self) -> &BaseDocument { - &self.inner + // Set net provider + if let Some(net_provider) = net_provider { + doc.set_net_provider(net_provider); + } + + // Create some minimal HTML to render the app into. + + // Create the html element + let mut mutr = doc.mutate(); + let html_element_id = mutr.create_element(qual_name("html", None), vec![]); + mutr.append_children(mutr.doc.root_node().id, &[html_element_id]); + + // Create the body element + let head_element_id = mutr.create_element(qual_name("head", None), vec![]); + mutr.append_children(html_element_id, &[head_element_id]); + + // Create the body element + let body_element_id = mutr.create_element(qual_name("body", None), vec![]); + mutr.append_children(html_element_id, &[body_element_id]); + + // Create another virtual element to hold the root
under the html element + let main_attr = blitz_dom::Attribute { + name: qual_name("id", None), + value: "main".to_string(), + }; + let main_element_id = mutr.create_element(qual_name("main", None), vec![main_attr]); + mutr.append_children(body_element_id, &[main_element_id]); + + drop(mutr); + + // Include default and user-specified stylesheets + doc.add_user_agent_stylesheet(DEFAULT_CSS); + + let vdom_state = DioxusState::create(main_element_id); + let mut doc = Self { + vdom, + vdom_state, + inner: doc, + html_element_id, + head_element_id, + body_element_id, + main_element_id, + }; + + doc.inner.set_base_url("dioxus://index.html"); + //doc.initial_build(); + doc.inner.print_tree(); + + doc } -} -impl AsMut for DioxusDocument { - fn as_mut(&mut self) -> &mut BaseDocument { - &mut self.inner + + pub fn initial_build(&mut self) { + let mut writer = MutationWriter::new(&mut self.inner, &mut self.vdom_state); + self.vdom.rebuild(&mut writer); } -} -impl From for BaseDocument { - fn from(doc: DioxusDocument) -> BaseDocument { - doc.inner + + pub fn create_head_element( + &mut self, + name: &str, + attributes: &[(String, String)], + contents: &Option, + ) { + let mut mutr = self.inner.mutate(); + + let attributes = attributes + .iter() + .map(|(name, value)| Attribute { + name: qual_name(name, None), + value: value.clone(), + }) + .collect(); + + let new_elem_id = mutr.create_element(qual_name(name, None), attributes); + mutr.append_children(self.head_element_id, &[new_elem_id]); + if let Some(contents) = contents { + mutr.append_text_to_node(new_elem_id, contents).unwrap(); + } + + // TODO: set title (we may also wish to have this built-in to the document?) + // if name == "title" { + // let title = mutr.doc.nodes[new_elem_id].text_content(); + // + // } } } + +// Implement DocumentLike and required traits for DioxusDocument impl Document for DioxusDocument { - type Doc = BaseDocument; + fn id(&self) -> usize { + self.inner.id() + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } fn poll(&mut self, mut cx: std::task::Context) -> bool { { @@ -78,487 +166,94 @@ impl Document for DioxusDocument { true } - fn id(&self) -> usize { - self.inner.id() - } - - fn handle_event(&mut self, event: &mut DomEvent) { - let chain = self.inner.node_chain(event.target); - + fn handle_event(&mut self, event: UiEvent) { set_event_converter(Box::new(NativeConverter {})); - - let renderer_event = event.clone(); - - let mut prevent_default = false; - let mut stop_propagation = false; - - match &event.data { - DomEventData::MouseMove(data) - | DomEventData::MouseDown(data) - | DomEventData::MouseUp(data) => { - let click_event_data = wrap_event_data(NativeClickData(data.clone())); - - for node_id in chain.clone().into_iter() { - let node = &self.inner.tree()[node_id]; - let dioxus_id = node.element_data().and_then(DioxusDocument::dioxus_id); - - if let Some(id) = dioxus_id { - let click_event = Event::new(click_event_data.clone(), true); - self.vdom - .runtime() - .handle_event(event.name(), click_event.clone(), id); - prevent_default |= !click_event.default_action_enabled(); - stop_propagation |= !click_event.propagates(); - } - - if !event.bubbles || stop_propagation { - break; - } - } - } - - DomEventData::Click(data) => { - let click_event_data = wrap_event_data(NativeClickData(data.clone())); - - for node_id in chain.clone().into_iter() { - let node = &self.inner.tree()[node_id]; - let dioxus_id = node.element_data().and_then(DioxusDocument::dioxus_id); - let mut trigger_label = false; - - if let Some(id) = dioxus_id { - // Trigger click event - let click_event = Event::new(click_event_data.clone(), true); - self.vdom - .runtime() - .handle_event("click", click_event.clone(), id); - prevent_default |= !click_event.default_action_enabled(); - stop_propagation |= !click_event.propagates(); - - if !prevent_default { - let mut default_event = - DomEvent::new(node_id, renderer_event.data.clone()); - self.inner.as_mut().handle_event(&mut default_event); - prevent_default = true; - - let element = self.inner.tree()[node_id].element_data().unwrap(); - trigger_label = element.name.local == *"label"; - - //TODO Check for other inputs which trigger input event on click here, eg radio - let triggers_input_event = element.name.local == local_name!("input") - && element.attr(local_name!("type")) == Some("checkbox"); - if triggers_input_event { - let form_data = - wrap_event_data(self.input_event_form_data(&chain, element)); - let input_event = Event::new(form_data, true); - self.vdom.runtime().handle_event("input", input_event, id); - } - } - } - - //Clicking labels triggers click, and possibly input event, of bound input - if trigger_label { - if let Some((dioxus_id, node_id)) = self.label_bound_input_element(node_id) - { - let click_event = Event::new(click_event_data.clone(), true); - self.vdom.runtime().handle_event( - "click", - click_event.clone(), - dioxus_id, - ); - - // Handle default DOM event - if click_event.default_action_enabled() { - let DomEventData::Click(event) = &renderer_event.data else { - unreachable!(); - }; - let input_click_data = self - .inner - .get_node(node_id) - .unwrap() - .synthetic_click_event(event.mods); - let mut default_event = DomEvent::new(node_id, input_click_data); - self.inner.as_mut().handle_event(&mut default_event); - prevent_default = true; - - // TODO: Generated click events should bubble separately - // prevent_default |= !click_event.default_action_enabled(); - - //TODO Check for other inputs which trigger input event on click here, eg radio - let element_data = self - .inner - .get_node(node_id) - .unwrap() - .element_data() - .unwrap(); - let triggers_input_event = - element_data.attr(local_name!("type")) == Some("checkbox"); - let form_data = wrap_event_data( - self.input_event_form_data(&chain, element_data), - ); - if triggers_input_event { - let input_event = Event::new(form_data, true); - self.vdom.runtime().handle_event( - "input", - input_event, - dioxus_id, - ); - } - } - } - } - - if !event.bubbles || stop_propagation { - break; - } - } - } - - DomEventData::KeyPress(kevent) => { - let key_event_data = wrap_event_data(BlitzKeyboardData(kevent.clone())); - - for node_id in chain.clone().into_iter() { - let node = &self.inner.tree()[node_id]; - let dioxus_id = node.element_data().and_then(DioxusDocument::dioxus_id); - println!("{} {:?}", node_id, dioxus_id); - - if let Some(id) = dioxus_id { - if kevent.state.is_pressed() { - // Handle keydown event - let event = Event::new(key_event_data.clone(), true); - self.vdom - .runtime() - .handle_event("keydown", event.clone(), id); - prevent_default |= !event.default_action_enabled(); - stop_propagation |= !event.propagates(); - - if !prevent_default && kevent.text.is_some() { - // Handle keypress event - let event = Event::new(key_event_data.clone(), true); - self.vdom - .runtime() - .handle_event("keypress", event.clone(), id); - prevent_default |= !event.default_action_enabled(); - stop_propagation |= !event.propagates(); - - if !prevent_default { - // Handle default DOM event - let mut default_event = - DomEvent::new(node_id, renderer_event.data.clone()); - self.inner.as_mut().handle_event(&mut default_event); - prevent_default = true; - - // Handle input event - let element = - self.inner.tree()[node_id].element_data().unwrap(); - let triggers_input_event = &element.name.local == "input" - && matches!( - element.attr(local_name!("type")), - None | Some("text" | "password" | "email" | "search") - ); - if triggers_input_event { - let form_data = wrap_event_data(dbg!( - self.input_event_form_data(&chain, element) - )); - let input_event = Event::new(form_data, true); - self.vdom.runtime().handle_event("input", input_event, id); - } - } - } - } else { - // Handle keyup event - let event = Event::new(key_event_data.clone(), true); - self.vdom.runtime().handle_event("keyup", event.clone(), id); - prevent_default |= !event.default_action_enabled(); - stop_propagation |= !event.propagates(); - } - } - - if !event.bubbles || stop_propagation { - break; - } - } - } - - DomEventData::Hover => {} - - // TODO: Implement IME and Hover events handling - DomEventData::Ime(_) => {} - } - - if !event.cancelable || !prevent_default { - self.inner.as_mut().handle_event(event); - } + let handler = DioxusEventHandler { + vdom: &mut self.vdom, + vdom_state: &mut self.vdom_state, + }; + let mut driver = EventDriver::new(self.inner.mutate(), handler); + driver.handle_ui_event(event); } } -fn wrap_event_data(value: T) -> Rc { - Rc::new(PlatformEventData::new(Box::new(value))) +impl Deref for DioxusDocument { + type Target = BaseDocument; + fn deref(&self) -> &BaseDocument { + &self.inner + } +} +impl DerefMut for DioxusDocument { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} +impl From for BaseDocument { + fn from(doc: DioxusDocument) -> BaseDocument { + doc.inner + } } -impl DioxusDocument { - /// Generate the FormData from an input event - /// Currently only cares about input checkboxes - pub fn input_event_form_data( - &self, - parent_chain: &[usize], - element_node_data: &ElementNodeData, - ) -> NativeFormData { - let parent_form = parent_chain.iter().find_map(|id| { - let node = self.inner.get_node(*id)?; - let element_data = node.element_data()?; - if element_data.name.local == local_name!("form") { - Some(node) - } else { - None - } - }); - let values = if let Some(parent_form) = parent_form { - let mut values = HashMap::::new(); - for form_input in self.input_descendents(parent_form).into_iter() { - // Match html behaviour here. To be included in values: - // - input must have a name - // - if its an input, we only include it if checked - // - if value is not specified, it defaults to 'on' - if let Some(name) = form_input.attr(local_name!("name")) { - if form_input.attr(local_name!("type")) == Some("checkbox") - && form_input - .element_data() - .and_then(|data| data.checkbox_input_checked()) - .unwrap_or(false) - { - let value = form_input - .attr(local_name!("value")) - .unwrap_or("on") - .to_string(); - values.insert(name.to_string(), FormValue(vec![value])); - } - } - } - values - } else { - Default::default() - }; - let value = match &element_node_data.node_specific_data { - NodeSpecificData::CheckboxInput(checked) => checked.to_string(), - NodeSpecificData::TextInput(input_data) => input_data.editor.text().to_string(), - _ => element_node_data - .attr(local_name!("value")) - .unwrap_or_default() - .to_string(), - }; +pub struct DioxusEventHandler<'v> { + vdom: &'v mut VirtualDom, + #[allow(dead_code, reason = "WIP")] + vdom_state: &'v mut DioxusState, +} - NativeFormData { value, values } - } - - /// Collect all the inputs which are descendents of a given node - fn input_descendents(&self, node: &Node) -> Vec<&Node> { - node.children - .iter() - .flat_map(|id| { - let mut res = Vec::<&Node>::new(); - let Some(n) = self.inner.get_node(*id) else { - return res; - }; - let Some(element_data) = n.element_data() else { - return res; - }; - if element_data.name.local == local_name!("input") { - res.push(n); - } - res.extend(self.input_descendents(n).iter()); - res - }) - .collect() - } - - pub fn new( - vdom: VirtualDom, - net_provider: Option>>, - ) -> Self { - let viewport = Viewport::new(0, 0, 1.0, ColorScheme::Light); - let mut doc = BaseDocument::new(viewport); - - // Set net provider - if let Some(net_provider) = net_provider { - doc.set_net_provider(net_provider); - } - - // Create a virtual "html" element to act as the root element, as we won't necessarily - // have a single root otherwise, while the rest of blitz requires that we do - let html_element_id = doc.create_node(NodeData::Element(ElementNodeData::new( - qual_name("html", None), - Vec::new(), - ))); - let root_node_id = doc.root_node().id; - let html_element = doc.get_node_mut(html_element_id).unwrap(); - html_element.parent = Some(root_node_id); - let root_node = doc.get_node_mut(root_node_id).unwrap(); - root_node.children.push(html_element_id); - - // Create the body element - let body_element_id = doc.create_node(NodeData::Element(ElementNodeData::new( - qual_name("body", None), - Vec::new(), - ))); - let html_element = doc.get_node_mut(html_element_id).unwrap(); - html_element.children.push(body_element_id); - let body_element = doc.get_node_mut(body_element_id).unwrap(); - body_element.parent = Some(html_element_id); - - // Create another virtual element to hold the root
under the html element - let main_element_id = doc.create_node(NodeData::Element(ElementNodeData::new( - qual_name("div", Some("id")), - vec![blitz_dom::node::Attribute { - name: qual_name("id", None), - value: "main".to_string(), - }], - ))); - let body_element = doc.get_node_mut(body_element_id).unwrap(); - body_element.children.push(main_element_id); - let main_element = doc.get_node_mut(main_element_id).unwrap(); - main_element.parent = Some(body_element_id); - - // Create the head element - let head_element_id = doc.create_node(NodeData::Element(ElementNodeData::new( - qual_name("head", None), - Vec::new(), - ))); - let head_element = doc.get_node_mut(head_element_id).unwrap(); - head_element.parent = Some(html_element_id); - let html_element = doc.get_node_mut(html_element_id).unwrap(); - html_element.children.push(head_element_id); - - // Include default and user-specified stylesheets - doc.add_user_agent_stylesheet(DEFAULT_CSS); - - let state = DioxusState::create(&mut doc, main_element_id); - let mut doc = Self { - vdom, - vdom_state: state, - inner: doc, - html_element_id, - head_element_id, - body_element_id, - main_element_id, - }; - - doc.inner.set_base_url("dioxus://index.html"); - - // doc.initial_build(); - - // doc.inner.print_tree(); - - doc - } - - pub fn initial_build(&mut self) { - // let mut writer = MutationWriter::new(&mut self.inner, &mut self.vdom_state); - - // self.vdom.rebuild(&mut writer); - // dbg!(self.vdom.rebuild_to_vec()); - // std::process::exit(0); - // dbg!(writer.state); - } - - pub fn label_bound_input_element(&self, label_node_id: NodeId) -> Option<(ElementId, NodeId)> { - let bound_input_elements = self.inner.label_bound_input_elements(label_node_id); - - // Filter down bound elements to those which have dioxus id - bound_input_elements.into_iter().find_map(|n| { - let target_element_data = n.element_data()?; - let node_id = n.id; - let dioxus_id = DioxusDocument::dioxus_id(target_element_data)?; - Some((dioxus_id, node_id)) - }) - } - - fn dioxus_id(element_node_data: &ElementNodeData) -> Option { - Some(ElementId( - element_node_data - .attrs - .iter() - .find(|attr| *attr.name.local == *"data-dioxus-id")? - .value - .parse::() - .ok()?, - )) - } - - pub fn create_head_element( +impl EventHandler for DioxusEventHandler<'_> { + fn handle_event( &mut self, - name: &str, - attributes: &[(String, String)], - contents: &Option, + chain: &[usize], + event: &mut DomEvent, + mutr: &mut blitz_dom::DocumentMutator<'_>, + event_state: &mut EventState, ) { - let mut stylesheet = None; - let mut title = None; - if name == "link" { - let is_stylesheet = attributes - .iter() - .any(|(name, value)| name == "rel" && value == "stylesheet"); - if is_stylesheet { - stylesheet = attributes - .iter() - .find(|(name, _value)| name == "href") - .map(|(_name, value)| value.clone()); + let event_data = match &event.data { + DomEventData::MouseMove(mevent) + | DomEventData::MouseDown(mevent) + | DomEventData::MouseUp(mevent) + | DomEventData::Click(mevent) => Some(wrap_event_data(NativeClickData(mevent.clone()))), + + DomEventData::KeyDown(kevent) + | DomEventData::KeyUp(kevent) + | DomEventData::KeyPress(kevent) => { + Some(wrap_event_data(BlitzKeyboardData(kevent.clone()))) + } + + DomEventData::Input(data) => Some(wrap_event_data(NativeFormData { + value: data.value.clone(), + values: HashMap::new(), + })), + + // TODO: Implement IME handling + DomEventData::Ime(_) => None, + }; + + let Some(event_data) = event_data else { + return; + }; + + for &node_id in chain { + // Get dioxus vdom id for node + let dioxus_id = mutr.doc.get_node(node_id).and_then(get_dioxus_id); + let Some(id) = dioxus_id else { + return; + }; + + // Handle event in vdom + let dx_event = Event::new(event_data.clone(), event.bubbles); + self.vdom + .runtime() + .handle_event(event.name(), dx_event.clone(), id); + + // Update event state + if !dx_event.default_action_enabled() { + event_state.prevent_default(); + } + if !dx_event.propagates() { + event_state.stop_propagation(); + break; } } - - if name == "title" { - title = attributes - .iter() - .find(|(name, _value)| name == "text") - .and_then(|(_name, _value)| contents.clone()); - } - - let attributes = attributes - .iter() - .map(|(name, value)| Attribute { - name: qual_name(name, None), - value: value.clone(), - }) - .collect(); - - let new_element = self - .inner - .create_node(NodeData::Element(ElementNodeData::new( - qual_name(name, None), - attributes, - ))); - - if let Some(contents) = contents { - let text_node = self.inner.create_text_node(contents); - self.inner - .get_node_mut(new_element) - .unwrap() - .children - .push(text_node); - } - - self.inner - .get_node_mut(self.head_element_id) - .unwrap() - .children - .push(new_element); - - if let Some(url) = stylesheet { - crate::assets::fetch_linked_stylesheet(&self.inner, new_element, url); - } - - if let Some(_title) = title { - println!("todo: set title"); - } } - - // pub fn apply_mutations(&mut self) { - // // Apply the mutations to the actual dom - // let mut writer = MutationWriter { - // doc: &mut self.inner, - // state: &mut self.vdom_state, - // }; - // self.vdom.render_immediate(&mut writer); - - // println!("APPLY MUTATIONS"); - // self.inner.print_tree(); - // } } diff --git a/packages/native/src/event.rs b/packages/native/src/event.rs deleted file mode 100644 index f8b10308b..000000000 --- a/packages/native/src/event.rs +++ /dev/null @@ -1,23 +0,0 @@ -use winit::window::WindowId; - -/// Dioxus-native specific event type -pub enum DioxusNativeEvent { - /// A hotreload event, basically telling us to update our templates. - #[cfg(all( - feature = "hot-reload", - debug_assertions, - not(target_os = "android"), - not(target_os = "ios") - ))] - DevserverEvent(dioxus_devtools::DevserverMsg), - - /// Create a new head element from the Link and Title elements - /// - /// todo(jon): these should probabkly be synchronous somehow - CreateHeadElement { - window: WindowId, - name: String, - attributes: Vec<(String, String)>, - contents: Option, - }, -} diff --git a/packages/native/src/event_handler.rs b/packages/native/src/events.rs similarity index 100% rename from packages/native/src/event_handler.rs rename to packages/native/src/events.rs diff --git a/packages/native/src/lib.rs b/packages/native/src/lib.rs index 29c3b3180..8fb4c1944 100644 --- a/packages/native/src/lib.rs +++ b/packages/native/src/lib.rs @@ -13,13 +13,12 @@ mod assets; mod contexts; mod dioxus_application; mod dioxus_document; -mod event; -mod event_handler; +mod events; mod mutation_writer; -pub use dioxus_application::DioxusNativeApplication; +use blitz_dom::{ns, Atom, QualName}; +pub use dioxus_application::{DioxusNativeApplication, DioxusNativeEvent}; pub use dioxus_document::DioxusDocument; -pub use event::DioxusNativeEvent; use blitz_shell::{create_default_event_loop, BlitzShellEvent, Config, WindowConfig}; use dioxus_core::{ComponentFunction, Element, VirtualDom}; @@ -68,7 +67,6 @@ pub fn launch_cfg_with_props( not(target_os = "ios") ))] { - use crate::event::DioxusNativeEvent; let proxy = event_loop.create_proxy(); dioxus_devtools::connect(move |event| { let dxn_event = DioxusNativeEvent::DevserverEvent(event); @@ -92,3 +90,36 @@ pub fn launch_cfg_with_props( // Run event loop event_loop.run_app(&mut application).unwrap(); } + +pub(crate) fn qual_name(local_name: &str, namespace: Option<&str>) -> QualName { + QualName { + prefix: None, + ns: namespace.map(Atom::from).unwrap_or(ns!(html)), + local: Atom::from(local_name), + } +} + +// Syntax sugar to make tracing calls less noisy in function below +macro_rules! trace { + ($pattern:literal) => {{ + #[cfg(feature = "tracing")] + tracing::info!($pattern); + }}; + ($pattern:literal, $item1:expr) => {{ + #[cfg(feature = "tracing")] + tracing::info!($pattern, $item1); + }}; + ($pattern:literal, $item1:expr, $item2:expr) => {{ + #[cfg(feature = "tracing")] + tracing::info!($pattern, $item1, $item2); + }}; + ($pattern:literal, $item1:expr, $item2:expr, $item3:expr) => {{ + #[cfg(feature = "tracing")] + tracing::info!($pattern, $item1, $item2); + }}; + ($pattern:literal, $item1:expr, $item2:expr, $item3:expr, $item4:expr) => {{ + #[cfg(feature = "tracing")] + tracing::info!($pattern, $item1, $item2, $item3, $item4); + }}; +} +pub(crate) use trace; diff --git a/packages/native/src/mutation_writer.rs b/packages/native/src/mutation_writer.rs index 03efa6faa..661039d18 100644 --- a/packages/native/src/mutation_writer.rs +++ b/packages/native/src/mutation_writer.rs @@ -1,14 +1,10 @@ -use crate::{dioxus_document::qual_name, NodeId}; -use blitz_dom::{ - local_name, namespace_url, - node::{Attribute, NodeSpecificData}, - ns, BaseDocument, ElementNodeData, NodeData, QualName, RestyleHint, -}; +//! Integration between Dioxus and Blitz +use crate::{qual_name, trace, NodeId}; +use blitz_dom::{Attribute, BaseDocument, DocumentMutator}; use dioxus_core::{ AttributeValue, ElementId, Template, TemplateAttribute, TemplateNode, WriteMutations, }; use rustc_hash::FxHashMap; -use std::collections::HashSet; /// The state of the Dioxus integration with the RealDom #[derive(Debug)] @@ -21,79 +17,13 @@ pub struct DioxusState { node_id_mapping: Vec>, } -/// A writer for mutations that can be used with the RealDom. -pub struct MutationWriter<'a> { - /// The realdom associated with this writer - pub doc: &'a mut BaseDocument, - - /// The state associated with this writer - pub state: &'a mut DioxusState, - - pub style_nodes: HashSet, - - /// The (latest) node which has been mounted in and had autofocus=true, if any - #[cfg(feature = "autofocus")] - pub node_to_autofocus: Option, -} - -impl<'a> MutationWriter<'a> { - pub fn new(doc: &'a mut BaseDocument, state: &'a mut DioxusState) -> Self { - MutationWriter { - doc, - state, - style_nodes: HashSet::new(), - - #[cfg(feature = "autofocus")] - node_to_autofocus: None, - } - } - - fn is_style_node(&self, node_id: NodeId) -> bool { - self.doc - .get_node(node_id) - .unwrap() - .data - .is_element_with_tag_name(&local_name!("style")) - } - - fn maybe_push_style_node(&mut self, node_id: impl Into>) { - if let Some(node_id) = node_id.into() { - if self.is_style_node(node_id) { - self.style_nodes.insert(node_id); - } - } - } - - #[track_caller] - fn maybe_push_parent_style_node(&mut self, node_id: NodeId) { - let parent_id = self.doc.get_node(node_id).unwrap().parent; - self.maybe_push_style_node(parent_id); - } -} - -impl Drop for MutationWriter<'_> { - fn drop(&mut self) { - // Add/Update inline stylesheets (