Merge branch 'master' into use-server-function
This commit is contained in:
1 parent
f3d1600822
commit
7e2ef1260f
81 files changed
+483
-375
No files matched your search
@@ -86,13 +86,6 @@ dioxus-core = { workspace = true, features = ["serialize"] }
|
||||
default = []
|
||||
plugin = ["mlua"]
|
||||
|
||||
# install path dx and dioxus as the same command
|
||||
# so, they're not really aliases
|
||||
# eventually dx will defer to the right version of dioxus
|
||||
[[bin]]
|
||||
path = "src/main.rs"
|
||||
name = "dioxus"
|
||||
|
||||
[[bin]]
|
||||
path = "src/main.rs"
|
||||
name = "dx"
|
||||
@@ -4,7 +4,7 @@
|
||||
name = "dioxus-cli"
|
||||
|
||||
# default platfrom
|
||||
# you can also use `dioxus serve/build --platform XXX` to use other platform
|
||||
# you can also use `dx serve/build --platform XXX` to use other platform
|
||||
# value: web | desktop
|
||||
default_platform = "desktop"
|
||||
|
||||
@@ -42,4 +42,4 @@ script = []
|
||||
|
||||
# use binaryen.wasm-opt for output Wasm file
|
||||
# binaryen just will trigger in `web` platform
|
||||
binaryen = { wasm_opt = true }
|
||||
binaryen = { wasm_opt = true }
|
||||
@@ -24,7 +24,7 @@ cargo install --path . --debug
|
||||
|
||||
## Get Started
|
||||
|
||||
Use `dioxus create project-name` to initialize a new Dioxus project. <br>
|
||||
Use `dx create project-name` to initialize a new Dioxus project. <br>
|
||||
|
||||
It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxus-template) repository.
|
||||
|
||||
@@ -33,7 +33,7 @@ It will be cloned from the [dioxus-template](https://github.com/DioxusLabs/dioxu
|
||||
Alternatively, you can specify the template path:
|
||||
|
||||
```
|
||||
dioxus create hello --template gh:dioxuslabs/dioxus-template
|
||||
dx create hello --template gh:dioxuslabs/dioxus-template
|
||||
```
|
||||
|
||||
## Dioxus Config File
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
In this chapter we will introduce all `dioxus-cli` commands.
|
||||
|
||||
> You can also use `dioxus --help` to get cli help info.
|
||||
> You can also use `dx --help` to get cli help info.
|
||||
|
||||
```
|
||||
dioxus
|
||||
dx
|
||||
Build, bundle, & ship your Dioxus app
|
||||
|
||||
USAGE:
|
||||
dioxus [OPTIONS] <SUBCOMMAND>
|
||||
dx [OPTIONS] <SUBCOMMAND>
|
||||
|
||||
OPTIONS:
|
||||
-h, --help Print help information
|
||||
@@ -23,4 +23,4 @@ SUBCOMMANDS:
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
serve Build, watch & serve the Rust WASM app and all of its assets
|
||||
translate Translate some html file into a Dioxus component
|
||||
```
|
||||
```
|
||||
@@ -1,13 +1,13 @@
|
||||
# Build
|
||||
|
||||
The `dioxus build` command can help you `pack & build` a dioxus project.
|
||||
The `dx build` command can help you `pack & build` a dioxus project.
|
||||
|
||||
```
|
||||
dioxus-build
|
||||
dioxus-build
|
||||
Build the Rust WASM app and all of its assets
|
||||
|
||||
USAGE:
|
||||
dioxus build [OPTIONS]
|
||||
dx build [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--example <EXAMPLE> [default: ""]
|
||||
@@ -19,7 +19,7 @@ OPTIONS:
|
||||
You can use this command to build a project:
|
||||
|
||||
```
|
||||
dioxus build --release
|
||||
dx build --release
|
||||
```
|
||||
|
||||
## Target platform
|
||||
@@ -28,14 +28,14 @@ Use the `platform` option to choose your target platform:
|
||||
|
||||
```
|
||||
# for desktop project
|
||||
dioxus build --platform desktop
|
||||
dx build --platform desktop
|
||||
```
|
||||
|
||||
`platform` currently only supports `desktop` & `web`.
|
||||
|
||||
```
|
||||
# for web project
|
||||
dioxus build --platform web
|
||||
dx build --platform web
|
||||
```
|
||||
|
||||
## Specify workspace bin
|
||||
@@ -43,7 +43,7 @@ dioxus build --platform web
|
||||
You can add the `--bin` option to select which crate you want Dioxus to build:
|
||||
|
||||
```
|
||||
dioxus build --bin app
|
||||
dx build --bin app
|
||||
```
|
||||
|
||||
## Build Example
|
||||
@@ -52,5 +52,5 @@ You can use the `example` option to select a example to build:
|
||||
|
||||
```
|
||||
# build the `test` example
|
||||
dioxus build --exmaple test
|
||||
```
|
||||
dx build --exmaple test
|
||||
```
|
||||
@@ -1,13 +1,13 @@
|
||||
# Clean
|
||||
|
||||
`dioxus clean` will clear the build artifacts (the out_dir and the cargo cache)
|
||||
`dx clean` will clear the build artifacts (the out_dir and the cargo cache)
|
||||
|
||||
```
|
||||
dioxus-clean
|
||||
dioxus-clean
|
||||
Clean build artifacts
|
||||
|
||||
USAGE:
|
||||
dioxus clean [OPTIONS]
|
||||
dx clean [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--bin [default: None]
|
||||
@@ -16,12 +16,12 @@ OPTIONS:
|
||||
# Example
|
||||
|
||||
```
|
||||
dioxus clean
|
||||
dx clean
|
||||
```
|
||||
|
||||
# Specify workspace bin
|
||||
You can add the `--bin` option to select which crate you want Dioxus to clean artifacts from:
|
||||
|
||||
```
|
||||
dioxus clean --bin app
|
||||
```
|
||||
dx clean --bin app
|
||||
```
|
||||
@@ -1,13 +1,13 @@
|
||||
# Serve
|
||||
|
||||
The `dioxus serve` can start a dev server with hot-reloading
|
||||
The `dx serve` can start a dev server with hot-reloading
|
||||
|
||||
```
|
||||
dioxus-serve
|
||||
dioxus-serve
|
||||
Build, watch & serve the Rust WASM app and all of its assets
|
||||
|
||||
USAGE:
|
||||
dioxus serve [OPTIONS]
|
||||
dx serve [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--example <EXAMPLE> [default: ""]
|
||||
@@ -20,7 +20,7 @@ OPTIONS:
|
||||
You can use this command to build project and start a dev server:
|
||||
|
||||
```
|
||||
dioxus serve
|
||||
dx serve
|
||||
```
|
||||
|
||||
## Serve Example
|
||||
@@ -29,7 +29,7 @@ You can use the `example` option to serve a example:
|
||||
|
||||
```
|
||||
# serve the `test` example
|
||||
dioxus serve --exmaple test
|
||||
dx serve --exmaple test
|
||||
```
|
||||
|
||||
## Specify workspace bin
|
||||
@@ -37,7 +37,7 @@ dioxus serve --exmaple test
|
||||
You can add the `--bin` option to select which crate you want Dioxus to build and serve:
|
||||
|
||||
```
|
||||
dioxus serve --bin app
|
||||
dx serve --bin app
|
||||
```
|
||||
|
||||
## Open Browser
|
||||
@@ -45,7 +45,7 @@ dioxus serve --bin app
|
||||
You can add the `--open` option to open system default browser when server startup:
|
||||
|
||||
```
|
||||
dioxus serve --open
|
||||
dx serve --open
|
||||
```
|
||||
|
||||
## RSX Hot Reloading
|
||||
@@ -53,7 +53,7 @@ dioxus serve --open
|
||||
You can add the `--hot-reload` flag to enable [rsx hot reloading](https://dioxuslabs.com/docs/0.3/guide/en/getting_started/hot_reload.html). This will allow you to reload some rsx changes without a full recompile:
|
||||
|
||||
```
|
||||
dioxus serve --open
|
||||
dx serve --open
|
||||
```
|
||||
|
||||
## Cross Origin Policy
|
||||
@@ -66,5 +66,5 @@ You can add the `cross-origin-policy` option to change cross-origin header to:
|
||||
```
|
||||
|
||||
```
|
||||
dioxus serve --corss-origin-policy
|
||||
```
|
||||
dx serve --corss-origin-policy
|
||||
```
|
||||
@@ -1,13 +1,13 @@
|
||||
# Translate
|
||||
|
||||
`dioxus translate` can translate some `html` file into a Dioxus compoent
|
||||
`dx translate` can translate some `html` file into a Dioxus compoent
|
||||
|
||||
```
|
||||
dioxus-translate
|
||||
dioxus-translate
|
||||
Translate some source file into a Dioxus component
|
||||
|
||||
USAGE:
|
||||
dioxus translate [OPTIONS] [OUTPUT]
|
||||
dx translate [OPTIONS] [OUTPUT]
|
||||
|
||||
ARGS:
|
||||
<OUTPUT> Output file, defaults to stdout if not present
|
||||
@@ -22,7 +22,7 @@ OPTIONS:
|
||||
You can use the `file` option to set path to the `html` file to translate:
|
||||
|
||||
```
|
||||
dioxus transtale --file ./index.html
|
||||
dx transtale --file ./index.html
|
||||
```
|
||||
|
||||
## Output rsx to a file
|
||||
@@ -30,7 +30,7 @@ dioxus transtale --file ./index.html
|
||||
You can pass a file to the traslate command to set the path to write the output of the command to:
|
||||
|
||||
```
|
||||
dioxus translate --file ./index.html component.rsx
|
||||
dx translate --file ./index.html component.rsx
|
||||
```
|
||||
|
||||
## Output rsx to a file
|
||||
@@ -38,7 +38,7 @@ dioxus translate --file ./index.html component.rsx
|
||||
Setting the `component` option will create a compoent from the HTML:
|
||||
|
||||
```
|
||||
dioxus translate --file ./index.html --component
|
||||
dx translate --file ./index.html --component
|
||||
```
|
||||
|
||||
## Example
|
||||
@@ -65,4 +65,4 @@ fn component(cx: Scope) -> Element {
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -29,8 +29,8 @@ General application confiration:
|
||||
# default: web
|
||||
default_platform = "web"
|
||||
```
|
||||
if you change this to `desktop`, the `dioxus build` will default building a desktop app
|
||||
3. ***out_dir*** - The directory to place the build artifacts from `dioxus build` or `dioxus service` into. This is also where the `assets` directory will be copied to
|
||||
if you change this to `desktop`, the `dx build` will default building a desktop app
|
||||
3. ***out_dir*** - The directory to place the build artifacts from `dx build` or `dx service` into. This is also where the `assets` directory will be copied to
|
||||
```
|
||||
out_dir = "dist"
|
||||
```
|
||||
|
||||
@@ -4,10 +4,10 @@ Once you have the Dioxus CLI tool installed, you can use it to create dioxus pro
|
||||
|
||||
## Initializing a default project
|
||||
|
||||
First, run the `dioxus create` command to create a new project ready to be used with Dioxus and the Dioxus CLI:
|
||||
First, run the `dx create` command to create a new project ready to be used with Dioxus and the Dioxus CLI:
|
||||
|
||||
```
|
||||
dioxus create hello-dioxus
|
||||
dx create hello-dioxus
|
||||
```
|
||||
|
||||
> It will clone a default template from github template: [DioxusLabs/dioxus-template](https://github.com/DioxusLabs/dioxus-template)
|
||||
@@ -15,7 +15,7 @@ dioxus create hello-dioxus
|
||||
>
|
||||
> You can choose to create your project from a different template by passing the `template` argument:
|
||||
> ```
|
||||
> dioxus init hello-dioxus --template=gh:dioxuslabs/dioxus-template
|
||||
> dx init hello-dioxus --template=gh:dioxuslabs/dioxus-template
|
||||
> ```
|
||||
|
||||
Next, move the current directory into your new project:
|
||||
@@ -33,7 +33,7 @@ cd hello-dioxus
|
||||
Finally, create serve your project with the Dioxus CLI:
|
||||
|
||||
```
|
||||
dioxus serve
|
||||
dx serve
|
||||
```
|
||||
|
||||
By default, the CLI serve your site at: [`http://127.0.0.1:8080/`](http://127.0.0.1:8080/)
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> For Cli 0.2.0 we will add `plugin-develop` support.
|
||||
|
||||
Before the 0.2.0 we use `dioxus tool` to use & install some plugin, but we think that is not good for extend cli program, some people want tailwind support, some people want sass support, we can't add all this thing in to the cli source code and we don't have time to maintain a lot of tools that user request, so maybe user make plugin by themself is a good choice.
|
||||
Before the 0.2.0 we use `dx tool` to use & install some plugin, but we think that is not good for extend cli program, some people want tailwind support, some people want sass support, we can't add all this thing in to the cli source code and we don't have time to maintain a lot of tools that user request, so maybe user make plugin by themself is a good choice.
|
||||
|
||||
### Why Lua ?
|
||||
|
||||
@@ -76,4 +76,4 @@ end
|
||||
manager.serve.interval = 1000
|
||||
|
||||
return manager
|
||||
```
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
name = "{{project-name}}"
|
||||
|
||||
# default platfrom
|
||||
# you can also use `dioxus serve/build --platform XXX` to use other platform
|
||||
# you can also use `dx serve/build --platform XXX` to use other platform
|
||||
# value: web | desktop
|
||||
default_platform = "{{default-platform}}"
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
"Binaryen tool not found, you can use `dioxus tool add binaryen` to install it."
|
||||
"Binaryen tool not found, you can use `dx tool add binaryen` to install it."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -200,7 +200,7 @@ pub fn build(config: &CrateConfig, quiet: bool) -> Result<BuildResult> {
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
"Tailwind tool not found, you can use `dioxus tool add tailwindcss` to install it."
|
||||
"Tailwind tool not found, you can use `dx tool add tailwindcss` to install it."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,12 +136,16 @@ async fn autoformat_project(check: bool) -> Result<()> {
|
||||
}
|
||||
|
||||
fn collect_rs_files(folder: &Path, files: &mut Vec<PathBuf>) {
|
||||
let Ok(folder) = folder.read_dir() else { return };
|
||||
let Ok(folder) = folder.read_dir() else {
|
||||
return;
|
||||
};
|
||||
|
||||
// load the gitignore
|
||||
|
||||
for entry in folder {
|
||||
let Ok(entry) = entry else { continue; };
|
||||
let Ok(entry) = entry else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let path = entry.path();
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ impl Plugin {
|
||||
}
|
||||
}
|
||||
Plugin::Add { name: _ } => {
|
||||
log::info!("You can use `dioxus plugin app-path` to get Installation position");
|
||||
log::info!("You can use `dx plugin app-path` to get Installation position");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -88,8 +88,7 @@ impl<'b> VirtualDom {
|
||||
}
|
||||
|
||||
// Intialize the root nodes slice
|
||||
node.root_ids
|
||||
.intialize(vec![ElementId(0); node.template.get().roots.len()].into_boxed_slice());
|
||||
*node.root_ids.borrow_mut() = vec![ElementId(0); node.template.get().roots.len()];
|
||||
|
||||
// The best renderers will have templates prehydrated and registered
|
||||
// Just in case, let's create the template using instructions anyways
|
||||
@@ -328,7 +327,7 @@ impl<'b> VirtualDom {
|
||||
fn load_template_root(&mut self, template: &VNode, root_idx: usize) -> ElementId {
|
||||
// Get an ID for this root since it's a real root
|
||||
let this_id = self.next_root(template, root_idx);
|
||||
template.root_ids.set(root_idx, this_id);
|
||||
template.root_ids.borrow_mut()[root_idx] = this_id;
|
||||
|
||||
self.mutations.push(LoadTemplate {
|
||||
name: template.template.get().name,
|
||||
|
||||
@@ -129,12 +129,14 @@ impl<'b> VirtualDom {
|
||||
});
|
||||
|
||||
// Make sure the roots get transferred over while we're here
|
||||
right_template.root_ids.transfer(&left_template.root_ids);
|
||||
*right_template.root_ids.borrow_mut() = left_template.root_ids.borrow().clone();
|
||||
|
||||
let root_ids = right_template.root_ids.borrow();
|
||||
|
||||
// Update the node refs
|
||||
for i in 0..right_template.root_ids.len() {
|
||||
if let Some(root_id) = right_template.root_ids.get(i) {
|
||||
self.update_template(root_id, right_template);
|
||||
for i in 0..root_ids.len() {
|
||||
if let Some(root_id) = root_ids.get(i) {
|
||||
self.update_template(*root_id, right_template);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -686,7 +688,7 @@ impl<'b> VirtualDom {
|
||||
Some(node) => node,
|
||||
None => {
|
||||
self.mutations.push(Mutation::PushRoot {
|
||||
id: node.root_ids.get(idx).unwrap(),
|
||||
id: node.root_ids.borrow()[idx],
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
@@ -821,7 +823,7 @@ impl<'b> VirtualDom {
|
||||
if let Some(dy) = node.dynamic_root(idx) {
|
||||
self.remove_dynamic_node(dy, gen_muts);
|
||||
} else {
|
||||
let id = node.root_ids.get(idx).unwrap();
|
||||
let id = node.root_ids.borrow()[idx];
|
||||
if gen_muts {
|
||||
self.mutations.push(Mutation::Remove { id });
|
||||
}
|
||||
@@ -928,7 +930,7 @@ impl<'b> VirtualDom {
|
||||
|
||||
fn find_first_element(&self, node: &'b VNode<'b>) -> ElementId {
|
||||
match node.dynamic_root(0) {
|
||||
None => node.root_ids.get(0).unwrap(),
|
||||
None => node.root_ids.borrow()[0],
|
||||
Some(Text(t)) => t.id.get().unwrap(),
|
||||
Some(Fragment(t)) => self.find_first_element(&t[0]),
|
||||
Some(Placeholder(t)) => t.id.get().unwrap(),
|
||||
@@ -944,7 +946,7 @@ impl<'b> VirtualDom {
|
||||
|
||||
fn find_last_element(&self, node: &'b VNode<'b>) -> ElementId {
|
||||
match node.dynamic_root(node.template.get().roots.len() - 1) {
|
||||
None => node.root_ids.last().unwrap(),
|
||||
None => *node.root_ids.borrow().last().unwrap(),
|
||||
Some(Text(t)) => t.id.get().unwrap(),
|
||||
Some(Fragment(t)) => self.find_last_element(t.last().unwrap()),
|
||||
Some(Placeholder(t)) => t.id.get().unwrap(),
|
||||
|
||||
+3
-102
@@ -5,7 +5,7 @@ use bumpalo::boxed::Box as BumpBox;
|
||||
use bumpalo::Bump;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
cell::{Cell, RefCell, UnsafeCell},
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Arguments, Debug},
|
||||
};
|
||||
|
||||
@@ -54,7 +54,7 @@ pub struct VNode<'a> {
|
||||
|
||||
/// The IDs for the roots of this template - to be used when moving the template around and removing it from
|
||||
/// the actual Dom
|
||||
pub root_ids: BoxedCellSlice,
|
||||
pub root_ids: RefCell<Vec<ElementId>>,
|
||||
|
||||
/// The dynamic parts of the template
|
||||
pub dynamic_nodes: &'a [DynamicNode<'a>],
|
||||
@@ -63,112 +63,13 @@ pub struct VNode<'a> {
|
||||
pub dynamic_attrs: &'a [Attribute<'a>],
|
||||
}
|
||||
|
||||
// Saftey: There is no way to get references to the internal data of this struct so no refrences will be invalidated by mutating the data with a immutable reference (The same principle behind Cell)
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BoxedCellSlice(UnsafeCell<Option<Box<[ElementId]>>>);
|
||||
|
||||
impl Clone for BoxedCellSlice {
|
||||
fn clone(&self) -> Self {
|
||||
Self(UnsafeCell::new(unsafe { (*self.0.get()).clone() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl BoxedCellSlice {
|
||||
pub fn last(&self) -> Option<ElementId> {
|
||||
unsafe {
|
||||
(*self.0.get())
|
||||
.as_ref()
|
||||
.and_then(|inner| inner.as_ref().last().copied())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, idx: usize) -> Option<ElementId> {
|
||||
unsafe {
|
||||
(*self.0.get())
|
||||
.as_ref()
|
||||
.and_then(|inner| inner.as_ref().get(idx).copied())
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_unchecked(&self, idx: usize) -> Option<ElementId> {
|
||||
(*self.0.get())
|
||||
.as_ref()
|
||||
.and_then(|inner| inner.as_ref().get(idx).copied())
|
||||
}
|
||||
|
||||
pub fn set(&self, idx: usize, new: ElementId) {
|
||||
unsafe {
|
||||
if let Some(inner) = &mut *self.0.get() {
|
||||
inner[idx] = new;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intialize(&self, contents: Box<[ElementId]>) {
|
||||
unsafe {
|
||||
*self.0.get() = Some(contents);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transfer(&self, other: &Self) {
|
||||
unsafe {
|
||||
*self.0.get() = (*other.0.get()).clone();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_from(&self, other: &Self) {
|
||||
unsafe {
|
||||
*self.0.get() = (*other.0.get()).take();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
unsafe {
|
||||
(*self.0.get())
|
||||
.as_ref()
|
||||
.map(|inner| inner.len())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a BoxedCellSlice {
|
||||
type Item = ElementId;
|
||||
|
||||
type IntoIter = BoxedCellSliceIter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
BoxedCellSliceIter {
|
||||
index: 0,
|
||||
borrow: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BoxedCellSliceIter<'a> {
|
||||
index: usize,
|
||||
borrow: &'a BoxedCellSlice,
|
||||
}
|
||||
|
||||
impl Iterator for BoxedCellSliceIter<'_> {
|
||||
type Item = ElementId;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let result = self.borrow.get(self.index);
|
||||
if result.is_some() {
|
||||
self.index += 1;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VNode<'a> {
|
||||
/// Create a template with no nodes that will be skipped over during diffing
|
||||
pub fn empty() -> Element<'a> {
|
||||
Some(VNode {
|
||||
key: None,
|
||||
parent: None,
|
||||
root_ids: BoxedCellSlice::default(),
|
||||
root_ids: Default::default(),
|
||||
dynamic_nodes: &[],
|
||||
dynamic_attrs: &[],
|
||||
template: Cell::new(Template {
|
||||
|
||||
@@ -87,7 +87,7 @@ impl VirtualDom {
|
||||
if matches!(allocated, RenderReturn::Aborted(_)) {
|
||||
self.suspended_scopes.insert(scope.id);
|
||||
}
|
||||
} else {
|
||||
} else if !self.suspended_scopes.is_empty() {
|
||||
_ = self.suspended_scopes.remove(&scope.id);
|
||||
}
|
||||
|
||||
|
||||
@@ -693,13 +693,13 @@ impl<'src> ScopeState {
|
||||
raw_ref.downcast_mut::<State>()
|
||||
})
|
||||
.expect(
|
||||
r###"
|
||||
r#"
|
||||
Unable to retrieve the hook that was initialized at this index.
|
||||
Consult the `rules of hooks` to understand how to use hooks properly.
|
||||
|
||||
You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
|
||||
Functions prefixed with "use" should never be called conditionally.
|
||||
"###,
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -571,12 +571,15 @@ impl VirtualDom {
|
||||
/// The mutations will be thrown out, so it's best to use this method for things like SSR that have async content
|
||||
pub async fn wait_for_suspense(&mut self) {
|
||||
loop {
|
||||
// println!("waiting for suspense {:?}", self.suspended_scopes);
|
||||
if self.suspended_scopes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// println!("waiting for suspense");
|
||||
self.wait_for_work().await;
|
||||
|
||||
// println!("Rendered immediately");
|
||||
_ = self.render_immediate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Verify that tasks get polled by the virtualdom properly, and that we escape wait_for_work safely
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use std::time::Duration;
|
||||
use std::{sync::atomic::AtomicUsize, time::Duration};
|
||||
|
||||
static mut POLL_COUNT: usize = 0;
|
||||
static POLL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
#[tokio::test]
|
||||
async fn it_works() {
|
||||
@@ -18,7 +18,10 @@ async fn it_works() {
|
||||
|
||||
// By the time the tasks are finished, we should've accumulated ticks from two tasks
|
||||
// Be warned that by setting the delay to too short, tokio might not schedule in the tasks
|
||||
assert_eq!(unsafe { POLL_COUNT }, 135);
|
||||
assert_eq!(
|
||||
POLL_COUNT.fetch_add(0, std::sync::atomic::Ordering::Relaxed),
|
||||
135
|
||||
);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
@@ -26,14 +29,14 @@ fn app(cx: Scope) -> Element {
|
||||
cx.spawn(async {
|
||||
for x in 0..10 {
|
||||
tokio::time::sleep(Duration::from_micros(50)).await;
|
||||
unsafe { POLL_COUNT += x }
|
||||
POLL_COUNT.fetch_add(x, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
|
||||
cx.spawn(async {
|
||||
for x in 0..10 {
|
||||
tokio::time::sleep(Duration::from_micros(25)).await;
|
||||
unsafe { POLL_COUNT += x * 2 }
|
||||
POLL_COUNT.fetch_add(x * 2, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,11 +8,48 @@ pub(crate) struct FileDialogRequest {
|
||||
#[serde(default)]
|
||||
accept: Option<String>,
|
||||
multiple: bool,
|
||||
directory: bool,
|
||||
pub event: String,
|
||||
pub target: usize,
|
||||
pub bubbles: bool,
|
||||
}
|
||||
|
||||
fn get_file_event_for_folder(request: &FileDialogRequest, dialog: rfd::FileDialog) -> Vec<PathBuf> {
|
||||
if request.multiple {
|
||||
dialog.pick_folders().into_iter().flatten().collect()
|
||||
} else {
|
||||
dialog.pick_folder().into_iter().collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_file_event_for_file(
|
||||
request: &FileDialogRequest,
|
||||
mut dialog: rfd::FileDialog,
|
||||
) -> Vec<PathBuf> {
|
||||
let filters: Vec<_> = request
|
||||
.accept
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.split(',')
|
||||
.filter_map(|s| Filters::from_str(s).ok())
|
||||
.collect();
|
||||
|
||||
let file_extensions: Vec<_> = filters
|
||||
.iter()
|
||||
.flat_map(|f| f.as_extensions().into_iter())
|
||||
.collect();
|
||||
|
||||
dialog = dialog.add_filter("name", file_extensions.as_slice());
|
||||
|
||||
let files: Vec<_> = if request.multiple {
|
||||
dialog.pick_files().into_iter().flatten().collect()
|
||||
} else {
|
||||
dialog.pick_file().into_iter().collect()
|
||||
};
|
||||
|
||||
files
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "windows",
|
||||
target_os = "macos",
|
||||
@@ -36,30 +73,13 @@ pub(crate) fn get_file_event(_request: &FileDialogRequest) -> Vec<PathBuf> {
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
pub(crate) fn get_file_event(request: &FileDialogRequest) -> Vec<PathBuf> {
|
||||
let mut dialog = rfd::FileDialog::new();
|
||||
let dialog = rfd::FileDialog::new();
|
||||
|
||||
let filters: Vec<_> = request
|
||||
.accept
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.split(',')
|
||||
.filter_map(|s| Filters::from_str(s).ok())
|
||||
.collect();
|
||||
|
||||
let file_extensions: Vec<_> = filters
|
||||
.iter()
|
||||
.flat_map(|f| f.as_extensions().into_iter())
|
||||
.collect();
|
||||
|
||||
dialog = dialog.add_filter("name", file_extensions.as_slice());
|
||||
|
||||
let files: Vec<_> = if request.multiple {
|
||||
dialog.pick_files().into_iter().flatten().collect()
|
||||
if request.directory {
|
||||
get_file_event_for_folder(request, dialog)
|
||||
} else {
|
||||
dialog.pick_file().into_iter().collect()
|
||||
};
|
||||
|
||||
files
|
||||
get_file_event_for_file(request, dialog)
|
||||
}
|
||||
}
|
||||
|
||||
enum Filters {
|
||||
|
||||
@@ -24,7 +24,7 @@ fn module_loader(root_name: &str) -> String {
|
||||
let target_id = find_real_id(target);
|
||||
if (target_id !== null) {
|
||||
const send = (event_name) => {
|
||||
const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name });
|
||||
const message = serializeIpcMessage("file_diolog", { accept: target.getAttribute("accept"), directory: target.getAttribute("webkitdirectory") === "true", multiple: target.hasAttribute("multiple"), target: parseInt(target_id), bubbles: event_bubbles(event_name), event: event_name });
|
||||
window.ipc.postMessage(message);
|
||||
};
|
||||
send("change&input");
|
||||
|
||||
@@ -20,7 +20,7 @@ fn app(cx: Scope) -> Element {
|
||||
background_color: "hsl({hue}, 70%, {brightness}%)",
|
||||
onmousemove: move |evt| {
|
||||
if let RenderReturn::Ready(node) = cx.root_node() {
|
||||
if let Some(id) = node.root_ids.get(0){
|
||||
if let Some(id) = node.root_ids.borrow().get(0).cloned() {
|
||||
let node = tui_query.get(mapping.get_node_id(id).unwrap());
|
||||
let Size{width, height} = node.size().unwrap();
|
||||
let pos = evt.inner().element_coordinates();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Run with:
|
||||
//!
|
||||
//! ```sh
|
||||
//! dioxus build --features web
|
||||
//! dx build --features web
|
||||
//! cargo run --features ssr
|
||||
//! ```
|
||||
|
||||
|
||||
@@ -1098,6 +1098,7 @@ builder_constructors! {
|
||||
autofocus: Bool DEFAULT,
|
||||
capture: String DEFAULT,
|
||||
checked: Bool DEFAULT,
|
||||
directory: Bool "webkitdirectory",
|
||||
disabled: Bool DEFAULT,
|
||||
form: Id DEFAULT,
|
||||
formaction: Uri DEFAULT,
|
||||
|
||||
@@ -56,10 +56,9 @@ where
|
||||
{
|
||||
use serde::Deserialize;
|
||||
|
||||
let Ok(file_engine) =
|
||||
SerializedFileEngine::deserialize(deserializer) else{
|
||||
return Ok(None);
|
||||
};
|
||||
let Ok(file_engine) = SerializedFileEngine::deserialize(deserializer) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let file_engine = std::sync::Arc::new(file_engine);
|
||||
Ok(Some(file_engine))
|
||||
|
||||
@@ -25,6 +25,7 @@ const bool_attrs = {
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
|
||||
export function setAttributeInner(node, field, value, ns) {
|
||||
|
||||
@@ -163,6 +163,7 @@ mod js {
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
function truthy(val) {
|
||||
return val === "true" || val === true;
|
||||
|
||||
@@ -11,13 +11,14 @@ pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket {
|
||||
.sink_map_err(|_| LiveViewError::SendingFailed)
|
||||
}
|
||||
|
||||
fn transform_rx(message: Result<Message, axum::Error>) -> Result<String, LiveViewError> {
|
||||
fn transform_rx(message: Result<Message, axum::Error>) -> Result<Vec<u8>, LiveViewError> {
|
||||
message
|
||||
.map_err(|_| LiveViewError::SendingFailed)?
|
||||
.into_text()
|
||||
.map(|s| s.into_bytes())
|
||||
.map_err(|_| LiveViewError::SendingFailed)
|
||||
}
|
||||
|
||||
async fn transform_tx(message: String) -> Result<Message, axum::Error> {
|
||||
Ok(Message::Text(message))
|
||||
async fn transform_tx(message: Vec<u8>) -> Result<Message, axum::Error> {
|
||||
Ok(Message::Text(String::from_utf8_lossy(&message).to_string()))
|
||||
}
|
||||
@@ -12,14 +12,12 @@ pub fn salvo_socket(ws: WebSocket) -> impl LiveViewSocket {
|
||||
.sink_map_err(|_| LiveViewError::SendingFailed)
|
||||
}
|
||||
|
||||
fn transform_rx(message: Result<Message, salvo::Error>) -> Result<String, LiveViewError> {
|
||||
fn transform_rx(message: Result<Message, salvo::Error>) -> Result<Vec<u8>, LiveViewError> {
|
||||
let as_bytes = message.map_err(|_| LiveViewError::SendingFailed)?;
|
||||
|
||||
let msg = String::from_utf8(as_bytes.into_bytes()).map_err(|_| LiveViewError::SendingFailed)?;
|
||||
|
||||
Ok(msg)
|
||||
Ok(as_bytes.into())
|
||||
}
|
||||
|
||||
async fn transform_tx(message: String) -> Result<Message, salvo::Error> {
|
||||
Ok(Message::text(message))
|
||||
async fn transform_tx(message: Vec<u8>) -> Result<Message, salvo::Error> {
|
||||
Ok(Message::text(String::from_utf8_lossy(&message).to_string()))
|
||||
}
|
||||
@@ -11,18 +11,15 @@ pub fn warp_socket(ws: WebSocket) -> impl LiveViewSocket {
|
||||
.sink_map_err(|_| LiveViewError::SendingFailed)
|
||||
}
|
||||
|
||||
fn transform_rx(message: Result<Message, warp::Error>) -> Result<String, LiveViewError> {
|
||||
fn transform_rx(message: Result<Message, warp::Error>) -> Result<Vec<u8>, LiveViewError> {
|
||||
// destructure the message into the buffer we got from warp
|
||||
let msg = message
|
||||
.map_err(|_| LiveViewError::SendingFailed)?
|
||||
.into_bytes();
|
||||
|
||||
// transform it back into a string, saving us the allocation
|
||||
let msg = String::from_utf8(msg).map_err(|_| LiveViewError::SendingFailed)?;
|
||||
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
async fn transform_tx(message: String) -> Result<Message, warp::Error> {
|
||||
Ok(Message::text(message))
|
||||
async fn transform_tx(message: Vec<u8>) -> Result<Message, warp::Error> {
|
||||
Ok(Message::text(String::from_utf8_lossy(&message).to_string()))
|
||||
}
|
||||
@@ -87,16 +87,16 @@ impl LiveViewPool {
|
||||
/// }
|
||||
/// ```
|
||||
pub trait LiveViewSocket:
|
||||
SinkExt<String, Error = LiveViewError>
|
||||
+ StreamExt<Item = Result<String, LiveViewError>>
|
||||
SinkExt<Vec<u8>, Error = LiveViewError>
|
||||
+ StreamExt<Item = Result<Vec<u8>, LiveViewError>>
|
||||
+ Send
|
||||
+ 'static
|
||||
{
|
||||
}
|
||||
|
||||
impl<S> LiveViewSocket for S where
|
||||
S: SinkExt<String, Error = LiveViewError>
|
||||
+ StreamExt<Item = Result<String, LiveViewError>>
|
||||
S: SinkExt<Vec<u8>, Error = LiveViewError>
|
||||
+ StreamExt<Item = Result<Vec<u8>, LiveViewError>>
|
||||
+ Send
|
||||
+ 'static
|
||||
{
|
||||
@@ -126,7 +126,7 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
||||
pin_mut!(ws);
|
||||
|
||||
// send the initial render to the client
|
||||
ws.send(edits).await?;
|
||||
ws.send(edits.into_bytes()).await?;
|
||||
|
||||
// Create the a proxy for query engine
|
||||
let (query_tx, mut query_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||
@@ -156,11 +156,11 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
||||
evt = ws.next() => {
|
||||
match evt.as_ref().map(|o| o.as_deref()) {
|
||||
// respond with a pong every ping to keep the websocket alive
|
||||
Some(Ok("__ping__")) => {
|
||||
ws.send("__pong__".to_string()).await?;
|
||||
Some(Ok(b"__ping__")) => {
|
||||
ws.send(b"__pong__".to_vec()).await?;
|
||||
}
|
||||
Some(Ok(evt)) => {
|
||||
if let Ok(message) = serde_json::from_str::<IpcMessage>(evt) {
|
||||
if let Ok(message) = serde_json::from_str::<IpcMessage>(&String::from_utf8_lossy(evt)) {
|
||||
match message {
|
||||
IpcMessage::Event(evt) => {
|
||||
// Intercept the mounted event and insert a custom element type
|
||||
@@ -196,7 +196,7 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
||||
|
||||
// handle any new queries
|
||||
Some(query) = query_rx.recv() => {
|
||||
ws.send(serde_json::to_string(&ClientUpdate::Query(query)).unwrap()).await?;
|
||||
ws.send(serde_json::to_string(&ClientUpdate::Query(query)).unwrap().into_bytes()).await?;
|
||||
}
|
||||
|
||||
Some(msg) = hot_reload_wait => {
|
||||
@@ -218,8 +218,12 @@ pub async fn run(mut vdom: VirtualDom, ws: impl LiveViewSocket) -> Result<(), Li
|
||||
.render_with_deadline(tokio::time::sleep(Duration::from_millis(10)))
|
||||
.await;
|
||||
|
||||
ws.send(serde_json::to_string(&ClientUpdate::Edits(edits)).unwrap())
|
||||
.await?;
|
||||
ws.send(
|
||||
serde_json::to_string(&ClientUpdate::Edits(edits))
|
||||
.unwrap()
|
||||
.into_bytes(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,9 @@ impl Button {
|
||||
fn write_value(&self, rdom: &mut RealDom) {
|
||||
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
||||
let node_type = text.node_type_mut();
|
||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Text(mut text) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
*text.text_mut() = self.value.clone();
|
||||
}
|
||||
}
|
||||
@@ -111,7 +113,9 @@ impl CustomElement for Button {
|
||||
|
||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||
let node_type = root.node_type();
|
||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
||||
let NodeType::Element(el) = &*node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
|
||||
let value = el
|
||||
.attributes
|
||||
@@ -146,7 +150,9 @@ impl CustomElement for Button {
|
||||
AttributeMask::All => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
self.update_value_attr(&el);
|
||||
self.update_size_attr(&mut el);
|
||||
}
|
||||
@@ -155,7 +161,9 @@ impl CustomElement for Button {
|
||||
AttributeMask::Some(attrs) => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
if attrs.contains("width") || attrs.contains("height") {
|
||||
self.update_size_attr(&mut el);
|
||||
}
|
||||
|
||||
@@ -94,14 +94,18 @@ impl CheckBox {
|
||||
fn write_value(&self, mut root: NodeMut) {
|
||||
let single_char = {
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element( el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
Self::width(&el) == "1px" || Self::height(&el) == "1px"
|
||||
};
|
||||
let rdom = root.real_dom_mut();
|
||||
|
||||
if let Some(mut text) = rdom.get_mut(self.text_id) {
|
||||
let node_type = text.node_type_mut();
|
||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Text(mut text) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
let value = if single_char {
|
||||
if self.checked {
|
||||
"☑"
|
||||
@@ -156,7 +160,9 @@ impl CustomElement for CheckBox {
|
||||
|
||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||
let node_type = root.node_type();
|
||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
||||
let NodeType::Element(el) = &*node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
|
||||
let value = el
|
||||
.attributes
|
||||
@@ -197,7 +203,9 @@ impl CustomElement for CheckBox {
|
||||
AttributeMask::All => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
self.update_value_attr(&el);
|
||||
self.update_size_attr(&mut el);
|
||||
self.update_checked_attr(&el);
|
||||
@@ -207,7 +215,9 @@ impl CustomElement for CheckBox {
|
||||
AttributeMask::Some(attrs) => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
if attrs.contains("width") || attrs.contains("height") {
|
||||
self.update_size_attr(&mut el);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,9 @@ impl CustomElement for Input {
|
||||
}
|
||||
|
||||
let node_type = root.node_type();
|
||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
||||
let NodeType::Element(el) = &*node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
let input_type = el
|
||||
.attributes
|
||||
.get(&OwnedAttributeDiscription {
|
||||
|
||||
@@ -163,7 +163,9 @@ impl Slider {
|
||||
|
||||
if let Some(mut div) = rdom.get_mut(self.pre_cursor_div) {
|
||||
let node_type = div.node_type_mut();
|
||||
let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut element) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
element.set_attribute(
|
||||
OwnedAttributeDiscription {
|
||||
name: "width".to_string(),
|
||||
@@ -175,7 +177,9 @@ impl Slider {
|
||||
|
||||
if let Some(mut div) = rdom.get_mut(self.post_cursor_div) {
|
||||
let node_type = div.node_type_mut();
|
||||
let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut element) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
element.set_attribute(
|
||||
OwnedAttributeDiscription {
|
||||
name: "width".to_string(),
|
||||
@@ -259,7 +263,9 @@ impl CustomElement for Slider {
|
||||
|
||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||
let node_type = root.node_type();
|
||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
||||
let NodeType::Element(el) = &*node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
|
||||
let value = el.attributes.get(&OwnedAttributeDiscription {
|
||||
name: "value".to_string(),
|
||||
@@ -390,7 +396,9 @@ impl CustomElement for Slider {
|
||||
AttributeMask::All => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
self.update_value_attr(&el);
|
||||
self.update_size_attr(&mut el);
|
||||
self.update_max_attr(&el);
|
||||
@@ -403,7 +411,9 @@ impl CustomElement for Slider {
|
||||
AttributeMask::Some(attrs) => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
if attrs.contains("width") || attrs.contains("height") {
|
||||
self.update_size_attr(&mut el);
|
||||
}
|
||||
|
||||
@@ -143,19 +143,25 @@ impl<C: TextLikeController> TextLike<C> {
|
||||
|
||||
if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) {
|
||||
let node_type = text.node_type_mut();
|
||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Text(mut text) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
*text.text_mut() = self.controller.display_text(text_before_first_cursor);
|
||||
}
|
||||
|
||||
if let Some(mut text) = rdom.get_mut(self.highlighted_text) {
|
||||
let node_type = text.node_type_mut();
|
||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Text(mut text) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
*text.text_mut() = self.controller.display_text(text_highlighted);
|
||||
}
|
||||
|
||||
if let Some(mut text) = rdom.get_mut(self.post_cursor_text) {
|
||||
let node_type = text.node_type_mut();
|
||||
let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Text(mut text) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
*text.text_mut() = self.controller.display_text(text_after_second_cursor);
|
||||
}
|
||||
|
||||
@@ -288,7 +294,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||
|
||||
fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
|
||||
let node_type = root.node_type();
|
||||
let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
|
||||
let NodeType::Element(el) = &*node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
|
||||
let value = el
|
||||
.attributes
|
||||
@@ -370,7 +378,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||
AttributeMask::All => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
self.update_value_attr(&el);
|
||||
self.update_size_attr(&mut el);
|
||||
self.update_max_width_attr(&el);
|
||||
@@ -381,7 +391,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
|
||||
AttributeMask::Some(attrs) => {
|
||||
{
|
||||
let node_type = root.node_type_mut();
|
||||
let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
|
||||
let NodeTypeMut::Element(mut el) = node_type else {
|
||||
panic!("input must be an element")
|
||||
};
|
||||
if attrs.contains("width") || attrs.contains("height") {
|
||||
self.update_size_attr(&mut el);
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ mod segment;
|
||||
/// Route Segments:
|
||||
/// 1. Static Segments: "/static"
|
||||
/// 2. Dynamic Segments: "/:dynamic" (where dynamic has a type that is FromStr in all child Variants)
|
||||
/// 3. Catch all Segments: "/:...segments" (where segments has a type that is FromSegments in all child Variants)
|
||||
/// 3. Catch all Segments: "/:..segments" (where segments has a type that is FromSegments in all child Variants)
|
||||
/// 4. Query Segments: "/?:query" (where query has a type that is FromQuery in all child Variants)
|
||||
///
|
||||
/// Routes are matched:
|
||||
/// 1. By there specificity this order: Query Routes ("/?:query"), Static Routes ("/route"), Dynamic Routes ("/:route"), Catch All Routes ("/:...route")
|
||||
/// 1. By there specificity this order: Query Routes ("/?:query"), Static Routes ("/route"), Dynamic Routes ("/:route"), Catch All Routes ("/:..route")
|
||||
/// 2. By the order they are defined in the enum
|
||||
///
|
||||
/// All features:
|
||||
@@ -369,13 +369,13 @@ impl RouteEnum {
|
||||
let (exclude, layout): (bool, Layout) = attr.parse_args_with(parser)?;
|
||||
|
||||
if exclude {
|
||||
let Some(layout_index) =
|
||||
layouts.iter().position(|l| l.comp == layout.comp) else {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"Attempted to exclude a layout that does not exist",
|
||||
));
|
||||
};
|
||||
let Some(layout_index) = layouts.iter().position(|l| l.comp == layout.comp)
|
||||
else {
|
||||
return Err(syn::Error::new(
|
||||
Span::call_site(),
|
||||
"Attempted to exclude a layout that does not exist",
|
||||
));
|
||||
};
|
||||
excluded.push(LayoutId(layout_index));
|
||||
} else {
|
||||
let layout_index = layouts.len();
|
||||
|
||||
@@ -126,7 +126,7 @@ impl Route {
|
||||
None => {
|
||||
return Err(syn::Error::new_spanned(
|
||||
variant.clone(),
|
||||
"Routable variants with a #[child(...)] attribute must have a field named \"child\" or a field with a #[child] attribute",
|
||||
"Routable variants with a #[child(..)] attribute must have a field named \"child\" or a field with a #[child] attribute",
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -134,14 +134,14 @@ impl Route {
|
||||
_ => {
|
||||
return Err(syn::Error::new_spanned(
|
||||
variant.clone(),
|
||||
"Routable variants with a #[child(...)] attribute must have named fields",
|
||||
"Routable variants with a #[child(..)] attribute must have named fields",
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(syn::Error::new_spanned(
|
||||
variant.clone(),
|
||||
"Routable variants must either have a #[route(...)] attribute or a #[child(...)] attribute",
|
||||
"Routable variants must either have a #[route(..)] attribute or a #[child(..)] attribute",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,10 +150,10 @@ pub fn parse_route_segments<'a>(
|
||||
|
||||
while let Some(segment) = iterator.next() {
|
||||
if let Some(segment) = segment.strip_prefix(':') {
|
||||
let spread = segment.starts_with("...");
|
||||
let spread = segment.starts_with("..");
|
||||
|
||||
let ident = if spread {
|
||||
segment[3..].to_string()
|
||||
segment[2..].to_string()
|
||||
} else {
|
||||
segment.to_string()
|
||||
};
|
||||
|
||||
@@ -10,8 +10,6 @@ mod rt;
|
||||
use dioxus_core::ScopeState;
|
||||
pub use rt::*;
|
||||
|
||||
use crate::rt::claim_rt;
|
||||
|
||||
pub fn use_init_signal_rt(cx: &ScopeState) {
|
||||
cx.use_hook(|| {
|
||||
let rt = claim_rt(cx.schedule_update_any());
|
||||
@@ -96,11 +94,7 @@ impl<T: Clone + 'static> std::ops::Deref for Signal<T> {
|
||||
|
||||
impl<T> std::clone::Clone for Signal<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
t: PhantomData,
|
||||
id: self.id,
|
||||
rt: self.rt,
|
||||
}
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ impl WebsysDom {
|
||||
// make sure we set the root node ids even if the node is not dynamic
|
||||
set_node(
|
||||
hydrated,
|
||||
vnode.root_ids.get(i).ok_or(VNodeNotInitialized)?,
|
||||
*vnode.root_ids.borrow().get(i).ok_or(VNodeNotInitialized)?,
|
||||
current_child.clone()?,
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user