1
0
Эх сурвалжийг харах

bugfixes, testing and refactoring

Evan Almloff 3 жил өмнө
parent
commit
7f4e257757

+ 2541 - 0
.vscode/launch.json

@@ -0,0 +1,2541 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-core'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-core"
+                ],
+                "filter": {
+                    "name": "dioxus-core",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-rsx'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-rsx"
+                ],
+                "filter": {
+                    "name": "dioxus-rsx",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-html'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-html"
+                ],
+                "filter": {
+                    "name": "dioxus-html",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-hooks'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-hooks"
+                ],
+                "filter": {
+                    "name": "dioxus-hooks",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-web'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-web"
+                ],
+                "filter": {
+                    "name": "dioxus-web",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'hydrate'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=hydrate",
+                    "--package=dioxus-web"
+                ],
+                "filter": {
+                    "name": "hydrate",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'hydrate'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=hydrate",
+                    "--package=dioxus-web"
+                ],
+                "filter": {
+                    "name": "hydrate",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'hydrate'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=hydrate",
+                    "--package=dioxus-web"
+                ],
+                "filter": {
+                    "name": "hydrate",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-interpreter-js'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-interpreter-js"
+                ],
+                "filter": {
+                    "name": "dioxus-interpreter-js",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-ssr'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-ssr"
+                ],
+                "filter": {
+                    "name": "dioxus-ssr",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'renders'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=renders",
+                    "--package=dioxus-ssr"
+                ],
+                "filter": {
+                    "name": "renders",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-desktop'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-desktop"
+                ],
+                "filter": {
+                    "name": "dioxus-desktop",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-mobile'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-mobile"
+                ],
+                "filter": {
+                    "name": "dioxus-mobile",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'fermi'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=fermi"
+                ],
+                "filter": {
+                    "name": "fermi",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-tui'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-tui"
+                ],
+                "filter": {
+                    "name": "dioxus-tui",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'margin'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=margin",
+                    "--package=dioxus-tui"
+                ],
+                "filter": {
+                    "name": "margin",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-native-core'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-native-core"
+                ],
+                "filter": {
+                    "name": "dioxus-native-core",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "dioxus",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'all_css'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=all_css",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "all_css",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'all_css'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=all_css",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "all_css",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'borrowed'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=borrowed",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "borrowed",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'borrowed'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=borrowed",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "borrowed",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'calculator'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=calculator",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "calculator",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'calculator'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=calculator",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "calculator",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'crm'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=crm",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "crm",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'crm'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=crm",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "crm",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'custom_assets'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=custom_assets",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "custom_assets",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'custom_assets'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=custom_assets",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "custom_assets",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'disabled'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=disabled",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "disabled",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'disabled'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=disabled",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "disabled",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'dog_app'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=dog_app",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "dog_app",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'dog_app'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=dog_app",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "dog_app",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'error_handle'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=error_handle",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "error_handle",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'error_handle'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=error_handle",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "error_handle",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'fermi'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=fermi",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "fermi",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'fermi'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=fermi",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "fermi",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'filedragdrop'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=filedragdrop",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "filedragdrop",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'filedragdrop'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=filedragdrop",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "filedragdrop",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'file_explorer'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=file_explorer",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "file_explorer",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'file_explorer'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=file_explorer",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "file_explorer",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'flat_router'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=flat_router",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "flat_router",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'flat_router'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=flat_router",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "flat_router",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'form'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=form",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "form",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'form'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=form",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "form",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'framework_benchmark'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=framework_benchmark",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "framework_benchmark",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'framework_benchmark'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=framework_benchmark",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "framework_benchmark",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'heavy_compute'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=heavy_compute",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "heavy_compute",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'heavy_compute'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=heavy_compute",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "heavy_compute",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'hello_world'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=hello_world",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "hello_world",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'hello_world'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=hello_world",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "hello_world",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'hydration'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=hydration",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "hydration",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'hydration'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=hydration",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "hydration",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'inputs'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=inputs",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "inputs",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'inputs'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=inputs",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "inputs",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'link'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=link",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "link",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'link'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=link",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "link",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'login_form'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=login_form",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "login_form",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'login_form'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=login_form",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "login_form",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'nested_listeners'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=nested_listeners",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "nested_listeners",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'nested_listeners'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=nested_listeners",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "nested_listeners",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'optional_props'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=optional_props",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "optional_props",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'optional_props'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=optional_props",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "optional_props",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'pattern_model'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=pattern_model",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "pattern_model",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'pattern_model'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=pattern_model",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "pattern_model",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'pattern_reducer'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=pattern_reducer",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "pattern_reducer",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'pattern_reducer'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=pattern_reducer",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "pattern_reducer",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'readme'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=readme",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "readme",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'readme'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=readme",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "readme",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'router'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=router",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "router",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'router'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=router",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "router",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'rsx_compile_fail'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=rsx_compile_fail",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "rsx_compile_fail",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'rsx_compile_fail'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=rsx_compile_fail",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "rsx_compile_fail",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'rsx_usage'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=rsx_usage",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "rsx_usage",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'rsx_usage'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=rsx_usage",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "rsx_usage",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'ssr'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=ssr",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "ssr",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'ssr'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=ssr",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "ssr",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'suspense'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=suspense",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "suspense",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'suspense'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=suspense",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "suspense",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'svg'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=svg",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "svg",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'svg'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=svg",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "svg",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tailwind'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tailwind",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tailwind",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tailwind'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tailwind",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tailwind",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tasks'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tasks",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tasks",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tasks'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tasks",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tasks",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'textarea'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=textarea",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "textarea",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'textarea'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=textarea",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "textarea",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'todomvc'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=todomvc",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "todomvc",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'todomvc'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=todomvc",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "todomvc",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_border'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_border",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_border",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_border'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_border",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_border",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_color_test'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_color_test",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_color_test",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_color_test'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_color_test",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_color_test",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_components'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_components",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_components",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_components'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_components",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_components",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_frame'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_frame",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_frame",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_frame'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_frame",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_frame",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_hover'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_hover",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_hover",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_hover'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_hover",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_hover",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_keys'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_keys",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_keys",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_keys'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_keys",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_keys",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_list'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_list",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_list",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_list'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_list",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_list",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_margin'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_margin",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_margin",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_margin'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_margin",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_margin",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_quadrants'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_quadrants",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_quadrants",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_quadrants'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_quadrants",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_quadrants",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_readme'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_readme",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_readme",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_readme'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_readme",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_readme",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_task'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_task",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_task",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_task'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_task",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_task",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'tui_text'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=tui_text",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_text",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'tui_text'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=tui_text",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "tui_text",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'window_event'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=window_event",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "window_event",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'window_event'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=window_event",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "window_event",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'xss_safety'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=xss_safety",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "xss_safety",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'xss_safety'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=xss_safety",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "xss_safety",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'borrowedstate'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=borrowedstate",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "borrowedstate",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'create_dom'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=create_dom",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "create_dom",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'diffing'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=diffing",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "diffing",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'earlyabort'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=earlyabort",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "earlyabort",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'fermi'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=fermi",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "fermi",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'lifecycle'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=lifecycle",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "lifecycle",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'miri_stress'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=miri_stress",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "miri_stress",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'passthru'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=passthru",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "passthru",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'scheduler'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=scheduler",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "scheduler",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'sharedstate'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=sharedstate",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "sharedstate",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'task'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=task",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "task",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'test_logging'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=test_logging",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "test_logging",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'vdom_rebuild'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=vdom_rebuild",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "vdom_rebuild",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug benchmark 'create'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--bench=create",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "create",
+                    "kind": "bench"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug benchmark 'jsframework'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--bench=jsframework",
+                    "--package=dioxus"
+                ],
+                "filter": {
+                    "name": "jsframework",
+                    "kind": "bench"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in library 'dioxus-router'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--lib",
+                    "--package=dioxus-router"
+                ],
+                "filter": {
+                    "name": "dioxus-router",
+                    "kind": "lib"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug example 'simple'",
+            "cargo": {
+                "args": [
+                    "build",
+                    "--example=simple",
+                    "--package=dioxus-router"
+                ],
+                "filter": {
+                    "name": "simple",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug unit tests in example 'simple'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--example=simple",
+                    "--package=dioxus-router"
+                ],
+                "filter": {
+                    "name": "simple",
+                    "kind": "example"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'ssr_router'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=ssr_router",
+                    "--package=dioxus-router"
+                ],
+                "filter": {
+                    "name": "ssr_router",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        },
+        {
+            "type": "lldb",
+            "request": "launch",
+            "name": "Debug integration test 'web_router'",
+            "cargo": {
+                "args": [
+                    "test",
+                    "--no-run",
+                    "--test=web_router",
+                    "--package=dioxus-router"
+                ],
+                "filter": {
+                    "name": "web_router",
+                    "kind": "test"
+                }
+            },
+            "args": [],
+            "cwd": "${workspaceFolder}"
+        }
+    ]
+}

+ 7 - 49
examples/tui_color_test.rs

@@ -4,54 +4,11 @@ fn main() {
     dioxus::tui::launch_cfg(
         app,
         dioxus::tui::Config {
-            rendering_mode: dioxus::tui::RenderingMode::Rgb,
+            rendering_mode: dioxus::tui::RenderingMode::Ansi,
         },
     );
 }
 
-#[derive(Props, PartialEq)]
-struct BoxProps {
-    x: i32,
-    y: i32,
-    hue: f32,
-    alpha: f32,
-}
-fn Box(cx: Scope<BoxProps>) -> Element {
-    let painted = use_state(&cx, || true);
-
-    // use_future(&cx, (), move |_| {
-    //     let count = count.to_owned();
-    //     let update = cx.schedule_update();
-    //     async move {
-    //         loop {
-    //             count.with_mut(|i| *i += 1);
-    //             tokio::time::sleep(std::time::Duration::from_millis(800)).await;
-    //             update();
-    //         }
-    //     }
-    // });
-
-    let x = cx.props.x;
-    let y = cx.props.y;
-    let hue = cx.props.hue;
-    let current_painted = painted.get();
-    let alpha = cx.props.alpha + if *current_painted { 100.0 } else { 0.0 };
-
-    cx.render(rsx! {
-        div {
-            left: "{x}px",
-            top: "{y}px",
-            width: "100%",
-            height: "100%",
-            background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
-            align_items: "center",
-            onkeydown: |_| painted.with_mut(|i| *i = !*i),
-            onmouseenter: |_| painted.with_mut(|i| *i = !*i),
-            p{" "}
-        }
-    })
-}
-
 fn app(cx: Scope) -> Element {
     let steps = 50;
     cx.render(rsx! {
@@ -71,11 +28,12 @@ fn app(cx: Scope) -> Element {
                                 {
                                     let alpha = y as f32*100.0/steps as f32;
                                     cx.render(rsx! {
-                                        Box{
-                                            x: x,
-                                            y: y,
-                                            alpha: alpha,
-                                            hue: hue,
+                                        div {
+                                            left: "{x}px",
+                                            top: "{y}px",
+                                            width: "10%",
+                                            height: "100%",
+                                            background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
                                         }
                                     })
                                 }

+ 3 - 14
examples/tui_readme.rs

@@ -5,26 +5,15 @@ fn main() {
 }
 
 fn app(cx: Scope) -> Element {
-    let alpha = use_state(&cx, || 100);
-
     cx.render(rsx! {
         div {
-            onwheel: move |evt| alpha.set((**alpha + evt.data.delta_y as i64).min(100).max(0)),
-
             width: "100%",
             height: "10px",
             background_color: "red",
-            // justify_content: "center",
-            // align_items: "center",
+            justify_content: "center",
+            align_items: "center",
 
-            p{
-                color: "rgba(0, 255, 0, {alpha}%)",
-                "Hello world!"
-            }
-            p{
-                "{alpha}"
-            }
-            // p{"Hi"}
+            "Hello world!"
         }
     })
 }

+ 88 - 0
examples/tui_stress_test.rs

@@ -0,0 +1,88 @@
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus::tui::launch_cfg(
+        app,
+        dioxus::tui::Config {
+            rendering_mode: dioxus::tui::RenderingMode::Rgb,
+        },
+    );
+}
+
+#[derive(Props, PartialEq)]
+struct BoxProps {
+    x: i32,
+    y: i32,
+    hue: f32,
+    alpha: f32,
+}
+#[allow(non_snake_case)]
+fn Box(cx: Scope<BoxProps>) -> Element {
+    let count = use_state(&cx, || 0);
+
+    use_future(&cx, (), move |_| {
+        let count = count.to_owned();
+        let update = cx.schedule_update();
+        async move {
+            loop {
+                count.with_mut(|i| *i += 1);
+                tokio::time::sleep(std::time::Duration::from_millis(800)).await;
+                update();
+            }
+        }
+    });
+
+    let x = cx.props.x * 2;
+    let y = cx.props.y * 2;
+    let hue = cx.props.hue;
+    let count = count.get();
+    let alpha = cx.props.alpha + (count % 100) as f32;
+
+    cx.render(rsx! {
+        div {
+            left: "{x}%",
+            top: "{y}%",
+            width: "100%",
+            height: "100%",
+            background_color: "hsl({hue}, 100%, 50%, {alpha}%)",
+            align_items: "center",
+            p{"{count}"}
+        }
+    })
+}
+
+fn app(cx: Scope) -> Element {
+    let steps = 50;
+    cx.render(rsx! {
+        div{
+            width: "100%",
+            height: "100%",
+            flex_direction: "column",
+            (0..=steps).map(|x|
+                {
+                    let hue = x as f32*360.0/steps as f32;
+                    cx.render(rsx! {
+                        div{
+                            width: "100%",
+                            height: "100%",
+                            flex_direction: "row",
+                            (0..=steps).map(|y|
+                                {
+                                    let alpha = y as f32*100.0/steps as f32;
+                                    cx.render(rsx! {
+                                        Box{
+                                            x: x,
+                                            y: y,
+                                            alpha: alpha,
+                                            hue: hue,
+                                        }
+                                    })
+                                }
+                            )
+                        }
+                    })
+                }
+            )
+        }
+    })
+}

+ 1 - 1
examples/tui_text.rs

@@ -15,7 +15,7 @@ fn app(cx: Scope) -> Element {
             onwheel: move |evt| alpha.set((**alpha + evt.data.delta_y as i64).min(100).max(0)),
 
             p {
-                // background_color: "black",
+                background_color: "black",
                 flex_direction: "column",
                 justify_content: "center",
                 align_items: "center",

+ 1 - 0
packages/core/src/diff.rs

@@ -423,6 +423,7 @@ impl<'b> DiffState<'b> {
         match (old.children.len(), new.children.len()) {
             (0, 0) => {}
             (0, _) => {
+                self.mutations.push_root(root);
                 let created = self.create_children(new.children);
                 self.mutations.append_children(created as u32);
             }

+ 6 - 3
packages/native-core/Cargo.toml

@@ -3,8 +3,6 @@ name = "dioxus-native-core"
 version = "0.2.0"
 edition = "2021"
 license = "MIT/Apache-2.0"
-authors = ["@dementhos"]
-description = "TUI-based renderer for Dioxus"
 repository = "https://github.com/DioxusLabs/dioxus/"
 homepage = "https://dioxuslabs.com"
 
@@ -13,5 +11,10 @@ dioxus-core = { path = "../core", version = "^0.2.0" }
 dioxus-html = { path = "../html", version = "^0.2.0" }
 dioxus-core-macro = { path = "../core-macro", version = "^0.2.0" }
 
-stretch2 = "0.4.1"
+# stretch2 = "0.4.1"
+stretch2 = { git = "https://github.com/Demonthos/stretch.git" }
 smallvec = "1.6"
+fxhash = "0.2"
+
+[dev-dependencies]
+rand = "0.8.5"

+ 580 - 0
packages/native-core/src/client_tree.rs

@@ -0,0 +1,580 @@
+use fxhash::{FxHashMap, FxHashSet};
+use std::{
+    collections::VecDeque,
+    ops::{Index, IndexMut},
+};
+
+use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
+
+/// A tree that can sync with dioxus mutations backed by a hashmap.
+/// Intended for use in lazy native renderers with a state that passes from parrent to children and or accumulates state from children to parrents.
+/// To get started implement [PushedDownState] and or [BubbledUpState] and call [Tree::apply_mutations] and [Tree::update_state].
+#[derive(Debug)]
+pub struct ClientTree<US: BubbledUpState = (), DS: PushedDownState = ()> {
+    root: usize,
+    nodes: Vec<Option<TreeNode<US, DS>>>,
+    nodes_listening: FxHashMap<&'static str, FxHashSet<usize>>,
+    node_stack: smallvec::SmallVec<[usize; 10]>,
+}
+
+impl<US: BubbledUpState, DS: PushedDownState> ClientTree<US, DS> {
+    pub fn new() -> ClientTree<US, DS> {
+        ClientTree {
+            root: 0,
+            nodes: {
+                let mut v = Vec::new();
+                v.push(Some(TreeNode::new(
+                    0,
+                    TreeNodeType::Element {
+                        tag: "Root".to_string(),
+                        namespace: Some("Root"),
+                        children: Vec::new(),
+                    },
+                )));
+                v
+            },
+            nodes_listening: FxHashMap::default(),
+            node_stack: smallvec::SmallVec::new(),
+        }
+    }
+
+    /// Updates the tree, up and down state and return a set of nodes that were updated pass this to update_state.
+    pub fn apply_mutations(&mut self, mutations_vec: Vec<Mutations>) -> Vec<usize> {
+        let mut nodes_updated = Vec::new();
+        for mutations in mutations_vec {
+            for e in mutations.edits {
+                use dioxus_core::DomEdit::*;
+                match e {
+                    PushRoot { root } => self.node_stack.push(root as usize),
+                    AppendChildren { many } => {
+                        let target = if self.node_stack.len() >= many as usize + 1 {
+                            *self
+                                .node_stack
+                                .get(self.node_stack.len() - (many as usize + 1))
+                                .unwrap()
+                        } else {
+                            0
+                        };
+                        let drained: Vec<_> = self
+                            .node_stack
+                            .drain(self.node_stack.len() - many as usize..)
+                            .collect();
+                        for ns in drained {
+                            self.link_child(ns, target).unwrap();
+                            nodes_updated.push(ns);
+                        }
+                    }
+                    ReplaceWith { root, m } => {
+                        let root = self.remove(root as usize).unwrap();
+                        let target = root.parent.unwrap().0;
+                        let drained: Vec<_> = self.node_stack.drain(0..m as usize).collect();
+                        for ns in drained {
+                            nodes_updated.push(ns);
+                            self.link_child(ns, target).unwrap();
+                        }
+                    }
+                    InsertAfter { root, n } => {
+                        let target = self[root as usize].parent.unwrap().0;
+                        let drained: Vec<_> = self.node_stack.drain(0..n as usize).collect();
+                        for ns in drained {
+                            nodes_updated.push(ns);
+                            self.link_child(ns, target).unwrap();
+                        }
+                    }
+                    InsertBefore { root, n } => {
+                        let target = self[root as usize].parent.unwrap().0;
+                        let drained: Vec<_> = self.node_stack.drain(0..n as usize).collect();
+                        for ns in drained {
+                            nodes_updated.push(ns);
+                            self.link_child(ns, target).unwrap();
+                        }
+                    }
+                    Remove { root } => {
+                        if let Some(parent) = self[root as usize].parent {
+                            nodes_updated.push(parent.0);
+                        }
+                        self.remove(root as usize).unwrap();
+                    }
+                    CreateTextNode { root, text } => {
+                        let n = TreeNode::new(
+                            root,
+                            TreeNodeType::Text {
+                                text: text.to_string(),
+                            },
+                        );
+                        self.insert(n);
+                        self.node_stack.push(root as usize)
+                    }
+                    CreateElement { root, tag } => {
+                        let n = TreeNode::new(
+                            root,
+                            TreeNodeType::Element {
+                                tag: tag.to_string(),
+                                namespace: None,
+                                children: Vec::new(),
+                            },
+                        );
+                        self.insert(n);
+                        self.node_stack.push(root as usize)
+                    }
+                    CreateElementNs { root, tag, ns } => {
+                        let n = TreeNode::new(
+                            root,
+                            TreeNodeType::Element {
+                                tag: tag.to_string(),
+                                namespace: Some(ns),
+                                children: Vec::new(),
+                            },
+                        );
+                        self.insert(n);
+                        self.node_stack.push(root as usize)
+                    }
+                    CreatePlaceholder { root } => {
+                        let n = TreeNode::new(root, TreeNodeType::Placeholder);
+                        self.insert(n);
+                        self.node_stack.push(root as usize)
+                    }
+
+                    NewEventListener {
+                        event_name,
+                        scope: _,
+                        root,
+                    } => {
+                        if let Some(v) = self.nodes_listening.get_mut(event_name) {
+                            v.insert(root as usize);
+                        } else {
+                            let mut hs = FxHashSet::default();
+                            hs.insert(root as usize);
+                            self.nodes_listening.insert(event_name, hs);
+                        }
+                    }
+                    RemoveEventListener { root, event } => {
+                        let v = self.nodes_listening.get_mut(event).unwrap();
+                        v.remove(&(root as usize));
+                    }
+                    SetText {
+                        root,
+                        text: new_text,
+                    } => {
+                        let target = &mut self[root as usize];
+                        nodes_updated.push(root as usize);
+                        match &mut target.node_type {
+                            TreeNodeType::Text { text } => {
+                                *text = new_text.to_string();
+                            }
+                            _ => unreachable!(),
+                        }
+                    }
+                    SetAttribute { root, .. } => {
+                        nodes_updated.push(root as usize);
+                    }
+                    RemoveAttribute { root, .. } => {
+                        nodes_updated.push(root as usize);
+                    }
+                }
+            }
+        }
+
+        nodes_updated
+    }
+
+    /// Seperated from apply_mutations because Mutations require a mutable reference to the VirtualDom.
+    pub fn update_state(
+        &mut self,
+        vdom: &VirtualDom,
+        nodes_updated: Vec<usize>,
+        us_ctx: &mut US::Ctx,
+        ds_ctx: &mut DS::Ctx,
+    ) -> Option<FxHashSet<usize>> {
+        let mut to_rerender = FxHashSet::default();
+        let mut nodes_updated: Vec<_> = nodes_updated
+            .into_iter()
+            .map(|id| (id, self[id].height))
+            .collect();
+        // Sort nodes first by height, then if the height is the same id.
+        nodes_updated.sort_by(|fst, snd| fst.1.cmp(&snd.1).then(fst.0.cmp(&snd.0)));
+        nodes_updated.dedup();
+
+        // bubble up state. To avoid calling reduce more times than nessisary start from the bottom and go up.
+        let mut to_bubble: VecDeque<_> = nodes_updated.clone().into();
+        while let Some((id, height)) = to_bubble.pop_back() {
+            let node = &mut self[id as usize];
+            let vnode = node.element(vdom);
+            let node_type = &node.node_type;
+            let up_state = &mut node.up_state;
+            let children = match node_type {
+                TreeNodeType::Element { children, .. } => Some(children),
+                _ => None,
+            };
+            // todo: reduce cloning state
+            let old = up_state.clone();
+            let mut new = up_state.clone();
+            let parent = node.parent.clone();
+            new.reduce(
+                children
+                    .unwrap_or(&Vec::new())
+                    .clone()
+                    .iter()
+                    .map(|c| &self[*c].up_state),
+                vnode,
+                us_ctx,
+            );
+            if new != old {
+                to_rerender.insert(id);
+                if let Some(p) = parent {
+                    let i = to_bubble.partition_point(|(other_id, h)| {
+                        *h < height - 1 || (*h == height - 1 && *other_id < p.0)
+                    });
+                    // make sure the parent is not already queued
+                    if i >= to_bubble.len() || to_bubble[i].0 != p.0 {
+                        to_bubble.insert(i, (p.0, height - 1));
+                    }
+                }
+                let node = &mut self[id as usize];
+                node.up_state = new;
+            }
+        }
+
+        // push down state. To avoid calling reduce more times than nessisary start from the top and go down.
+        let mut to_push: VecDeque<_> = nodes_updated.clone().into();
+        while let Some((id, height)) = to_push.pop_front() {
+            let node = &self[id as usize];
+            // todo: reduce cloning state
+            let old = node.down_state.clone();
+            let mut new = node.down_state.clone();
+            let vnode = node.element(vdom);
+            new.reduce(
+                node.parent
+                    .filter(|e| e.0 != 0)
+                    .map(|e| &self[e].down_state),
+                vnode,
+                ds_ctx,
+            );
+            if new != old {
+                to_rerender.insert(id);
+                let node = &mut self[id as usize];
+                match &node.node_type {
+                    TreeNodeType::Element { children, .. } => {
+                        for c in children {
+                            let i = to_push.partition_point(|(other_id, h)| {
+                                *h < height + 1 || (*h == height + 1 && *other_id < c.0)
+                            });
+                            if i >= to_push.len() || to_push[i].0 != c.0 {
+                                to_push.insert(i, (c.0, height + 1));
+                            }
+                        }
+                    }
+                    _ => (),
+                };
+                node.down_state = new;
+            }
+        }
+
+        Some(to_rerender)
+    }
+
+    fn link_child(&mut self, child_id: usize, parent_id: usize) -> Option<()> {
+        debug_assert_ne!(child_id, parent_id);
+        let parent = &mut self[parent_id];
+        parent.add_child(ElementId(child_id));
+        let parent_height = parent.height + 1;
+        self[child_id].set_parent(ElementId(parent_id));
+        self.increase_height(child_id, parent_height);
+        Some(())
+    }
+
+    fn increase_height(&mut self, id: usize, amount: u16) {
+        let n = &mut self[id];
+        n.height += amount;
+        match &n.node_type {
+            TreeNodeType::Element { children, .. } => {
+                for c in children.clone() {
+                    self.increase_height(c.0, amount);
+                }
+            }
+            _ => (),
+        }
+    }
+
+    fn remove(&mut self, id: usize) -> Option<TreeNode<US, DS>> {
+        // We do not need to remove the node from the parent's children list for children.
+        fn inner<US: BubbledUpState, DS: PushedDownState>(
+            tree: &mut ClientTree<US, DS>,
+            id: usize,
+        ) -> Option<TreeNode<US, DS>> {
+            let mut node = tree.nodes[id as usize].take()?;
+            match &mut node.node_type {
+                TreeNodeType::Element { children, .. } => {
+                    for c in children {
+                        inner(tree, c.0)?;
+                    }
+                }
+                _ => (),
+            }
+            Some(node)
+        }
+        let mut node = self.nodes[id as usize].take()?;
+        if let Some(parent) = node.parent {
+            let parent = &mut self[parent];
+            parent.remove_child(ElementId(id));
+        }
+        match &mut node.node_type {
+            TreeNodeType::Element { children, .. } => {
+                for c in children {
+                    inner(self, c.0)?;
+                }
+            }
+            _ => (),
+        }
+        Some(node)
+    }
+
+    fn insert(&mut self, node: TreeNode<US, DS>) {
+        let current_len = self.nodes.len();
+        let id = node.id.0;
+        if current_len - 1 < node.id.0 {
+            // self.nodes.reserve(1 + id - current_len);
+            self.nodes.extend((0..1 + id - current_len).map(|_| None));
+        }
+        self.nodes[id] = Some(node);
+    }
+
+    pub fn get(&self, id: usize) -> Option<&TreeNode<US, DS>> {
+        self.nodes.get(id)?.as_ref()
+    }
+
+    pub fn get_mut(&mut self, id: usize) -> Option<&mut TreeNode<US, DS>> {
+        self.nodes.get_mut(id)?.as_mut()
+    }
+
+    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&TreeNode<US, DS>> {
+        if let Some(nodes) = self.nodes_listening.get(event) {
+            let mut listening: Vec<_> = nodes.iter().map(|id| &self[*id]).collect();
+            listening.sort_by(|n1, n2| (n1.height).cmp(&n2.height).reverse());
+            listening
+        } else {
+            Vec::new()
+        }
+    }
+
+    /// Check if the tree contains a node and its children.
+    pub fn contains_node(&self, node: &VNode) -> bool {
+        match node {
+            VNode::Component(_) => {
+                todo!()
+            }
+            VNode::Element(e) => {
+                if let Some(id) = e.id.get() {
+                    let tree_node = &self[id];
+                    match &tree_node.node_type {
+                        TreeNodeType::Element {
+                            tag,
+                            namespace,
+                            children,
+                        } => {
+                            tag == e.tag
+                                && namespace == &e.namespace
+                                && children.iter().copied().collect::<FxHashSet<_>>()
+                                    == e.children
+                                        .iter()
+                                        .map(|c| c.mounted_id())
+                                        .collect::<FxHashSet<_>>()
+                                && e.children.iter().all(|c| {
+                                    self.contains_node(c)
+                                        && self[c.mounted_id()].parent == e.id.get()
+                                })
+                        }
+                        _ => false,
+                    }
+                } else {
+                    true
+                }
+            }
+            VNode::Fragment(f) => f.children.iter().all(|c| self.contains_node(c)),
+            VNode::Placeholder(_) => true,
+            VNode::Text(t) => {
+                if let Some(id) = t.id.get() {
+                    let tree_node = &self[id];
+                    match &tree_node.node_type {
+                        TreeNodeType::Text { text } => t.text == text,
+                        _ => false,
+                    }
+                } else {
+                    true
+                }
+            }
+        }
+    }
+
+    /// Return the number of nodes in the tree.
+    pub fn size(&self) -> usize {
+        // The tree has a root node, ignore it.
+        self.nodes.iter().filter(|n| n.is_some()).count() - 1
+    }
+
+    /// Returns the id of the root node.
+    pub fn root_id(&self) -> usize {
+        self.root
+    }
+
+    /// Call a function for each node in the tree, depth first.
+    pub fn traverse(&self, mut f: impl FnMut(&TreeNode<US, DS>)) {
+        fn inner<US: BubbledUpState, DS: PushedDownState>(
+            tree: &ClientTree<US, DS>,
+            id: ElementId,
+            f: &mut impl FnMut(&TreeNode<US, DS>),
+        ) {
+            let node = &tree[id];
+            f(node);
+            match &node.node_type {
+                TreeNodeType::Element { children, .. } => {
+                    for c in children {
+                        inner(tree, *c, f);
+                    }
+                }
+                _ => (),
+            }
+        }
+        match &self[self.root].node_type {
+            TreeNodeType::Element { children, .. } => {
+                for c in children {
+                    inner(self, *c, &mut f);
+                }
+            }
+            _ => (),
+        }
+    }
+}
+
+impl<US: BubbledUpState, DS: PushedDownState> Index<usize> for ClientTree<US, DS> {
+    type Output = TreeNode<US, DS>;
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        self.get(idx).expect("Node does not exist")
+    }
+}
+
+impl<US: BubbledUpState, DS: PushedDownState> Index<ElementId> for ClientTree<US, DS> {
+    type Output = TreeNode<US, DS>;
+
+    fn index(&self, idx: ElementId) -> &Self::Output {
+        &self[idx.0]
+    }
+}
+
+impl<US: BubbledUpState, DS: PushedDownState> IndexMut<usize> for ClientTree<US, DS> {
+    fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
+        self.get_mut(idx).expect("Node does not exist")
+    }
+}
+impl<US: BubbledUpState, DS: PushedDownState> IndexMut<ElementId> for ClientTree<US, DS> {
+    fn index_mut(&mut self, idx: ElementId) -> &mut Self::Output {
+        &mut self[idx.0]
+    }
+}
+
+/// The node is stored client side and stores only basic data about the node. For more complete information about the node see [`TreeNode::element`].
+#[derive(Debug, Clone)]
+pub struct TreeNode<US: BubbledUpState, DS: PushedDownState> {
+    /// The id of the node this node was created from.
+    pub id: ElementId,
+    /// The parent id of the node.
+    pub parent: Option<ElementId>,
+    /// State of the node that is bubbled up to its parents. The state must depend only on the node and its children.
+    pub up_state: US,
+    /// State of the node that is pushed down to the children. The state must depend only on the node itself and its parent.
+    pub down_state: DS,
+    /// Additional inforation specific to the node type
+    pub node_type: TreeNodeType,
+    /// The number of parents before the root node. The root node has height 1.
+    pub height: u16,
+}
+
+#[derive(Debug, Clone)]
+pub enum TreeNodeType {
+    Text {
+        text: String,
+    },
+    Element {
+        tag: String,
+        namespace: Option<&'static str>,
+        children: Vec<ElementId>,
+    },
+    Placeholder,
+}
+
+impl<US: BubbledUpState, DS: PushedDownState> TreeNode<US, DS> {
+    fn new(id: u64, node_type: TreeNodeType) -> Self {
+        TreeNode {
+            id: ElementId(id as usize),
+            parent: None,
+            node_type,
+            down_state: DS::default(),
+            up_state: US::default(),
+            height: 0,
+        }
+    }
+
+    /// Returns a reference to the element that this node refrences.
+    pub fn element<'b>(&self, vdom: &'b VirtualDom) -> &'b VNode<'b> {
+        vdom.get_element(self.id).unwrap()
+    }
+
+    fn add_child(&mut self, child: ElementId) {
+        match &mut self.node_type {
+            TreeNodeType::Element { children, .. } => {
+                children.push(child);
+            }
+            _ => (),
+        }
+    }
+
+    fn remove_child(&mut self, child: ElementId) {
+        match &mut self.node_type {
+            TreeNodeType::Element { children, .. } => {
+                children.retain(|c| c != &child);
+            }
+            _ => (),
+        }
+    }
+
+    fn set_parent(&mut self, parent: ElementId) {
+        self.parent = Some(parent);
+    }
+}
+
+/// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children.
+/// Called when the current node's node properties are modified or a parrent's [PushedDownState] is modified.
+/// Called at most once per update.
+pub trait PushedDownState: Default + PartialEq + Clone {
+    /// The context is passed to the [PushedDownState::reduce] when it is pushed down.
+    /// This is sometimes nessisary for lifetime purposes.
+    type Ctx;
+    fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, ctx: &mut Self::Ctx);
+}
+impl PushedDownState for () {
+    type Ctx = ();
+    fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {}
+}
+
+/// This state is derived from children. For example a non-flexbox div's size could be derived from the size of children.
+/// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
+/// Called at most once per update.
+pub trait BubbledUpState: Default + PartialEq + Clone {
+    /// The context is passed to the [BubbledUpState::reduce] when it is bubbled up.
+    /// This is sometimes nessisary for lifetime purposes.
+    type Ctx;
+    fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, ctx: &mut Self::Ctx)
+    where
+        I: Iterator<Item = &'a Self>,
+        Self: 'a;
+}
+impl BubbledUpState for () {
+    type Ctx = ();
+    fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
+    where
+        I: Iterator<Item = &'a Self>,
+        Self: 'a,
+    {
+    }
+}

+ 2 - 3
packages/native-core/src/layout.rs

@@ -1,4 +1,4 @@
-use crate::BubbledUpState;
+use crate::client_tree::BubbledUpState;
 use dioxus_core::*;
 use stretch2::prelude::*;
 
@@ -58,7 +58,7 @@ impl BubbledUpState for StretchLayout {
                     apply_layout_attributes(name, value, &mut style);
                 }
 
-                // todo: move
+                // the root node fills the entire area
                 if el.id.get() == Some(ElementId(0)) {
                     apply_layout_attributes("width", "100%", &mut style);
                     apply_layout_attributes("height", "100%", &mut style);
@@ -69,7 +69,6 @@ impl BubbledUpState for StretchLayout {
                 for l in children {
                     child_layout.push(l.node.unwrap());
                 }
-                child_layout.reverse();
 
                 if let Some(n) = self.node {
                     if &stretch.children(n).unwrap() != &child_layout {

+ 1 - 525
packages/native-core/src/lib.rs

@@ -1,527 +1,3 @@
-use std::collections::{HashMap, HashSet, VecDeque};
-
-use dioxus_core::{ElementId, Mutations, VNode, VirtualDom};
+pub mod client_tree;
 pub mod layout;
 pub mod layout_attributes;
-
-/// A tree that can sync with dioxus mutations backed by a hashmap.
-/// Intended for use in lazy native renderers with a state that passes from parrent to children and or accumulates state from children to parrents.
-/// To get started implement [PushedDownState] and or [BubbledUpState] and call [Tree::apply_mutations] and [Tree::update_state].
-#[derive(Debug)]
-
-pub struct Tree<US: BubbledUpState = (), DS: PushedDownState = ()> {
-    pub root: usize,
-    pub nodes: Vec<Option<TreeNode<US, DS>>>,
-    pub nodes_listening: HashMap<&'static str, HashSet<usize>>,
-}
-
-impl<US: BubbledUpState, DS: PushedDownState> Tree<US, DS> {
-    pub fn new() -> Tree<US, DS> {
-        Tree {
-            root: 0,
-            nodes: {
-                let mut v = Vec::new();
-                v.push(Some(TreeNode::new(
-                    0,
-                    TreeNodeType::Element {
-                        tag: "Root".to_string(),
-                        namespace: Some("Root"),
-                        children: Vec::new(),
-                    },
-                )));
-                v
-            },
-            nodes_listening: HashMap::new(),
-        }
-    }
-
-    /// Updates the tree, up and down state and return a set of nodes that were updated
-    pub fn apply_mutations(&mut self, mutations_vec: Vec<Mutations>) -> Vec<usize> {
-        let mut nodes_updated = Vec::new();
-        for mutations in mutations_vec {
-            let mut node_stack: smallvec::SmallVec<[usize; 5]> = smallvec::SmallVec::new();
-            for e in mutations.edits {
-                use dioxus_core::DomEdit::*;
-                match e {
-                    PushRoot { root } => node_stack.push(root as usize),
-                    AppendChildren { many } => {
-                        let target = if node_stack.len() >= many as usize + 1 {
-                            *node_stack
-                                .get(node_stack.len() - (many as usize + 1))
-                                .unwrap()
-                        } else {
-                            0
-                        };
-                        for ns in node_stack.drain(node_stack.len() - many as usize..).rev() {
-                            self.link_child(ns, target).unwrap();
-                            nodes_updated.push(ns);
-                        }
-                    }
-                    ReplaceWith { root, m } => {
-                        let root = self.remove(root as usize).unwrap();
-                        let target = root.parent.unwrap().0;
-                        for ns in node_stack.drain(0..m as usize) {
-                            nodes_updated.push(ns);
-                            self.link_child(ns, target).unwrap();
-                        }
-                    }
-                    InsertAfter { root, n } => {
-                        let target = self.get(root as usize).parent.unwrap().0;
-                        for ns in node_stack.drain(0..n as usize) {
-                            nodes_updated.push(ns);
-                            self.link_child(ns, target).unwrap();
-                        }
-                    }
-                    InsertBefore { root, n } => {
-                        let target = self.get(root as usize).parent.unwrap().0;
-                        for ns in node_stack.drain(0..n as usize) {
-                            nodes_updated.push(ns);
-                            self.link_child(ns, target).unwrap();
-                        }
-                    }
-                    Remove { root } => {
-                        if let Some(parent) = self.get(root as usize).parent {
-                            nodes_updated.push(parent.0);
-                        }
-                        self.remove(root as usize).unwrap();
-                    }
-                    CreateTextNode { root, text } => {
-                        let n = TreeNode::new(
-                            root,
-                            TreeNodeType::Text {
-                                text: text.to_string(),
-                            },
-                        );
-                        self.insert(n);
-                        node_stack.push(root as usize)
-                    }
-                    CreateElement { root, tag } => {
-                        let n = TreeNode::new(
-                            root,
-                            TreeNodeType::Element {
-                                tag: tag.to_string(),
-                                namespace: None,
-                                children: Vec::new(),
-                            },
-                        );
-                        self.insert(n);
-                        node_stack.push(root as usize)
-                    }
-                    CreateElementNs { root, tag, ns } => {
-                        let n = TreeNode::new(
-                            root,
-                            TreeNodeType::Element {
-                                tag: tag.to_string(),
-                                namespace: Some(ns),
-                                children: Vec::new(),
-                            },
-                        );
-                        self.insert(n);
-                        node_stack.push(root as usize)
-                    }
-                    CreatePlaceholder { root } => {
-                        let n = TreeNode::new(root, TreeNodeType::Placeholder);
-                        self.insert(n);
-                        node_stack.push(root as usize)
-                    }
-
-                    NewEventListener {
-                        event_name,
-                        scope: _,
-                        root,
-                    } => {
-                        if let Some(v) = self.nodes_listening.get_mut(event_name) {
-                            v.insert(root as usize);
-                        } else {
-                            let mut hs = HashSet::new();
-                            hs.insert(root as usize);
-                            self.nodes_listening.insert(event_name, hs);
-                        }
-                    }
-                    RemoveEventListener { root, event } => {
-                        let v = self.nodes_listening.get_mut(event).unwrap();
-                        v.remove(&(root as usize));
-                    }
-                    SetText {
-                        root,
-                        text: new_text,
-                    } => {
-                        let target = self.get_mut(root as usize);
-                        nodes_updated.push(root as usize);
-                        match &mut target.node_type {
-                            TreeNodeType::Text { text } => {
-                                *text = new_text.to_string();
-                            }
-                            _ => unreachable!(),
-                        }
-                    }
-                    SetAttribute { root, .. } => {
-                        nodes_updated.push(root as usize);
-                    }
-                    RemoveAttribute { root, .. } => {
-                        nodes_updated.push(root as usize);
-                    }
-                }
-            }
-        }
-
-        nodes_updated
-    }
-
-    pub fn update_state(
-        &mut self,
-        vdom: &VirtualDom,
-        nodes_updated: Vec<usize>,
-        us_ctx: &mut US::Ctx,
-        ds_ctx: &mut DS::Ctx,
-    ) -> Option<HashSet<usize>> {
-        let mut to_rerender = HashSet::new();
-        let mut nodes_updated: Vec<_> = nodes_updated
-            .into_iter()
-            .map(|id| (id, self.get(id).height))
-            .collect();
-        nodes_updated.dedup();
-        nodes_updated.sort_by_key(|(_, h)| *h);
-
-        // bubble up state. To avoid calling reduce more times than nessisary start from the bottom and go up.
-        // todo: this is called multable times per element?
-        let mut to_bubble: VecDeque<_> = nodes_updated.clone().into();
-        while let Some((id, height)) = to_bubble.pop_back() {
-            let node = self.get_mut(id as usize);
-            let vnode = node.element(vdom);
-            let node_type = &node.node_type;
-            let up_state = &mut node.up_state;
-            let children = match node_type {
-                TreeNodeType::Element { children, .. } => Some(children),
-                _ => None,
-            };
-            // todo: reduce cloning state
-            let old = up_state.clone();
-            let mut new = up_state.clone();
-            let parent = node.parent.clone();
-            new.reduce(
-                children
-                    .unwrap_or(&Vec::new())
-                    .clone()
-                    .iter()
-                    .map(|c| &self.get(c.0).up_state),
-                vnode,
-                us_ctx,
-            );
-            if new != old {
-                to_rerender.insert(id);
-                if let Some(p) = parent {
-                    let i = to_bubble.partition_point(|(_, h)| *h < height - 1);
-                    // make sure the parent is not already queued
-                    if i >= to_bubble.len() || to_bubble.get(i).unwrap().0 != p.0 {
-                        to_bubble.insert(i, (p.0, height - 1));
-                    }
-                }
-                let node = self.get_mut(id as usize);
-                node.up_state = new;
-            }
-        }
-
-        // push down state. To avoid calling reduce more times than nessisary start from the top and go down.
-        let mut to_push: VecDeque<_> = nodes_updated.clone().into();
-        while let Some((id, height)) = to_push.pop_front() {
-            let node = self.get_mut(id as usize);
-            // todo: reduce cloning state
-            let old = node.down_state.clone();
-            let mut new = node.down_state.clone();
-            let vnode = node.element(vdom);
-            new.reduce(
-                node.parent.map(|e| &self.get(e.0).down_state),
-                vnode,
-                ds_ctx,
-            );
-            if new != old {
-                to_rerender.insert(id);
-                let node = self.get_mut(id as usize);
-                match &node.node_type {
-                    TreeNodeType::Element { children, .. } => {
-                        for c in children {
-                            let i = to_bubble.partition_point(|(_, h)| *h < height + 1);
-                            to_bubble.insert(i, (c.0, height + 1));
-                        }
-                    }
-                    _ => (),
-                };
-                node.down_state = new;
-            }
-        }
-
-        Some(to_rerender)
-    }
-
-    fn link_child(&mut self, child_id: usize, parent_id: usize) -> Option<()> {
-        debug_assert_ne!(child_id, parent_id);
-        let parent = self.get_mut(parent_id);
-        parent.add_child(ElementId(child_id));
-        let parent_height = parent.height + 1;
-        self.get_mut(child_id).set_parent(ElementId(parent_id));
-        self.increase_height(child_id, parent_height);
-        Some(())
-    }
-
-    fn increase_height(&mut self, id: usize, amount: u16) {
-        let n = self.get_mut(id);
-        n.height += amount;
-        match &n.node_type {
-            TreeNodeType::Element { children, .. } => {
-                for c in children.clone() {
-                    self.increase_height(c.0, amount);
-                }
-            }
-            _ => (),
-        }
-    }
-
-    fn remove(&mut self, id: usize) -> Option<TreeNode<US, DS>> {
-        let mut node = self.nodes.get_mut(id as usize).unwrap().take().unwrap();
-        match &mut node.node_type {
-            TreeNodeType::Element { children, .. } => {
-                for c in children {
-                    self.remove(c.0).unwrap();
-                }
-            }
-            _ => (),
-        }
-        Some(node)
-    }
-
-    fn insert(&mut self, node: TreeNode<US, DS>) {
-        let current_len = self.nodes.len();
-        let id = node.id.0;
-        if current_len - 1 < node.id.0 {
-            // self.nodes.reserve(1 + id - current_len);
-            self.nodes.extend((0..1 + id - current_len).map(|_| None));
-        }
-        self.nodes[id] = Some(node);
-    }
-
-    pub fn get(&self, id: usize) -> &TreeNode<US, DS> {
-        self.nodes.get(id).unwrap().as_ref().unwrap()
-    }
-
-    fn get_mut(&mut self, id: usize) -> &mut TreeNode<US, DS> {
-        self.nodes.get_mut(id).unwrap().as_mut().unwrap()
-    }
-
-    pub fn get_listening_sorted(&self, event: &'static str) -> Vec<&TreeNode<US, DS>> {
-        if let Some(nodes) = self.nodes_listening.get(event) {
-            let mut listening: Vec<_> = nodes.iter().map(|id| self.get(*id)).collect();
-            listening.sort_by(|n1, n2| (n1.height).cmp(&n2.height).reverse());
-            listening
-        } else {
-            Vec::new()
-        }
-    }
-}
-
-/// The node is stored client side and stores render data
-#[derive(Debug, Clone)]
-pub struct TreeNode<US: BubbledUpState, DS: PushedDownState> {
-    pub id: ElementId,
-    pub parent: Option<ElementId>,
-    pub up_state: US,
-    pub down_state: DS,
-    pub node_type: TreeNodeType,
-    pub height: u16,
-}
-
-#[derive(Debug, Clone)]
-pub enum TreeNodeType {
-    Text {
-        text: String,
-    },
-    Element {
-        tag: String,
-        namespace: Option<&'static str>,
-        children: Vec<ElementId>,
-    },
-    Placeholder,
-}
-
-impl<US: BubbledUpState, DS: PushedDownState> TreeNode<US, DS> {
-    fn new(id: u64, node_type: TreeNodeType) -> Self {
-        TreeNode {
-            id: ElementId(id as usize),
-            parent: None,
-            node_type,
-            down_state: DS::default(),
-            up_state: US::default(),
-            height: 0,
-        }
-    }
-
-    fn element<'b>(&self, vdom: &'b VirtualDom) -> &'b VNode<'b> {
-        vdom.get_element(self.id).unwrap()
-    }
-
-    fn add_child(&mut self, child: ElementId) {
-        match &mut self.node_type {
-            TreeNodeType::Element { children, .. } => {
-                children.push(child);
-            }
-            _ => (),
-        }
-    }
-
-    fn set_parent(&mut self, parent: ElementId) {
-        self.parent = Some(parent);
-    }
-}
-
-/// This state that is passed down to children. For example text properties (`<b>` `<i>` `<u>`) would be passed to children.
-/// Called when the current node's node properties are modified or a parrent's [PushedDownState] is modified.
-/// Called at most once per update.
-pub trait PushedDownState: Default + PartialEq + Clone {
-    type Ctx;
-    fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, ctx: &mut Self::Ctx);
-}
-impl PushedDownState for () {
-    type Ctx = ();
-    fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {}
-}
-
-/// This state is derived from children. For example a non-flexbox div's size could be derived from the size of children.
-/// Called when the current node's node properties are modified, a child's [BubbledUpState] is modified or a child is removed.
-/// Called at most once per update.
-pub trait BubbledUpState: Default + PartialEq + Clone {
-    type Ctx;
-    fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, ctx: &mut Self::Ctx)
-    where
-        I: Iterator<Item = &'a Self>,
-        Self: 'a;
-}
-impl BubbledUpState for () {
-    type Ctx = ();
-    fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
-    where
-        I: Iterator<Item = &'a Self>,
-        Self: 'a,
-    {
-    }
-}
-
-// /// The nodes that need to be updated after updating a state.
-// pub struct Update {
-//     children: bool,
-//     parent: bool,
-// }
-
-// /// This state is derived from children and parents.
-// /// Called when the current node's node properties are modified or a parent or child's [State] is modified.
-// /// Unlike [BubbledUpState] and [PushedDownState] this may be called mulable times per update. Prefer those over this.
-// pub trait State: Default + PartialEq + Clone {
-//     fn reduce<'a, I>(&mut self, parent: Option<&Self>, children: I, vnode: &VNode) -> Update
-//     where
-//         I: Iterator<Item = &'a Self>,
-//         Self: 'a;
-// }
-// impl State for () {
-//     fn reduce<'a, I>(&mut self, _parent: Option<&Self>, _children: I, _vnode: &VNode) -> Update
-//     where
-//         I: Iterator<Item = &'a Self>,
-//         Self: 'a,
-//     {
-//         Update {
-//             children: false,
-//             parent: false,
-//         }
-//     }
-// }
-
-#[test]
-fn test_insert() {
-    use dioxus_core::*;
-    use dioxus_core_macro::*;
-    use dioxus_html as dioxus_elements;
-
-    #[derive(Debug, Default, PartialEq, Clone)]
-    struct Rect {
-        x: u16,
-        y: u16,
-        width: u16,
-        height: u16,
-    }
-
-    impl BubbledUpState for Rect {
-        type Ctx = ();
-
-        fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, _ctx: &mut Self::Ctx)
-        where
-            I: Iterator<Item = &'a Self>,
-            Self: 'a,
-        {
-            match vnode {
-                VNode::Text(t) => {
-                    *self = Rect {
-                        x: 0,
-                        y: 0,
-                        width: t.text.len().try_into().unwrap(),
-                        height: 1,
-                    };
-                    return;
-                }
-                _ => (),
-            }
-            self.width = 2;
-            self.height = 2;
-            for c in children {
-                println!("\t{c:?}");
-                self.width = self.width.max(c.width);
-                self.height += c.height;
-            }
-        }
-    }
-
-    #[allow(non_snake_case)]
-    fn Base(cx: Scope) -> Element {
-        rsx!(cx, div {})
-    }
-
-    let vdom = VirtualDom::new(Base);
-    let node_1 = rsx! {
-        div{
-            div{
-                "hello"
-                "hello world"
-            }
-        }
-    };
-    let node_2 = rsx! {
-        div{
-            div{
-                "hello"
-                "hello world"
-            }
-        }
-    };
-    let mutations = vdom.diff_lazynodes(node_1, node_2);
-
-    let mut tree: Tree<Rect, ()> = Tree {
-        root: 0,
-        nodes: {
-            let mut v = Vec::new();
-            v.push(Some(TreeNode::new(
-                0,
-                TreeNodeType::Element {
-                    tag: "Root".to_string(),
-                    namespace: Some("Root"),
-                    children: Vec::new(),
-                },
-            )));
-            v
-        },
-        nodes_listening: HashMap::new(),
-    };
-    println!("{:?}", mutations);
-    let to_update = tree.apply_mutations(vec![mutations.0]);
-    let to_rerender = tree
-        .update_state(&vdom, to_update, &mut (), &mut ())
-        .unwrap();
-    println!("{to_rerender:?}");
-    panic!("{}", format!("{:?}", &tree.nodes[1..]).replace("\\", ""));
-}

+ 153 - 0
packages/native-core/tests/change_nodes.rs

@@ -0,0 +1,153 @@
+use dioxus_core::VNode;
+use dioxus_core::*;
+use dioxus_core_macro::*;
+use dioxus_html as dioxus_elements;
+use dioxus_native_core::client_tree::ClientTree;
+use std::cell::Cell;
+
+#[test]
+fn tree_remove_node() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {})
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div{
+            div{}
+        }
+    });
+
+    let mut tree: ClientTree<(), ()> = ClientTree::new();
+
+    let _to_update = tree.apply_mutations(vec![mutations]);
+    let child_div = VElement {
+        id: Cell::new(Some(ElementId(2))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(1))),
+        listeners: &[],
+        attributes: &[],
+        children: &[],
+    };
+    let child_div_el = VNode::Element(&child_div);
+    let root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[child_div_el],
+    };
+
+    assert_eq!(tree.size(), 2);
+    assert!(&tree.contains_node(&VNode::Element(&root_div)));
+    assert_eq!(tree[1].height, 1);
+    assert_eq!(tree[2].height, 2);
+
+    let vdom = VirtualDom::new(Base);
+    let mutations = vdom.diff_lazynodes(
+        rsx! {
+            div{
+                div{}
+            }
+        },
+        rsx! {
+            div{}
+        },
+    );
+    tree.apply_mutations(vec![mutations.1]);
+
+    let new_root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[],
+    };
+
+    assert_eq!(tree.size(), 1);
+    assert!(&tree.contains_node(&VNode::Element(&new_root_div)));
+    assert_eq!(tree[1].height, 1);
+}
+
+#[test]
+fn tree_add_node() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {})
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div{}
+    });
+
+    let mut tree: ClientTree<(), ()> = ClientTree::new();
+
+    let _to_update = tree.apply_mutations(vec![mutations]);
+
+    let root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[],
+    };
+
+    assert_eq!(tree.size(), 1);
+    assert!(&tree.contains_node(&VNode::Element(&root_div)));
+    assert_eq!(tree[1].height, 1);
+
+    let vdom = VirtualDom::new(Base);
+    let mutations = vdom.diff_lazynodes(
+        rsx! {
+            div{}
+        },
+        rsx! {
+            div{
+                p{}
+            }
+        },
+    );
+    tree.apply_mutations(vec![mutations.1]);
+
+    let child_div = VElement {
+        id: Cell::new(Some(ElementId(2))),
+        key: None,
+        tag: "p",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(1))),
+        listeners: &[],
+        attributes: &[],
+        children: &[],
+    };
+    let child_div_el = VNode::Element(&child_div);
+    let new_root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[child_div_el],
+    };
+
+    assert_eq!(tree.size(), 2);
+    assert!(&tree.contains_node(&VNode::Element(&new_root_div)));
+    assert_eq!(tree[1].height, 1);
+    assert_eq!(tree[2].height, 2);
+}

