mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-30 08:00:21 +00:00
feat: arbitrary attributes
This commit is contained in:
parent
f2c48c5d90
commit
356f37e9ee
7 changed files with 298 additions and 9 deletions
265
packages/core/src/arbitrary_value.rs
Normal file
265
packages/core/src/arbitrary_value.rs
Normal file
|
@ -0,0 +1,265 @@
|
|||
use std::fmt::Formatter;
|
||||
|
||||
// trying to keep values at 3 bytes
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AttributeValue<'a> {
|
||||
Text(&'a str),
|
||||
Float32(f32),
|
||||
Float64(f64),
|
||||
Int32(i32),
|
||||
Int64(i64),
|
||||
Uint32(u32),
|
||||
Uint64(u64),
|
||||
Bool(bool),
|
||||
ColorRGB(u8, u8, u8),
|
||||
ColorRGBA(u8, u8, u8, u8),
|
||||
ColorHex(u32),
|
||||
ColorHexAlpha(u32, u8),
|
||||
Vec3Float(f32, f32, f32),
|
||||
Vec3Int(i32, i32, i32),
|
||||
Vec3Uint(u32, u32, u32),
|
||||
Vec4Float(f32, f32, f32, f32),
|
||||
Vec4Int(i32, i32, i32, i32),
|
||||
Vec4Uint(u32, u32, u32, u32),
|
||||
Bytes(&'a [u8]),
|
||||
Any(ArbitraryAttributeValue<'a>),
|
||||
}
|
||||
|
||||
impl<'a> AttributeValue<'a> {
|
||||
pub fn is_truthy(&self) -> bool {
|
||||
match self {
|
||||
AttributeValue::Text(t) => *t == "true",
|
||||
AttributeValue::Bool(t) => *t,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_falsy(&self) -> bool {
|
||||
match self {
|
||||
AttributeValue::Text(t) => *t == "false",
|
||||
AttributeValue::Bool(t) => !(*t),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Display for AttributeValue<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AttributeValue::Text(a) => write!(f, "{}", a),
|
||||
AttributeValue::Float32(a) => write!(f, "{}", a),
|
||||
AttributeValue::Float64(a) => write!(f, "{}", a),
|
||||
AttributeValue::Int32(a) => write!(f, "{}", a),
|
||||
AttributeValue::Int64(a) => write!(f, "{}", a),
|
||||
AttributeValue::Uint32(a) => write!(f, "{}", a),
|
||||
AttributeValue::Uint64(a) => write!(f, "{}", a),
|
||||
AttributeValue::Bool(a) => write!(f, "{}", a),
|
||||
AttributeValue::ColorRGB(_, _, _) => todo!(),
|
||||
AttributeValue::ColorRGBA(_, _, _, _) => todo!(),
|
||||
AttributeValue::ColorHex(_) => todo!(),
|
||||
AttributeValue::ColorHexAlpha(_, _) => todo!(),
|
||||
AttributeValue::Vec3Float(_, _, _) => todo!(),
|
||||
AttributeValue::Vec3Int(_, _, _) => todo!(),
|
||||
AttributeValue::Vec3Uint(_, _, _) => todo!(),
|
||||
AttributeValue::Vec4Float(_, _, _, _) => todo!(),
|
||||
AttributeValue::Vec4Int(_, _, _, _) => todo!(),
|
||||
AttributeValue::Vec4Uint(_, _, _, _) => todo!(),
|
||||
AttributeValue::Bytes(_) => todo!(),
|
||||
AttributeValue::Any(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ArbitraryAttributeValue<'a> {
|
||||
pub value: &'a dyn std::any::Any,
|
||||
pub cmp: fn(&'a dyn std::any::Any, &'a dyn std::any::Any) -> bool,
|
||||
}
|
||||
|
||||
impl PartialEq for ArbitraryAttributeValue<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(self.cmp)(self.value, other.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ArbitraryAttributeValue<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ArbitraryAttributeValue").finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'a> serde::Serialize for ArbitraryAttributeValue<'a> {
|
||||
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
panic!("ArbitraryAttributeValue should not be serialized")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'de, 'a> serde::Deserialize<'de> for &'a ArbitraryAttributeValue<'a> {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
panic!("ArbitraryAttributeValue is not deserializable!")
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<'de, 'a> serde::Deserialize<'de> for ArbitraryAttributeValue<'a> {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
panic!("ArbitraryAttributeValue is not deserializable!")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AttributeValue<'a> {
|
||||
pub fn as_text(&self) -> Option<&'a str> {
|
||||
match self {
|
||||
AttributeValue::Text(s) => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float32(&self) -> Option<f32> {
|
||||
match self {
|
||||
AttributeValue::Float32(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float64(&self) -> Option<f64> {
|
||||
match self {
|
||||
AttributeValue::Float64(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int32(&self) -> Option<i32> {
|
||||
match self {
|
||||
AttributeValue::Int32(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_int64(&self) -> Option<i64> {
|
||||
match self {
|
||||
AttributeValue::Int64(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_uint32(&self) -> Option<u32> {
|
||||
match self {
|
||||
AttributeValue::Uint32(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_uint64(&self) -> Option<u64> {
|
||||
match self {
|
||||
AttributeValue::Uint64(i) => Some(*i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bool(&self) -> Option<bool> {
|
||||
match self {
|
||||
AttributeValue::Bool(b) => Some(*b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_color_rgb(&self) -> Option<(u8, u8, u8)> {
|
||||
match self {
|
||||
AttributeValue::ColorRGB(r, g, b) => Some((*r, *g, *b)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_color_rgba(&self) -> Option<(u8, u8, u8, u8)> {
|
||||
match self {
|
||||
AttributeValue::ColorRGBA(r, g, b, a) => Some((*r, *g, *b, *a)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_color_hex(&self) -> Option<u32> {
|
||||
match self {
|
||||
AttributeValue::ColorHex(c) => Some(*c),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_color_hex_alpha(&self) -> Option<(u32, u8)> {
|
||||
match self {
|
||||
AttributeValue::ColorHexAlpha(c, a) => Some((*c, *a)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_float(&self) -> Option<(f32, f32, f32)> {
|
||||
match self {
|
||||
AttributeValue::Vec3Float(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_int(&self) -> Option<(i32, i32, i32)> {
|
||||
match self {
|
||||
AttributeValue::Vec3Int(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec3_uint(&self) -> Option<(u32, u32, u32)> {
|
||||
match self {
|
||||
AttributeValue::Vec3Uint(x, y, z) => Some((*x, *y, *z)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_float(&self) -> Option<(f32, f32, f32, f32)> {
|
||||
match self {
|
||||
AttributeValue::Vec4Float(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_int(&self) -> Option<(i32, i32, i32, i32)> {
|
||||
match self {
|
||||
AttributeValue::Vec4Int(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vec4_uint(&self) -> Option<(u32, u32, u32, u32)> {
|
||||
match self {
|
||||
AttributeValue::Vec4Uint(x, y, z, w) => Some((*x, *y, *z, *w)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> Option<&[u8]> {
|
||||
match self {
|
||||
AttributeValue::Bytes(b) => Some(b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_any(&self) -> Option<&'a ArbitraryAttributeValue> {
|
||||
match self {
|
||||
AttributeValue::Any(a) => Some(a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_attribute_value_size() {
|
||||
assert_eq!(std::mem::size_of::<AttributeValue<'_>>(), 24);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
pub(crate) mod arbitrary_value;
|
||||
pub(crate) mod diff;
|
||||
pub(crate) mod events;
|
||||
pub(crate) mod lazynodes;
|
||||
|
@ -13,6 +14,7 @@ pub(crate) mod util;
|
|||
pub(crate) mod virtual_dom;
|
||||
|
||||
pub(crate) mod innerlude {
|
||||
pub use crate::arbitrary_value::*;
|
||||
pub use crate::events::*;
|
||||
pub use crate::lazynodes::*;
|
||||
pub use crate::mutations::*;
|
||||
|
|
|
@ -167,8 +167,9 @@ pub enum DomEdit<'bump> {
|
|||
field: &'static str,
|
||||
|
||||
/// The value of the attribute.
|
||||
value: &'bump str,
|
||||
value: AttributeValue<'bump>,
|
||||
|
||||
// value: &'bump str,
|
||||
/// The (optional) namespace of the attribute.
|
||||
/// For instance, "style" is in the "style" namespace.
|
||||
ns: Option<&'bump str>,
|
||||
|
@ -286,7 +287,7 @@ impl<'a> Mutations<'a> {
|
|||
self.edits.push(SetText { text, root });
|
||||
}
|
||||
|
||||
pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute, root: u64) {
|
||||
pub(crate) fn set_attribute(&mut self, attribute: &'a Attribute<'a>, root: u64) {
|
||||
let Attribute {
|
||||
name,
|
||||
value,
|
||||
|
@ -296,7 +297,7 @@ impl<'a> Mutations<'a> {
|
|||
|
||||
self.edits.push(SetAttribute {
|
||||
field: name,
|
||||
value,
|
||||
value: value.clone(),
|
||||
ns: *namespace,
|
||||
root,
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! cheap and *very* fast to construct - building a full tree should be quick.
|
||||
|
||||
use crate::{
|
||||
innerlude::{ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState},
|
||||
innerlude::{ComponentPtr, Element, Properties, Scope, ScopeId, ScopeState, AttributeValue},
|
||||
lazynodes::LazyNodes,
|
||||
AnyEvent, Component,
|
||||
};
|
||||
|
@ -339,7 +339,7 @@ pub struct Attribute<'a> {
|
|||
pub name: &'static str,
|
||||
|
||||
/// The value of the attribute.
|
||||
pub value: &'a str,
|
||||
pub value: AttributeValue<'a>,
|
||||
|
||||
/// An indication if this attribute can be ignored during diffing
|
||||
///
|
||||
|
@ -357,6 +357,7 @@ pub struct Attribute<'a> {
|
|||
pub namespace: Option<&'static str>,
|
||||
}
|
||||
|
||||
|
||||
/// An event listener.
|
||||
/// IE onclick, onkeydown, etc
|
||||
pub struct Listener<'bump> {
|
||||
|
@ -610,6 +611,24 @@ impl<'a> NodeFactory<'a> {
|
|||
is_volatile: bool,
|
||||
) -> Attribute<'a> {
|
||||
let (value, is_static) = self.raw_text(val);
|
||||
Attribute {
|
||||
name,
|
||||
value: AttributeValue::Text(value),
|
||||
is_static,
|
||||
namespace,
|
||||
is_volatile,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`Attribute`] using non-arguments
|
||||
pub fn custom_attr(
|
||||
&self,
|
||||
name: &'static str,
|
||||
value: AttributeValue<'a>,
|
||||
namespace: Option<&'static str>,
|
||||
is_volatile: bool,
|
||||
is_static: bool,
|
||||
) -> Attribute<'a> {
|
||||
Attribute {
|
||||
name,
|
||||
value,
|
||||
|
|
|
@ -186,7 +186,9 @@ impl<'a> TextRenderer<'a, '_> {
|
|||
while let Some(attr) = attr_iter.next() {
|
||||
match attr.namespace {
|
||||
None => match attr.name {
|
||||
"dangerous_inner_html" => inner_html = Some(attr.value),
|
||||
"dangerous_inner_html" => {
|
||||
inner_html = Some(attr.value.as_text().unwrap())
|
||||
}
|
||||
"allowfullscreen"
|
||||
| "allowpaymentrequest"
|
||||
| "async"
|
||||
|
@ -213,7 +215,7 @@ impl<'a> TextRenderer<'a, '_> {
|
|||
| "reversed"
|
||||
| "selected"
|
||||
| "truespeed" => {
|
||||
if attr.value != "false" {
|
||||
if attr.value.is_truthy() {
|
||||
write!(f, " {}=\"{}\"", attr.name, attr.value)?
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
|
|||
dioxus-core = { path = "../core", version = "^0.2.1" }
|
||||
dioxus-html = { path = "../html", version = "^0.2.1", features = ["wasm-bind"] }
|
||||
dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1", features = [
|
||||
"web",
|
||||
"web"
|
||||
] }
|
||||
|
||||
js-sys = "0.3.56"
|
||||
|
|
|
@ -146,7 +146,7 @@ impl WebsysDom {
|
|||
value,
|
||||
ns,
|
||||
} => {
|
||||
let value = serde_wasm_bindgen::to_value(value).unwrap();
|
||||
let value = serde_wasm_bindgen::to_value(&value).unwrap();
|
||||
self.interpreter.SetAttribute(root, field, value, ns)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue