Skip to content

Commit

Permalink
xilem_web: Rewrite modifiers (Attributes, Classes and Styles), …
Browse files Browse the repository at this point in the history
…and cleanup/extend docs (#699)

Previously the modifier systems had design issues i.e. bugs (non-deleted
styles/classes/attributes), and were unnecessary complex.
This aims to solve this (partly) by not using separate traits, but
concrete types and a different mechanism that is closer to how
`ElementSplice` works.

There's a few fundamental properties that composable type-based
modifiers need to support to avoid surprising/buggy behavior:

* Minimize actual changes to the underlying element, as DOM traffic is
expensive.
* Be compatible to memoization: e.g. a `Rotate` view should still be
applicable to possibly memoized transform values of the underlying
element.
* Recreation when the underlying element has changed (e.g. with a change
of variants of a `OneOf`).

To support all this, the modifier system needs to retain modifiers for
each modifier-view, and track its changes of the corresponding view.
Previously all elements were directly written and separated with markers
into a `Vec` to limit the boundaries of such views, but this had issues,
when e.g. all modifiers were deleted (e.g. clearing a `Vec` of classes),
by not reacting to this (I noticed that issue in the todomvc example
with the footer).

With this PR, the count of modifiers of a modifier-view are directly
stored either (hardcoded) in the view impl or its view state, which
cleans up the concrete modifier elements (such as `AttributeModifier`,
not including a separate `Marker` variant), and makes it less prone for
errors (and is slightly less memory-intensive).

The API to use these modifiers in modifier-views was also redesigned to
hopefully be more straight-forward/idiomatic. But as mentioned above
there's still challenges, which introduce complexity (which I'd like to
hide at least for simpler cases than these modifiers, likely in a future
PR).
All of this should now be documented in the new `modifier` module, where
now the modifiers `Attributes`, `Classes` and `Styles` reside. Other
views (like events) may also end up there...

One interesting aspect compared to the previous system is the use of a
new trait `With` for modifiers.
Instead of (roughly) `Element: WithStyle`, it works with `Element:
With<Styles>`.
This prevents all kinds of reimplementations of something like
`WithStyle` for elements.
This gets especially visible in the `one_of` module, which now can be
covered by a single blanket implementation.

Further the cargo-feature "hydration" was deleted, as it causes more
headaches to maintain than it really brings benefits (minimally less
binary size), depending on the future, it may or may not make sense to
reintroduce this.
  • Loading branch information
Philipp-M authored Oct 23, 2024
1 parent 30cb1e0 commit 53a5354
Show file tree
Hide file tree
Showing 25 changed files with 2,173 additions and 2,171 deletions.
27 changes: 27 additions & 0 deletions xilem_core/src/views/one_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,33 @@ where
}
}

impl<T, A, B, C, D, E, F, G, H, I> AsMut<T> for OneOf<A, B, C, D, E, F, G, H, I>
where
A: AsMut<T>,
B: AsMut<T>,
C: AsMut<T>,
D: AsMut<T>,
E: AsMut<T>,
F: AsMut<T>,
G: AsMut<T>,
H: AsMut<T>,
I: AsMut<T>,
{
fn as_mut(&mut self) -> &mut T {
match self {
OneOf::A(e) => <A as AsMut<T>>::as_mut(e),
OneOf::B(e) => <B as AsMut<T>>::as_mut(e),
OneOf::C(e) => <C as AsMut<T>>::as_mut(e),
OneOf::D(e) => <D as AsMut<T>>::as_mut(e),
OneOf::E(e) => <E as AsMut<T>>::as_mut(e),
OneOf::F(e) => <F as AsMut<T>>::as_mut(e),
OneOf::G(e) => <G as AsMut<T>>::as_mut(e),
OneOf::H(e) => <H as AsMut<T>>::as_mut(e),
OneOf::I(e) => <I as AsMut<T>>::as_mut(e),
}
}
}

/// A context type which can support [`OneOf9`] and [related views](super::one_of).
///
/// This should be implemented by users of Xilem Core.
Expand Down
3 changes: 1 addition & 2 deletions xilem_web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,6 @@ features = [
]

[features]
default = ["hydration"]
hydration = []
default = []
# This interns some often used strings, such as element tags ("div" etc.), which slightly improves performance when creating elements at the cost of a bigger wasm binary
intern_strings = ["wasm-bindgen/enable-interning"]
1 change: 0 additions & 1 deletion xilem_web/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ where
&inner.root,
inner.ctx.fragment.clone(),
false,
#[cfg(feature = "hydration")]
false,
);
new_fragment.seq_rebuild(
Expand Down
Loading

0 comments on commit 53a5354

Please sign in to comment.