+ 124 - 0
packages/native-core/tests/initial_build.rs

@@ -0,0 +1,124 @@
+use std::cell::Cell;
+
+use dioxus_core::VNode;
+use dioxus_core::*;
+use dioxus_core_macro::*;
+use dioxus_html as dioxus_elements;
+use dioxus_native_core::client_tree::ClientTree;
+
+#[test]
+fn tree_initial_build_simple() {
+    use std::cell::Cell;
+
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {})
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div{}
+    });
+
+    let mut tree: ClientTree<(), ()> = ClientTree::new();
+
+    let _to_update = tree.apply_mutations(vec![mutations]);
+    let root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[],
+    };
+    assert_eq!(tree.size(), 1);
+    assert!(&tree.contains_node(&VNode::Element(&root_div)));
+    assert_eq!(tree[1].height, 1);
+}
+
+#[test]
+fn tree_initial_build_with_children() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {})
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div{
+            div{
+                "hello"
+                p{
+                    "world"
+                }
+                "hello world"
+            }
+        }
+    });
+
+    let mut tree: ClientTree<(), ()> = ClientTree::new();
+
+    let _to_update = tree.apply_mutations(vec![mutations]);
+    let first_text = VText {
+        id: Cell::new(Some(ElementId(3))),
+        text: "hello",
+        is_static: true,
+    };
+    let first_text_node = VNode::Text(&first_text);
+    let child_text = VText {
+        id: Cell::new(Some(ElementId(5))),
+        text: "world",
+        is_static: true,
+    };
+    let child_text_node = VNode::Text(&child_text);
+    let child_p_el = VElement {
+        id: Cell::new(Some(ElementId(4))),
+        key: None,
+        tag: "p",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(2))),
+        listeners: &[],
+        attributes: &[],
+        children: &[child_text_node],
+    };
+    let child_p_node = VNode::Element(&child_p_el);
+    let second_text = VText {
+        id: Cell::new(Some(ElementId(6))),
+        text: "hello world",
+        is_static: true,
+    };
+    let second_text_node = VNode::Text(&second_text);
+    let child_div_el = VElement {
+        id: Cell::new(Some(ElementId(2))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(1))),
+        listeners: &[],
+        attributes: &[],
+        children: &[first_text_node, child_p_node, second_text_node],
+    };
+    let child_div_node = VNode::Element(&child_div_el);
+    let root_div = VElement {
+        id: Cell::new(Some(ElementId(1))),
+        key: None,
+        tag: "div",
+        namespace: None,
+        parent: Cell::new(Some(ElementId(0))),
+        listeners: &[],
+        attributes: &[],
+        children: &[child_div_node],
+    };
+    assert_eq!(tree.size(), 6);
+    assert!(&tree.contains_node(&VNode::Element(&root_div)));
+    assert_eq!(tree[1].height, 1);
+    assert_eq!(tree[2].height, 2);
+    assert_eq!(tree[3].height, 3);
+    assert_eq!(tree[4].height, 3);
+    assert_eq!(tree[5].height, 4);
+    assert_eq!(tree[6].height, 3);
+}

+ 320 - 0
packages/native-core/tests/state.rs

@@ -0,0 +1,320 @@
+use dioxus_core::VNode;
+use dioxus_core::*;
+use dioxus_core_macro::*;
+use dioxus_html as dioxus_elements;
+use dioxus_native_core::client_tree::*;
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct CallCounter(u32);
+impl BubbledUpState for CallCounter {
+    type Ctx = ();
+
+    fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
+    where
+        I: Iterator<Item = &'a Self>,
+        Self: 'a,
+    {
+        self.0 += 1;
+    }
+}
+
+impl PushedDownState for CallCounter {
+    type Ctx = ();
+
+    fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {
+        self.0 += 1;
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct BubbledUpStateTester(String, Vec<Box<BubbledUpStateTester>>);
+impl BubbledUpState for BubbledUpStateTester {
+    type Ctx = u32;
+
+    fn reduce<'a, I>(&mut self, children: I, vnode: &VNode, ctx: &mut Self::Ctx)
+    where
+        I: Iterator<Item = &'a Self>,
+        Self: 'a,
+    {
+        assert_eq!(*ctx, 42);
+        *self = BubbledUpStateTester(
+            vnode.mounted_id().to_string(),
+            children.map(|c| Box::new(c.clone())).collect(),
+        );
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Default)]
+struct PushedDownStateTester(String, Option<Box<PushedDownStateTester>>);
+impl PushedDownState for PushedDownStateTester {
+    type Ctx = u32;
+
+    fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, ctx: &mut Self::Ctx) {
+        assert_eq!(*ctx, 42);
+        *self = PushedDownStateTester(
+            vnode.mounted_id().to_string(),
+            parent.map(|c| Box::new(c.clone())),
+        );
+    }
+}
+
+#[test]
+fn tree_state_initial() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {
+            p{}
+            h1{}
+        })
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div {
+            p{}
+            h1{}
+        }
+    });
+
+    let mut tree: ClientTree<BubbledUpStateTester, PushedDownStateTester> = ClientTree::new();
+
+    let nodes_updated = tree.apply_mutations(vec![mutations]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut 42, &mut 42);
+
+    let root_div = &tree[1];
+    assert_eq!(root_div.up_state.0, "1");
+    assert_eq!(
+        root_div.up_state.1,
+        vec![
+            Box::new(BubbledUpStateTester("2".to_string(), Vec::new())),
+            Box::new(BubbledUpStateTester("3".to_string(), Vec::new()))
+        ]
+    );
+    assert_eq!(root_div.down_state.0, "1");
+    assert_eq!(root_div.down_state.1, None);
+
+    let child_p = &tree[2];
+    assert_eq!(child_p.up_state.0, "2");
+    assert_eq!(child_p.up_state.1, Vec::new());
+    assert_eq!(child_p.down_state.0, "2");
+    assert_eq!(
+        child_p.down_state.1,
+        Some(Box::new(PushedDownStateTester("1".to_string(), None)))
+    );
+
+    let child_h1 = &tree[3];
+    assert_eq!(child_h1.up_state.0, "3");
+    assert_eq!(child_h1.up_state.1, Vec::new());
+    assert_eq!(child_h1.down_state.0, "3");
+    assert_eq!(
+        child_h1.down_state.1,
+        Some(Box::new(PushedDownStateTester("1".to_string(), None)))
+    );
+}
+
+#[test]
+fn tree_state_reduce_initally_called_minimally() {
+    #[derive(Debug, Clone, PartialEq, Default)]
+    struct CallCounter(u32);
+    impl BubbledUpState for CallCounter {
+        type Ctx = ();
+
+        fn reduce<'a, I>(&mut self, _children: I, _vnode: &VNode, _ctx: &mut Self::Ctx)
+        where
+            I: Iterator<Item = &'a Self>,
+            Self: 'a,
+        {
+            self.0 += 1;
+        }
+    }
+
+    impl PushedDownState for CallCounter {
+        type Ctx = ();
+
+        fn reduce(&mut self, _parent: Option<&Self>, _vnode: &VNode, _ctx: &mut Self::Ctx) {
+            self.0 += 1;
+        }
+    }
+
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        })
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div {
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        }
+    });
+
+    let mut tree: ClientTree<CallCounter, CallCounter> = ClientTree::new();
+
+    let nodes_updated = tree.apply_mutations(vec![mutations]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
+
+    tree.traverse(|n| {
+        assert_eq!(n.up_state.0, 1);
+        assert_eq!(n.down_state.0, 1);
+    });
+}
+
+#[test]
+fn tree_state_reduce_down_called_minimally_on_update() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        })
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div {
+            width: "100%",
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        }
+    });
+
+    let mut tree: ClientTree<CallCounter, CallCounter> = ClientTree::new();
+
+    let nodes_updated = tree.apply_mutations(vec![mutations]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
+    let nodes_updated = tree.apply_mutations(vec![Mutations {
+        edits: vec![DomEdit::SetAttribute {
+            root: 1,
+            field: "width",
+            value: "99%",
+            ns: Some("style"),
+        }],
+        dirty_scopes: fxhash::FxHashSet::default(),
+        refs: Vec::new(),
+    }]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
+
+    tree.traverse(|n| {
+        assert_eq!(n.down_state.0, 2);
+    });
+}
+
+#[test]
+fn tree_state_reduce_up_called_minimally_on_update() {
+    #[allow(non_snake_case)]
+    fn Base(cx: Scope) -> Element {
+        rsx!(cx, div {
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        })
+    }
+
+    let vdom = VirtualDom::new(Base);
+
+    let mutations = vdom.create_vnodes(rsx! {
+        div {
+            width: "100%",
+            div{
+                div{
+                    p{}
+                }
+                p{
+                    "hello"
+                }
+                div{
+                    h1{}
+                }
+                p{
+                    "world"
+                }
+            }
+        }
+    });
+
+    let mut tree: ClientTree<CallCounter, CallCounter> = ClientTree::new();
+
+    let nodes_updated = tree.apply_mutations(vec![mutations]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
+    let nodes_updated = tree.apply_mutations(vec![Mutations {
+        edits: vec![DomEdit::SetAttribute {
+            root: 4,
+            field: "width",
+            value: "99%",
+            ns: Some("style"),
+        }],
+        dirty_scopes: fxhash::FxHashSet::default(),
+        refs: Vec::new(),
+    }]);
+    let _to_rerender = tree.update_state(&vdom, nodes_updated, &mut (), &mut ());
+
+    tree.traverse(|n| {
+        assert_eq!(n.up_state.0, if n.id.0 > 4 { 1 } else { 2 });
+    });
+}

+ 3 - 1
packages/tui/Cargo.toml

@@ -22,5 +22,7 @@ crossterm = "0.23.0"
 anyhow = "1.0.42"
 tokio = { version = "1.15.0", features = ["full"] }
 futures = "0.3.19"
-stretch2 = "0.4.1"
+# stretch2 = "0.4.1"
+stretch2 = { git = "https://github.com/Demonthos/stretch.git" }
 smallvec = "1.6"
+fxhash = "0.2"

+ 22 - 19
packages/tui/src/hooks.rs

@@ -2,14 +2,17 @@ use crossterm::event::{
     Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind,
 };
 use dioxus_core::*;
+use fxhash::{FxHashMap, FxHashSet};
 
 use dioxus_html::{on::*, KeyCode};
-use dioxus_native_core::{layout::StretchLayout, Tree, TreeNode};
+use dioxus_native_core::{
+    client_tree::{ClientTree, TreeNode},
+    layout::StretchLayout,
+};
 use futures::{channel::mpsc::UnboundedReceiver, StreamExt};
 use std::{
     any::Any,
     cell::RefCell,
-    collections::{HashMap, HashSet},
     rc::Rc,
     sync::Arc,
     time::{Duration, Instant},
@@ -166,7 +169,7 @@ impl InnerInputState {
         evts: &mut Vec<EventCore>,
         resolved_events: &mut Vec<UserEvent>,
         layout: &Stretch,
-        tree: &mut Tree<StretchLayout, StyleModifier>,
+        tree: &mut ClientTree<StretchLayout, StyleModifier>,
     ) {
         let previous_mouse = self
             .mouse
@@ -191,7 +194,7 @@ impl InnerInputState {
         previous_mouse: Option<(MouseData, Vec<u16>)>,
         resolved_events: &mut Vec<UserEvent>,
         layout: &Stretch,
-        tree: &mut Tree<StretchLayout, StyleModifier>,
+        tree: &mut ClientTree<StretchLayout, StyleModifier>,
     ) {
         struct Data<'b> {
             new_pos: (i32, i32),
@@ -213,17 +216,17 @@ impl InnerInputState {
         fn try_create_event(
             name: &'static str,
             data: Arc<dyn Any + Send + Sync>,
-            will_bubble: &mut HashSet<ElementId>,
+            will_bubble: &mut FxHashSet<ElementId>,
             resolved_events: &mut Vec<UserEvent>,
             node: &TreeNode<StretchLayout, StyleModifier>,
-            tree: &Tree<StretchLayout, StyleModifier>,
+            tree: &ClientTree<StretchLayout, StyleModifier>,
         ) {
             // only trigger event if the event was not triggered already by a child
             if will_bubble.insert(node.id) {
                 let mut parent = node.parent;
                 while let Some(parent_id) = parent {
                     will_bubble.insert(parent_id);
-                    parent = tree.get(parent_id.0).parent;
+                    parent = tree[parent_id.0].parent;
                 }
                 resolved_events.push(UserEvent {
                     scope_id: None,
@@ -259,7 +262,7 @@ impl InnerInputState {
 
             {
                 // mousemove
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mousemove") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let previously_contained = data
@@ -285,7 +288,7 @@ impl InnerInputState {
 
             {
                 // mouseenter
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mouseenter") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let previously_contained = data
@@ -311,7 +314,7 @@ impl InnerInputState {
 
             {
                 // mouseover
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mouseover") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let previously_contained = data
@@ -337,7 +340,7 @@ impl InnerInputState {
 
             {
                 // mousedown
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mousedown") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
@@ -359,7 +362,7 @@ impl InnerInputState {
 
             {
                 // mouseup
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mouseup") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
@@ -381,7 +384,7 @@ impl InnerInputState {
 
             {
                 // click
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("click") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
@@ -403,7 +406,7 @@ impl InnerInputState {
 
             {
                 // contextmenu
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("contextmenu") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
@@ -425,7 +428,7 @@ impl InnerInputState {
 
             {
                 // wheel
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("wheel") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let currently_contains = layout_contains_point(node_layout, data.new_pos);
@@ -449,7 +452,7 @@ impl InnerInputState {
 
             {
                 // mouseleave
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mouseleave") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let previously_contained = data
@@ -473,7 +476,7 @@ impl InnerInputState {
 
             {
                 // mouseout
-                let mut will_bubble = HashSet::new();
+                let mut will_bubble = FxHashSet::default();
                 for node in tree.get_listening_sorted("mouseout") {
                     let node_layout = layout.layout(node.up_state.node.unwrap()).unwrap();
                     let previously_contained = data
@@ -543,7 +546,7 @@ impl RinkInputHandler {
     pub fn get_events<'a>(
         &self,
         layout: &Stretch,
-        tree: &mut Tree<StretchLayout, StyleModifier>,
+        tree: &mut ClientTree<StretchLayout, StyleModifier>,
     ) -> Vec<UserEvent> {
         let mut resolved_events = Vec::new();
 
@@ -578,7 +581,7 @@ impl RinkInputHandler {
             .map(|evt| (evt.0, evt.1.into_any()));
 
         // todo: currently resolves events in all nodes, but once the focus system is added it should filter by focus
-        let mut hm: HashMap<&'static str, Vec<Arc<dyn Any + Send + Sync>>> = HashMap::new();
+        let mut hm: FxHashMap<&'static str, Vec<Arc<dyn Any + Send + Sync>>> = FxHashMap::default();
         for (event, data) in events {
             if let Some(v) = hm.get_mut(event) {
                 v.push(data);

+ 12 - 32
packages/tui/src/lib.rs

@@ -9,10 +9,8 @@ use crossterm::{
 };
 use dioxus_core::exports::futures_channel::mpsc::unbounded;
 use dioxus_core::*;
-use dioxus_html::on::{KeyboardData, MouseData, PointerData, TouchData, WheelData};
-use dioxus_native_core::{layout::StretchLayout, Tree};
+use dioxus_native_core::{client_tree::ClientTree, layout::StretchLayout};
 use futures::{channel::mpsc::UnboundedSender, pin_mut, StreamExt};
-use std::collections::HashSet;
 use std::{io, time::Duration};
 use stretch2::{prelude::Size, Stretch};
 use style_attributes::StyleModifier;
@@ -44,7 +42,7 @@ pub fn launch_cfg(app: Component<()>, cfg: Config) {
 
     cx.provide_root_context(state);
 
-    let mut tree: Tree<StretchLayout, StyleModifier> = Tree::new();
+    let mut tree: ClientTree<StretchLayout, StyleModifier> = ClientTree::new();
     let mutations = dom.rebuild();
     let to_update = tree.apply_mutations(vec![mutations]);
     let mut stretch = Stretch::new();
@@ -60,7 +58,7 @@ pub fn render_vdom(
     ctx: UnboundedSender<TermEvent>,
     handler: RinkInputHandler,
     cfg: Config,
-    mut tree: Tree<StretchLayout, StyleModifier>,
+    mut tree: ClientTree<StretchLayout, StyleModifier>,
     mut stretch: Stretch,
 ) -> Result<()> {
     // Setup input handling
@@ -100,12 +98,8 @@ pub fn render_vdom(
             let mut terminal = Terminal::new(backend).unwrap();
 
             terminal.clear().unwrap();
-            let mut to_rerender: HashSet<usize> = tree
-                .nodes
-                .iter()
-                .filter_map(|n| n.as_ref())
-                .map(|n| n.id.0)
-                .collect();
+            let mut to_rerender: fxhash::FxHashSet<usize> = vec![0].into_iter().collect();
+            let mut redraw = true;
 
             loop {
                 /*
@@ -120,15 +114,16 @@ pub fn render_vdom(
                 todo: lazy re-rendering
                 */
 
-                if !to_rerender.is_empty() {
+                if !to_rerender.is_empty() || redraw {
+                    redraw = false;
                     terminal.draw(|frame| {
                         // size is guaranteed to not change when rendering
                         let dims = frame.size();
                         // println!("{dims:?}");
                         let width = dims.width;
                         let height = dims.height;
-                        let root_id = tree.root;
-                        let root_node = tree.get(root_id).up_state.node.unwrap();
+                        let root_id = tree.root_id();
+                        let root_node = tree[root_id].up_state.node.unwrap();
                         stretch
                             .compute_layout(
                                 root_node,
@@ -138,7 +133,7 @@ pub fn render_vdom(
                                 },
                             )
                             .unwrap();
-                        let root = tree.get(tree.root);
+                        let root = &tree[tree.root_id()];
                         render::render_vnode(frame, &stretch, &tree, &root, cfg);
                     })?;
                 }
@@ -146,22 +141,6 @@ pub fn render_vdom(
                 // resolve events before rendering
                 // todo: events do not trigger update?
                 for e in handler.get_events(&stretch, &mut tree) {
-                    // let tname = if e.data.is::<PointerData>() {
-                    //     "PointerData"
-                    // } else if e.data.is::<WheelData>() {
-                    //     "WheelData"
-                    // } else if e.data.is::<MouseData>() {
-                    //     "MouseData"
-                    // } else if e.data.is::<KeyboardData>() {
-                    //     "KeyboardData"
-                    // } else if e.data.is::<TouchData>() {
-                    //     "TouchData"
-                    // } else if e.data.is::<(u16, u16)>() {
-                    //     "(u16, u16)"
-                    // } else {
-                    //     panic!()
-                    // };
-                    // println!("{tname}: {e:?}");
                     vdom.handle_message(SchedulerMsg::Event(e));
                 }
 
@@ -184,7 +163,8 @@ pub fn render_vdom(
                                             break;
                                         }
                                     }
-                                    TermEvent::Resize(_, _) | TermEvent::Mouse(_) => {}
+                                    TermEvent::Resize(_, _) => redraw = true,
+                                    TermEvent::Mouse(_) => {}
                                 },
                                 InputEvent::Tick => {} // tick
                                 InputEvent::Close => break,

+ 13 - 7
packages/tui/src/render.rs

@@ -1,4 +1,8 @@
-use dioxus_native_core::{layout::StretchLayout, layout_attributes::UnitSystem, Tree, TreeNode};
+use dioxus_native_core::{
+    client_tree::{ClientTree, TreeNode},
+    layout::StretchLayout,
+    layout_attributes::UnitSystem,
+};
 use std::io::Stdout;
 use stretch2::{
     geometry::Point,
@@ -19,12 +23,14 @@ const RADIUS_MULTIPLIER: [f32; 2] = [1.0, 0.5];
 pub fn render_vnode<'a>(
     frame: &mut tui::Frame<CrosstermBackend<Stdout>>,
     layout: &Stretch,
-    tree: &Tree<StretchLayout, StyleModifier>,
+    tree: &ClientTree<StretchLayout, StyleModifier>,
     node: &TreeNode<StretchLayout, StyleModifier>,
     cfg: Config,
 ) {
+    use dioxus_native_core::client_tree::TreeNodeType;
+
     match &node.node_type {
-        dioxus_native_core::TreeNodeType::Placeholder => return,
+        TreeNodeType::Placeholder => return,
         _ => (),
     }
 
@@ -34,7 +40,7 @@ pub fn render_vnode<'a>(
     let Size { width, height } = size;
 
     match &node.node_type {
-        dioxus_native_core::TreeNodeType::Text { text } => {
+        TreeNodeType::Text { text } => {
             #[derive(Default)]
             struct Label<'a> {
                 text: &'a str,
@@ -64,7 +70,7 @@ pub fn render_vnode<'a>(
                 frame.render_widget(WidgetWithContext::new(label, cfg), area);
             }
         }
-        dioxus_native_core::TreeNodeType::Element { children, .. } => {
+        TreeNodeType::Element { children, .. } => {
             let area = Rect::new(*x as u16, *y as u16, *width as u16, *height as u16);
 
             // the renderer will panic if a node is rendered out of range even if the size is zero
@@ -73,10 +79,10 @@ pub fn render_vnode<'a>(
             }
 
             for c in children {
-                render_vnode(frame, layout, tree, tree.get(c.0), cfg);
+                render_vnode(frame, layout, tree, &tree[c.0], cfg);
             }
         }
-        dioxus_native_core::TreeNodeType::Placeholder => unreachable!(),
+        TreeNodeType::Placeholder => unreachable!(),
     }
 }
 

+ 4 - 2
packages/tui/src/style_attributes.rs

@@ -31,8 +31,8 @@
 
 use dioxus_core::{Attribute, VNode};
 use dioxus_native_core::{
+    client_tree::PushedDownState,
     layout_attributes::{parse_value, UnitSystem},
-    PushedDownState,
 };
 
 use crate::style::{RinkColor, RinkStyle};
@@ -48,7 +48,9 @@ impl PushedDownState for StyleModifier {
 
     fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, _ctx: &mut Self::Ctx) {
         *self = StyleModifier::default();
-        self.style.fg = None;
+        if parent.is_some() {
+            self.style.fg = None;
+        }
         match vnode {
             VNode::Element(el) => {
                 // handle text modifier elements

+ 0 - 83
packages/tui/src/utils.rs

@@ -1,83 +0,0 @@
-// use dioxus_core::{Element, ElementId, Mutations, VNode, VirtualDom, DomEdit};
-
-// /// The focus system needs a iterator that can persist through changes in the [VirtualDom]. Iterate through it with [ElementIter::next], and update it with [ElementIter::update] (with data from [`VirtualDom::work_with_deadline`]).
-// pub(crate) struct ElementIter {
-//     // stack of elements and fragments
-//     stack: smallvec::SmallVec<[(ElementId, usize); 5]>,
-// }
-
-// impl ElementIter {
-//     pub(crate) fn new(initial: ElementId) -> Self {
-//         ElementIter {
-//             stack: smallvec::smallvec![(initial, 0)],
-//         }
-//     }
-//     /// remove stale element refreneces
-//     pub(crate) fn update(&mut self, mutations: &Mutations, vdom: &VirtualDom) {
-//         let ids_removed: Vec<_> = mutations.edits.iter().filter_map(|e| if let DomEdit::Remove{root: }).collect();
-//         for node in self.stack {
-
-//             match node.0 {
-//                 VNode::Fragment(f) => {
-
-//                 }
-
-//                 VNode::Element(_) => {}
-
-//                 _ => unreachable!(),
-//             }
-//         }
-//     }
-//     pub(crate) fn next<'a>(&mut self, vdom: &'a VirtualDom) -> Option<&'a VNode<'a>> {
-//         let last = self.stack.last()?.0;
-//         let node = vdom.get_element(last)?;
-//         match node {
-//             VNode::Fragment(f) => {
-//                 let mut last_mut = self.stack.last_mut()?;
-//                 if last_mut.1 + 1 >= f.children.len() {
-//                     self.stack.pop();
-//                     self.next(vdom)
-//                 } else {
-//                     last_mut.1 += 1;
-//                     let new_node = &f.children[last_mut.1];
-//                     if matches!(new_node, VNode::Fragment(_) | VNode::Element(_)) {
-//                         self.stack.push((new_node.mounted_id(), 0));
-//                     }
-//                     self.next(vdom)
-//                 }
-//             }
-
-//             VNode::Component(vcomp) => {
-//                 let idx = vcomp.scope.get().unwrap();
-//                 let new_node = vdom.get_scope(idx).unwrap().root_node();
-//                 *self.stack.last_mut()? = (new_node.mounted_id(), 0);
-//                 self.next(vdom)
-//             }
-
-//             VNode::Placeholder(_) | VNode::Text(_) => {
-//                 self.stack.pop();
-//                 self.next(vdom)
-//             }
-
-//             VNode::Element(e) => {
-//                 let mut last_mut = self.stack.last_mut()?;
-//                 if last_mut.1 + 1 >= e.children.len() {
-//                     self.stack.pop();
-//                     self.next(vdom);
-//                 } else {
-//                     last_mut.1 += 1;
-//                     let new_node = &e.children[last_mut.1];
-//                     if matches!(new_node, VNode::Fragment(_) | VNode::Element(_)) {
-//                         self.stack.push((new_node.mounted_id(), 0));
-//                     }
-//                     self.next(vdom);
-//                 }
-//                 Some(node)
-//             }
-//         }
-//     }
-
-//     pub(crate) fn peak(&self) -> Option<&ElementId> {
-//         self.stack.last().map(|(e, c)| e)
-//     }
-// }

+ 7 - 0
packages/tui/tests/margin.rs

@@ -90,4 +90,11 @@ fn margin_and_flex_row2() {
     assert_eq!(stretch.layout(node).unwrap().size.height, 100f32);
     assert_eq!(stretch.layout(node).unwrap().location.x, 0f32);
     assert_eq!(stretch.layout(node).unwrap().location.y, 0f32);
+
+    dbg!(stretch.layout(node0)).unwrap();
+
+    // assert_eq!(stretch.layout(node0).unwrap().size.width, 80f32);
+    // assert_eq!(stretch.layout(node0).unwrap().size.height, 100f32);
+    // assert_eq!(stretch.layout(node0).unwrap().location.x, 10f32);
+    // assert_eq!(stretch.layout(node0).unwrap().location.y, 0f32);
 }