mirror of https://github.com/linebender/xilem
Use `ViewMarker` trait instead of the generic `Marker` to allow `impl ViewSequence` as return type (#472)
This allows returning `impl ViewSequence` as this was previously not possibly as the `Marker` generic parameter couldn't be named (easily) in `ViewSequence<..., Marker>`. This also provides specialized `ViewSequence`s for xilem (`WidgetViewSequence` and `FlexSequence`) as well as for xilem_web (`DomFragment`). Additional doc-tests/documentation and a small example (in `counter`) for xilem_web is provided as well. This has the drawback to not being able to reeimplement `ViewSequence` for types that already implement `View`, which was previously possible (as seen by the now removed `NoElementView` `ViewSequence` implementation). And additionally by introducing more boilerplate by having to implement `ViewMarker` for every type that implements `View`. --------- Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
This commit is contained in:
parent
544a4a1ca9
commit
24427bbb44
|
@ -5,7 +5,7 @@ use masonry::widget::{CrossAxisAlignment, MainAxisAlignment};
|
||||||
use winit::dpi::LogicalSize;
|
use winit::dpi::LogicalSize;
|
||||||
use winit::error::EventLoopError;
|
use winit::error::EventLoopError;
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
use xilem::view::Flex;
|
use xilem::view::{Flex, FlexSequence};
|
||||||
use xilem::EventLoopBuilder;
|
use xilem::EventLoopBuilder;
|
||||||
use xilem::{
|
use xilem::{
|
||||||
view::{button, flex, label, sized_box, Axis, FlexExt as _, FlexSpacer},
|
view::{button, flex, label, sized_box, Axis, FlexExt as _, FlexSpacer},
|
||||||
|
@ -254,7 +254,7 @@ fn app_logic(data: &mut Calculator) -> impl WidgetView<Calculator> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a horizontal centered flex row designed for the display portion of the calculator.
|
/// Creates a horizontal centered flex row designed for the display portion of the calculator.
|
||||||
pub fn centered_flex_row<Seq, Marker>(sequence: Seq) -> Flex<Seq, Marker> {
|
pub fn centered_flex_row<State, Seq: FlexSequence<State>>(sequence: Seq) -> Flex<Seq, State> {
|
||||||
flex(sequence)
|
flex(sequence)
|
||||||
.direction(Axis::Horizontal)
|
.direction(Axis::Horizontal)
|
||||||
.cross_axis_alignment(CrossAxisAlignment::Center)
|
.cross_axis_alignment(CrossAxisAlignment::Center)
|
||||||
|
@ -263,7 +263,7 @@ pub fn centered_flex_row<Seq, Marker>(sequence: Seq) -> Flex<Seq, Marker> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a horizontal filled flex row designed to be used in a grid.
|
/// Creates a horizontal filled flex row designed to be used in a grid.
|
||||||
pub fn flex_row<Seq, Marker>(sequence: Seq) -> Flex<Seq, Marker> {
|
pub fn flex_row<State, Seq: FlexSequence<State>>(sequence: Seq) -> Flex<Seq, State> {
|
||||||
flex(sequence)
|
flex(sequence)
|
||||||
.direction(Axis::Horizontal)
|
.direction(Axis::Horizontal)
|
||||||
.cross_axis_alignment(CrossAxisAlignment::Fill)
|
.cross_axis_alignment(CrossAxisAlignment::Fill)
|
||||||
|
|
|
@ -26,7 +26,7 @@ enum CountMessage {
|
||||||
|
|
||||||
// `map_action()` is basically how elm works, i.e. provide a message that the parent view has to handle to update the state.
|
// `map_action()` is basically how elm works, i.e. provide a message that the parent view has to handle to update the state.
|
||||||
// In this case the parent adjusts the count that is given to this view according to the message
|
// In this case the parent adjusts the count that is given to this view according to the message
|
||||||
fn elm_counter<T>(count: i32) -> impl WidgetView<T, CountMessage> {
|
fn elm_counter<T: 'static>(count: i32) -> impl WidgetView<T, CountMessage> {
|
||||||
flex((
|
flex((
|
||||||
label(format!("elm count: {count}")),
|
label(format!("elm count: {count}")),
|
||||||
button("+", |_| CountMessage::Increment),
|
button("+", |_| CountMessage::Increment),
|
||||||
|
|
|
@ -109,6 +109,7 @@ fn app_logic(data: &mut AppData) -> impl WidgetView<AppData> {
|
||||||
|
|
||||||
fn toggleable(data: &mut AppData) -> impl WidgetView<AppData> {
|
fn toggleable(data: &mut AppData) -> impl WidgetView<AppData> {
|
||||||
if data.active {
|
if data.active {
|
||||||
|
fork(
|
||||||
flex((
|
flex((
|
||||||
button("Deactivate", |data: &mut AppData| {
|
button("Deactivate", |data: &mut AppData| {
|
||||||
data.active = false;
|
data.active = false;
|
||||||
|
@ -116,9 +117,10 @@ fn toggleable(data: &mut AppData) -> impl WidgetView<AppData> {
|
||||||
button("Unlimited Power", |data: &mut AppData| {
|
button("Unlimited Power", |data: &mut AppData| {
|
||||||
data.count = -1_000_000;
|
data.count = -1_000_000;
|
||||||
}),
|
}),
|
||||||
run_once(|| tracing::warn!("The pathway to unlimited power has been revealed")),
|
|
||||||
))
|
))
|
||||||
.direction(Axis::Horizontal)
|
.direction(Axis::Horizontal),
|
||||||
|
run_once(|| tracing::warn!("The pathway to unlimited power has been revealed")),
|
||||||
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
} else {
|
} else {
|
||||||
button("Activate", |data: &mut AppData| data.active = true).boxed()
|
button("Activate", |data: &mut AppData| data.active = true).boxed()
|
||||||
|
|
|
@ -19,6 +19,7 @@ use winit::{
|
||||||
};
|
};
|
||||||
use xilem_core::{
|
use xilem_core::{
|
||||||
AsyncCtx, MessageResult, RawProxy, SuperElement, View, ViewElement, ViewId, ViewPathTracker,
|
AsyncCtx, MessageResult, RawProxy, SuperElement, View, ViewElement, ViewId, ViewPathTracker,
|
||||||
|
ViewSequence,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use masonry::{
|
pub use masonry::{
|
||||||
|
@ -209,6 +210,30 @@ where
|
||||||
type Widget = W;
|
type Widget = W;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ordered sequence of widget views, it's used for `0..N` views.
|
||||||
|
/// See [`ViewSequence`] for more technical details.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use xilem::{view::prose, WidgetViewSequence};
|
||||||
|
///
|
||||||
|
/// fn prose_sequence<State: 'static>(
|
||||||
|
/// texts: impl Iterator<Item = &'static str>,
|
||||||
|
/// ) -> impl WidgetViewSequence<State> {
|
||||||
|
/// texts.map(prose).collect::<Vec<_>>()
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait WidgetViewSequence<State, Action = ()>:
|
||||||
|
ViewSequence<State, Action, ViewCtx, Pod<any_view::DynWidget>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Seq, State, Action> WidgetViewSequence<State, Action> for Seq where
|
||||||
|
Seq: ViewSequence<State, Action, ViewCtx, Pod<any_view::DynWidget>>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
type WidgetMap = HashMap<WidgetId, Vec<ViewId>>;
|
type WidgetMap = HashMap<WidgetId, Vec<ViewId>>;
|
||||||
|
|
||||||
pub struct ViewCtx {
|
pub struct ViewCtx {
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
use std::{future::Future, marker::PhantomData, sync::Arc};
|
use std::{future::Future, marker::PhantomData, sync::Arc};
|
||||||
|
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use xilem_core::{DynMessage, Message, MessageProxy, NoElement, View, ViewId, ViewPathTracker};
|
use xilem_core::{
|
||||||
|
DynMessage, Message, MessageProxy, NoElement, View, ViewId, ViewMarker, ViewPathTracker,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::ViewCtx;
|
use crate::ViewCtx;
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ pub struct AsyncRepeat<F, H, M> {
|
||||||
message: PhantomData<fn() -> M>,
|
message: PhantomData<fn() -> M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F, H, M> ViewMarker for AsyncRepeat<F, H, M> {}
|
||||||
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx> for AsyncRepeat<F, H, M>
|
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx> for AsyncRepeat<F, H, M>
|
||||||
where
|
where
|
||||||
F: Fn(MessageProxy<M>) -> Fut + 'static,
|
F: Fn(MessageProxy<M>) -> Fut + 'static,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use crate::{core::View, Pod};
|
use crate::{core::View, Pod};
|
||||||
use masonry::{widget, ArcStr};
|
use masonry::{widget, ArcStr};
|
||||||
use xilem_core::Mut;
|
use xilem_core::{Mut, ViewMarker};
|
||||||
|
|
||||||
pub use masonry::PointerButton;
|
pub use masonry::PointerButton;
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ pub struct Button<F> {
|
||||||
callback: F,
|
callback: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F> ViewMarker for Button<F> {}
|
||||||
impl<F, State, Action> View<State, Action, ViewCtx> for Button<F>
|
impl<F, State, Action> View<State, Action, ViewCtx> for Button<F>
|
||||||
where
|
where
|
||||||
F: Fn(&mut State, PointerButton) -> MessageResult<Action> + Send + Sync + 'static,
|
F: Fn(&mut State, PointerButton) -> MessageResult<Action> + Send + Sync + 'static,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use masonry::{widget, ArcStr};
|
use masonry::{widget, ArcStr};
|
||||||
use xilem_core::Mut;
|
use xilem_core::{Mut, ViewMarker};
|
||||||
|
|
||||||
use crate::{MessageResult, Pod, View, ViewCtx, ViewId};
|
use crate::{MessageResult, Pod, View, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ pub struct Checkbox<F> {
|
||||||
callback: F,
|
callback: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F> ViewMarker for Checkbox<F> {}
|
||||||
impl<F, State, Action> View<State, Action, ViewCtx> for Checkbox<F>
|
impl<F, State, Action> View<State, Action, ViewCtx> for Checkbox<F>
|
||||||
where
|
where
|
||||||
F: Fn(&mut State, bool) -> Action + Send + Sync + 'static,
|
F: Fn(&mut State, bool) -> Action + Send + Sync + 'static,
|
||||||
|
|
|
@ -9,36 +9,38 @@ use masonry::{
|
||||||
};
|
};
|
||||||
use xilem_core::{
|
use xilem_core::{
|
||||||
AppendVec, DynMessage, ElementSplice, MessageResult, Mut, SuperElement, View, ViewElement,
|
AppendVec, DynMessage, ElementSplice, MessageResult, Mut, SuperElement, View, ViewElement,
|
||||||
ViewId, ViewPathTracker, ViewSequence,
|
ViewId, ViewMarker, ViewPathTracker, ViewSequence,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{AnyWidgetView, Pod, ViewCtx, WidgetView};
|
use crate::{AnyWidgetView, Pod, ViewCtx, WidgetView};
|
||||||
|
|
||||||
pub use masonry::widget::{Axis, CrossAxisAlignment, FlexParams, MainAxisAlignment};
|
pub use masonry::widget::{Axis, CrossAxisAlignment, FlexParams, MainAxisAlignment};
|
||||||
|
|
||||||
pub fn flex<Seq, Marker>(sequence: Seq) -> Flex<Seq, Marker> {
|
pub fn flex<State, Action, Seq: FlexSequence<State, Action>>(
|
||||||
|
sequence: Seq,
|
||||||
|
) -> Flex<Seq, State, Action> {
|
||||||
Flex {
|
Flex {
|
||||||
phantom: PhantomData,
|
|
||||||
sequence,
|
sequence,
|
||||||
axis: Axis::Vertical,
|
axis: Axis::Vertical,
|
||||||
cross_axis_alignment: CrossAxisAlignment::Center,
|
cross_axis_alignment: CrossAxisAlignment::Center,
|
||||||
main_axis_alignment: MainAxisAlignment::Start,
|
main_axis_alignment: MainAxisAlignment::Start,
|
||||||
fill_major_axis: false,
|
fill_major_axis: false,
|
||||||
gap: None,
|
gap: None,
|
||||||
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Flex<Seq, Marker> {
|
pub struct Flex<Seq, State, Action = ()> {
|
||||||
sequence: Seq,
|
sequence: Seq,
|
||||||
axis: Axis,
|
axis: Axis,
|
||||||
cross_axis_alignment: CrossAxisAlignment,
|
cross_axis_alignment: CrossAxisAlignment,
|
||||||
main_axis_alignment: MainAxisAlignment,
|
main_axis_alignment: MainAxisAlignment,
|
||||||
fill_major_axis: bool,
|
fill_major_axis: bool,
|
||||||
phantom: PhantomData<fn() -> Marker>,
|
|
||||||
gap: Option<f64>,
|
gap: Option<f64>,
|
||||||
|
phantom: PhantomData<fn() -> (State, Action)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Seq, Marker> Flex<Seq, Marker> {
|
impl<Seq, State, Action> Flex<Seq, State, Action> {
|
||||||
pub fn direction(mut self, axis: Axis) -> Self {
|
pub fn direction(mut self, axis: Axis) -> Self {
|
||||||
self.axis = axis;
|
self.axis = axis;
|
||||||
self
|
self
|
||||||
|
@ -85,9 +87,12 @@ impl<Seq, Marker> Flex<Seq, Marker> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, Seq, Marker: 'static> View<State, Action, ViewCtx> for Flex<Seq, Marker>
|
impl<Seq, State, Action> ViewMarker for Flex<Seq, State, Action> {}
|
||||||
|
impl<State, Action, Seq> View<State, Action, ViewCtx> for Flex<Seq, State, Action>
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<State, Action, ViewCtx, FlexElement, Marker>,
|
State: 'static,
|
||||||
|
Action: 'static,
|
||||||
|
Seq: FlexSequence<State, Action>,
|
||||||
{
|
{
|
||||||
type Element = Pod<widget::Flex>;
|
type Element = Pod<widget::Flex>;
|
||||||
|
|
||||||
|
@ -303,6 +308,31 @@ impl ElementSplice<FlexElement> for FlexSplice<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ordered sequence of views for a [`Flex`] view.
|
||||||
|
/// See [`ViewSequence`] for more technical details.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use xilem::view::{label, FlexSequence, FlexExt as _};
|
||||||
|
///
|
||||||
|
/// fn label_sequence<State: 'static>(
|
||||||
|
/// labels: impl Iterator<Item = &'static str>,
|
||||||
|
/// flex: f64,
|
||||||
|
/// ) -> impl FlexSequence<State> {
|
||||||
|
/// labels.map(|l| label(l).flex(flex)).collect::<Vec<_>>()
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait FlexSequence<State, Action = ()>:
|
||||||
|
ViewSequence<State, Action, ViewCtx, FlexElement>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Seq, State, Action> FlexSequence<State, Action> for Seq where
|
||||||
|
Seq: ViewSequence<State, Action, ViewCtx, FlexElement>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait which extends a [`WidgetView`] with methods to provide parameters for a flex item, or being able to use it interchangeably with a spacer
|
/// A trait which extends a [`WidgetView`] with methods to provide parameters for a flex item, or being able to use it interchangeably with a spacer
|
||||||
pub trait FlexExt<State, Action>: WidgetView<State, Action> {
|
pub trait FlexExt<State, Action>: WidgetView<State, Action> {
|
||||||
/// Applies [`impl Into<FlexParams>`](`FlexParams`) to this view, can be used as child of a [`Flex`] [`View`]
|
/// Applies [`impl Into<FlexParams>`](`FlexParams`) to this view, can be used as child of a [`Flex`] [`View`]
|
||||||
|
@ -407,6 +437,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action> ViewMarker for FlexItem<V, State, Action> {}
|
||||||
impl<State, Action, V> View<State, Action, ViewCtx> for FlexItem<V, State, Action>
|
impl<State, Action, V> View<State, Action, ViewCtx> for FlexItem<V, State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
|
@ -485,6 +516,7 @@ impl<State, Action> From<FlexSpacer> for AnyFlexChild<State, Action> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewMarker for FlexSpacer {}
|
||||||
// This impl doesn't require a view id, as it neither receives, nor sends any messages
|
// This impl doesn't require a view id, as it neither receives, nor sends any messages
|
||||||
// If this should ever change, it's necessary to adjust the `AnyFlexChild` `View` impl
|
// If this should ever change, it's necessary to adjust the `AnyFlexChild` `View` impl
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for FlexSpacer {
|
impl<State, Action> View<State, Action, ViewCtx> for FlexSpacer {
|
||||||
|
@ -593,6 +625,7 @@ pub struct AnyFlexChildState<State: 'static, Action: 'static> {
|
||||||
generation: u64,
|
generation: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action> ViewMarker for AnyFlexChild<State, Action> {}
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for AnyFlexChild<State, Action>
|
impl<State, Action> View<State, Action, ViewCtx> for AnyFlexChild<State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use masonry::{text::TextBrush, widget, ArcStr};
|
use masonry::{text::TextBrush, widget, ArcStr};
|
||||||
use xilem_core::Mut;
|
use xilem_core::{Mut, ViewMarker};
|
||||||
|
|
||||||
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ impl Label {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewMarker for Label {}
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for Label {
|
impl<State, Action> View<State, Action, ViewCtx> for Label {
|
||||||
type Element = Pod<widget::Label>;
|
type Element = Pod<widget::Label>;
|
||||||
type ViewState = ();
|
type ViewState = ();
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use masonry::{text::TextBrush, widget, ArcStr};
|
use masonry::{text::TextBrush, widget, ArcStr};
|
||||||
use xilem_core::Mut;
|
use xilem_core::{Mut, ViewMarker};
|
||||||
|
|
||||||
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
use crate::{Color, MessageResult, Pod, TextAlignment, View, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ impl Prose {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewMarker for Prose {}
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for Prose {
|
impl<State, Action> View<State, Action, ViewCtx> for Prose {
|
||||||
type Element = Pod<widget::Prose>;
|
type Element = Pod<widget::Prose>;
|
||||||
type ViewState = ();
|
type ViewState = ();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use masonry::widget;
|
use masonry::widget;
|
||||||
|
use xilem_core::ViewMarker;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{Mut, View, ViewId},
|
core::{Mut, View, ViewId},
|
||||||
|
@ -74,6 +75,7 @@ impl<V> SizedBox<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V> ViewMarker for SizedBox<V> {}
|
||||||
impl<V, State, Action> View<State, Action, ViewCtx> for SizedBox<V>
|
impl<V, State, Action> View<State, Action, ViewCtx> for SizedBox<V>
|
||||||
where
|
where
|
||||||
V: WidgetView<State, Action>,
|
V: WidgetView<State, Action>,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use masonry::{text::TextBrush, widget};
|
use masonry::{text::TextBrush, widget};
|
||||||
use xilem_core::{Mut, View};
|
use xilem_core::{Mut, View, ViewMarker};
|
||||||
|
|
||||||
use crate::{Color, MessageResult, Pod, TextAlignment, ViewCtx, ViewId};
|
use crate::{Color, MessageResult, Pod, TextAlignment, ViewCtx, ViewId};
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ impl<State, Action> Textbox<State, Action> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action> ViewMarker for Textbox<State, Action> {}
|
||||||
impl<State: 'static, Action: 'static> View<State, Action, ViewCtx> for Textbox<State, Action> {
|
impl<State: 'static, Action: 'static> View<State, Action, ViewCtx> for Textbox<State, Action> {
|
||||||
type Element = Pod<widget::Textbox>;
|
type Element = Pod<widget::Textbox>;
|
||||||
type ViewState = ();
|
type ViewState = ();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use std::{io::stdin, path::PathBuf};
|
use std::{io::stdin, path::PathBuf};
|
||||||
|
|
||||||
use xilem_core::{
|
use xilem_core::{
|
||||||
AnyElement, AnyView, Mut, SuperElement, View, ViewElement, ViewId, ViewPathTracker,
|
AnyElement, AnyView, Mut, SuperElement, View, ViewElement, ViewId, ViewMarker, ViewPathTracker,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -145,6 +145,7 @@ impl ViewElement for FsPath {
|
||||||
type Mut<'a> = &'a mut PathBuf;
|
type Mut<'a> = &'a mut PathBuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewMarker for File {}
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for File {
|
impl<State, Action> View<State, Action, ViewCtx> for File {
|
||||||
type Element = FsPath;
|
type Element = FsPath;
|
||||||
type ViewState = ();
|
type ViewState = ();
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
|
||||||
use xilem_core::{
|
use xilem_core::{
|
||||||
DynMessage, MessageResult, Mut, SuperElement, View, ViewElement, ViewId, ViewPathTracker,
|
DynMessage, MessageResult, Mut, SuperElement, View, ViewElement, ViewId, ViewMarker,
|
||||||
|
ViewPathTracker,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn app_logic(_: &mut u32) -> impl WidgetView<u32> {
|
pub fn app_logic(_: &mut u32) -> impl WidgetView<u32> {
|
||||||
|
@ -44,6 +45,7 @@ impl<W: Widget> ViewElement for WidgetPod<W> {
|
||||||
type Mut<'a> = WidgetMut<'a, W>;
|
type Mut<'a> = WidgetMut<'a, W>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ViewMarker for Button {}
|
||||||
impl<State, Action> View<State, Action, ViewCtx> for Button {
|
impl<State, Action> View<State, Action, ViewCtx> for Button {
|
||||||
type Element = WidgetPod<ButtonWidget>;
|
type Element = WidgetPod<ButtonWidget>;
|
||||||
type ViewState = ();
|
type ViewState = ();
|
||||||
|
|
|
@ -8,7 +8,8 @@ use core::any::Any;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyElement, DynMessage, MessageResult, Mut, View, ViewElement, ViewId, ViewPathTracker,
|
AnyElement, DynMessage, MessageResult, Mut, View, ViewElement, ViewId, ViewMarker,
|
||||||
|
ViewPathTracker,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A view which can have any view type where the [`View::Element`] is compatible with
|
/// A view which can have any view type where the [`View::Element`] is compatible with
|
||||||
|
@ -171,6 +172,10 @@ pub struct AnyViewState {
|
||||||
generation: u64,
|
generation: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action, Context, Element, Message> ViewMarker
|
||||||
|
for dyn AnyView<State, Action, Context, Element, Message>
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
||||||
for dyn AnyView<State, Action, Context, Element, Message>
|
for dyn AnyView<State, Action, Context, Element, Message>
|
||||||
where
|
where
|
||||||
|
@ -220,6 +225,11 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: IWBN if we could avoid this
|
// TODO: IWBN if we could avoid this
|
||||||
|
|
||||||
|
impl<State, Action, Context, Element, Message> ViewMarker
|
||||||
|
for dyn AnyView<State, Action, Context, Element, Message> + Send
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
||||||
for dyn AnyView<State, Action, Context, Element, Message> + Send
|
for dyn AnyView<State, Action, Context, Element, Message> + Send
|
||||||
where
|
where
|
||||||
|
@ -268,6 +278,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action, Context, Element, Message> ViewMarker
|
||||||
|
for dyn AnyView<State, Action, Context, Element, Message> + Send + Sync
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
||||||
for dyn AnyView<State, Action, Context, Element, Message> + Send + Sync
|
for dyn AnyView<State, Action, Context, Element, Message> + Send + Sync
|
||||||
where
|
where
|
||||||
|
@ -316,6 +330,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action, Context, Element, Message> ViewMarker
|
||||||
|
for dyn AnyView<State, Action, Context, Element, Message> + Sync
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context, Element, Message> View<State, Action, Context, Message>
|
||||||
for dyn AnyView<State, Action, Context, Element, Message> + Sync
|
for dyn AnyView<State, Action, Context, Element, Message> + Sync
|
||||||
where
|
where
|
||||||
|
|
|
@ -94,3 +94,16 @@ pub struct NoElement;
|
||||||
impl ViewElement for NoElement {
|
impl ViewElement for NoElement {
|
||||||
type Mut<'a> = ();
|
type Mut<'a> = ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SuperElement<NoElement> for NoElement {
|
||||||
|
fn upcast(child: NoElement) -> Self {
|
||||||
|
child
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_downcast_val<R>(
|
||||||
|
this: Mut<'_, Self>,
|
||||||
|
f: impl FnOnce(Mut<'_, NoElement>) -> R,
|
||||||
|
) -> (Self::Mut<'_>, R) {
|
||||||
|
((), f(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ mod deferred;
|
||||||
pub use deferred::{AsyncCtx, MessageProxy, PhantomView, ProxyError, RawProxy};
|
pub use deferred::{AsyncCtx, MessageProxy, PhantomView, ProxyError, RawProxy};
|
||||||
|
|
||||||
mod view;
|
mod view;
|
||||||
pub use view::{View, ViewId, ViewPathTracker};
|
pub use view::{View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
mod views;
|
mod views;
|
||||||
pub use views::{
|
pub use views::{
|
||||||
|
|
|
@ -9,8 +9,10 @@ use core::sync::atomic::Ordering;
|
||||||
use alloc::vec::Drain;
|
use alloc::vec::Drain;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::element::NoElement;
|
// use crate::element::NoElement;
|
||||||
use crate::{DynMessage, MessageResult, SuperElement, View, ViewElement, ViewId, ViewPathTracker};
|
use crate::{
|
||||||
|
DynMessage, MessageResult, SuperElement, View, ViewElement, ViewId, ViewMarker, ViewPathTracker,
|
||||||
|
};
|
||||||
|
|
||||||
/// An append only `Vec`.
|
/// An append only `Vec`.
|
||||||
///
|
///
|
||||||
|
@ -74,11 +76,11 @@ impl<T> Default for AppendVec<T> {
|
||||||
/// Note that this will have persistent allocation with size proportional
|
/// Note that this will have persistent allocation with size proportional
|
||||||
/// to the *longest* `Vec` which is ever provided in the View tree, as this
|
/// to the *longest* `Vec` which is ever provided in the View tree, as this
|
||||||
/// uses a generational indexing scheme.
|
/// uses a generational indexing scheme.
|
||||||
|
/// - An [`array`] of `ViewSequence` values.
|
||||||
/// - Tuples of `ViewSequences` with up to 15 elements.
|
/// - Tuples of `ViewSequences` with up to 15 elements.
|
||||||
/// These can be nested if an ad-hoc sequence of more than 15 sequences is needed.
|
/// These can be nested if an ad-hoc sequence of more than 15 sequences is needed.
|
||||||
///
|
///
|
||||||
pub trait ViewSequence<State, Action, Context, Element, Marker, Message = DynMessage>:
|
pub trait ViewSequence<State, Action, Context, Element, Message = DynMessage>: 'static
|
||||||
'static
|
|
||||||
where
|
where
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
|
@ -143,15 +145,11 @@ pub trait ElementSplice<Element: ViewElement> {
|
||||||
fn delete<R>(&mut self, f: impl FnOnce(Element::Mut<'_>) -> R) -> R;
|
fn delete<R>(&mut self, f: impl FnOnce(Element::Mut<'_>) -> R) -> R;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker type to workaround trait ambiguity.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct WasAView;
|
|
||||||
|
|
||||||
impl<State, Action, Context, V, Element, Message>
|
impl<State, Action, Context, V, Element, Message>
|
||||||
ViewSequence<State, Action, Context, Element, WasAView, Message> for V
|
ViewSequence<State, Action, Context, Element, Message> for V
|
||||||
where
|
where
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
V: View<State, Action, Context, Message>,
|
V: View<State, Action, Context, Message> + ViewMarker,
|
||||||
Element: SuperElement<V::Element>,
|
Element: SuperElement<V::Element>,
|
||||||
V::Element: ViewElement,
|
V::Element: ViewElement,
|
||||||
{
|
{
|
||||||
|
@ -218,10 +216,10 @@ pub struct OptionSeqState<InnerState> {
|
||||||
///
|
///
|
||||||
/// Will mark messages which were sent to a `Some` value if a `None` has since
|
/// Will mark messages which were sent to a `Some` value if a `None` has since
|
||||||
/// occurred as stale.
|
/// occurred as stale.
|
||||||
impl<State, Action, Context, Element, Marker, Seq, Message>
|
impl<State, Action, Context, Element, Seq, Message>
|
||||||
ViewSequence<State, Action, Context, Element, Option<Marker>, Message> for Option<Seq>
|
ViewSequence<State, Action, Context, Element, Message> for Option<Seq>
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<State, Action, Context, Element, Marker, Message>,
|
Seq: ViewSequence<State, Action, Context, Element, Message>,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
{
|
{
|
||||||
|
@ -338,57 +336,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `View` with [no element](crate::NoElement) can be added to any [`ViewSequence`], because it does not use any
|
|
||||||
/// properties of the `Element` type.
|
|
||||||
impl<State, Action, Context, Element, NoElementView, Message>
|
|
||||||
ViewSequence<State, Action, Context, Element, NoElement, Message> for NoElementView
|
|
||||||
where
|
|
||||||
NoElementView: View<State, Action, Context, Message, Element = NoElement>,
|
|
||||||
Element: ViewElement,
|
|
||||||
Context: ViewPathTracker,
|
|
||||||
{
|
|
||||||
#[doc(hidden)]
|
|
||||||
type SeqState = NoElementView::ViewState;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn seq_build(&self, ctx: &mut Context, _: &mut AppendVec<Element>) -> Self::SeqState {
|
|
||||||
let (NoElement, state) = self.build(ctx);
|
|
||||||
state
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn seq_rebuild(
|
|
||||||
&self,
|
|
||||||
prev: &Self,
|
|
||||||
seq_state: &mut Self::SeqState,
|
|
||||||
ctx: &mut Context,
|
|
||||||
_: &mut impl ElementSplice<Element>,
|
|
||||||
) {
|
|
||||||
self.rebuild(prev, seq_state, ctx, ());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn seq_teardown(
|
|
||||||
&self,
|
|
||||||
seq_state: &mut Self::SeqState,
|
|
||||||
ctx: &mut Context,
|
|
||||||
_: &mut impl ElementSplice<Element>,
|
|
||||||
) {
|
|
||||||
self.teardown(seq_state, ctx, ());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn seq_message(
|
|
||||||
&self,
|
|
||||||
seq_state: &mut Self::SeqState,
|
|
||||||
id_path: &[ViewId],
|
|
||||||
message: Message,
|
|
||||||
app_state: &mut State,
|
|
||||||
) -> MessageResult<Action, Message> {
|
|
||||||
self.message(seq_state, id_path, message, app_state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The state used to implement `ViewSequence` for `Vec<impl ViewSequence>`
|
/// The state used to implement `ViewSequence` for `Vec<impl ViewSequence>`
|
||||||
///
|
///
|
||||||
/// We use a generation arena for vector types, with half of the `ViewId` dedicated
|
/// We use a generation arena for vector types, with half of the `ViewId` dedicated
|
||||||
|
@ -428,10 +375,10 @@ fn view_id_to_index_generation(view_id: ViewId) -> (usize, u32) {
|
||||||
///
|
///
|
||||||
/// Will mark messages which were sent to any index as stale if
|
/// Will mark messages which were sent to any index as stale if
|
||||||
/// that index has been unused in the meantime.
|
/// that index has been unused in the meantime.
|
||||||
impl<State, Action, Context, Element, Marker, Seq, Message>
|
impl<State, Action, Context, Element, Seq, Message>
|
||||||
ViewSequence<State, Action, Context, Element, Vec<Marker>, Message> for Vec<Seq>
|
ViewSequence<State, Action, Context, Element, Message> for Vec<Seq>
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<State, Action, Context, Element, Marker, Message>,
|
Seq: ViewSequence<State, Action, Context, Element, Message>,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
{
|
{
|
||||||
|
@ -582,10 +529,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, Context, Element, Marker, Seq, Message, const N: usize>
|
impl<State, Action, Context, Element, Seq, Message, const N: usize>
|
||||||
ViewSequence<State, Action, Context, Element, Vec<Marker>, Message> for [Seq; N]
|
ViewSequence<State, Action, Context, Element, Message> for [Seq; N]
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<State, Action, Context, Element, Marker, Message>,
|
Seq: ViewSequence<State, Action, Context, Element, Message>,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
{
|
{
|
||||||
|
@ -661,7 +608,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, Context, Element, Message>
|
impl<State, Action, Context, Element, Message>
|
||||||
ViewSequence<State, Action, Context, Element, (), Message> for ()
|
ViewSequence<State, Action, Context, Element, Message> for ()
|
||||||
where
|
where
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
|
@ -699,10 +646,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, Context, Element, Marker, Seq, Message>
|
impl<State, Action, Context, Element, Seq, Message>
|
||||||
ViewSequence<State, Action, Context, Element, (Marker,), Message> for (Seq,)
|
ViewSequence<State, Action, Context, Element, Message> for (Seq,)
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<State, Action, Context, Element, Marker, Message>,
|
Seq: ViewSequence<State, Action, Context, Element, Message>,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
{
|
{
|
||||||
|
@ -753,12 +700,9 @@ macro_rules! impl_view_tuple {
|
||||||
Action,
|
Action,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Element: ViewElement,
|
Element: ViewElement,
|
||||||
$(
|
$($seq: ViewSequence<State, Action, Context, Element, Message>,)+
|
||||||
$marker,
|
|
||||||
$seq: ViewSequence<State, Action, Context, Element, $marker, Message>,
|
|
||||||
)+
|
|
||||||
Message,
|
Message,
|
||||||
> ViewSequence<State, Action, Context, Element, ($($marker,)+), Message> for ($($seq,)+)
|
> ViewSequence<State, Action, Context, Element, Message> for ($($seq,)+)
|
||||||
|
|
||||||
{
|
{
|
||||||
type SeqState = ($($seq::SeqState,)+);
|
type SeqState = ($($seq::SeqState,)+);
|
||||||
|
|
|
@ -9,6 +9,22 @@ use alloc::{boxed::Box, sync::Arc};
|
||||||
|
|
||||||
use crate::{message::MessageResult, DynMessage, Mut, ViewElement};
|
use crate::{message::MessageResult, DynMessage, Mut, ViewElement};
|
||||||
|
|
||||||
|
/// A type which can be a [`View`]. Imposes no requirements on the underlying type.
|
||||||
|
/// Should be implemented alongside every `View` implementation:
|
||||||
|
/// ```ignore
|
||||||
|
/// impl<...> ViewMarker for Button<...> {}
|
||||||
|
/// impl<...> View<...> for Button<...> {...}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Details
|
||||||
|
///
|
||||||
|
/// Because `View` is generic, Rust [allows you](https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules) to implement this trait for certain non-local types.
|
||||||
|
/// These non-local types can include `Vec<_>` and `Option<_>`.
|
||||||
|
/// If this trait were not present, those implementations of `View` would conflict with those types' implementations of `ViewSequence`.
|
||||||
|
/// This is because every `View` type also implementations `ViewSequence`.
|
||||||
|
/// Since `ViewMarker` is not generic, these non-local implementations are not permitted for this trait, which means that the conflicting implementation cannot happen.
|
||||||
|
pub trait ViewMarker {}
|
||||||
|
|
||||||
/// A lightweight, short-lived representation of the state of a retained
|
/// A lightweight, short-lived representation of the state of a retained
|
||||||
/// structure, usually a user interface node.
|
/// structure, usually a user interface node.
|
||||||
///
|
///
|
||||||
|
@ -30,11 +46,21 @@ use crate::{message::MessageResult, DynMessage, Mut, ViewElement};
|
||||||
/// During message handling, mutable access to the app state is given to view nodes,
|
/// During message handling, mutable access to the app state is given to view nodes,
|
||||||
/// which will in turn generally expose it to callbacks.
|
/// which will in turn generally expose it to callbacks.
|
||||||
///
|
///
|
||||||
|
/// Due to restrictions of the [orphan rules](https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules),
|
||||||
|
/// `ViewMarker` needs to be implemented for every type that implements `View`, see [`ViewMarker`] for more details.
|
||||||
|
/// For example:
|
||||||
|
/// ```ignore
|
||||||
|
/// impl<...> ViewMarker for Button<...> {}
|
||||||
|
/// impl<...> View<...> for Button<...> {...}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// ## Alloc
|
/// ## Alloc
|
||||||
///
|
///
|
||||||
/// In order to support the default open-ended [`DynMessage`] type as `Message`, this trait requires an
|
/// In order to support the default open-ended [`DynMessage`] type as `Message`, this trait requires an
|
||||||
/// allocator to be available.
|
/// allocator to be available.
|
||||||
pub trait View<State, Action, Context: ViewPathTracker, Message = DynMessage>: 'static {
|
pub trait View<State, Action, Context: ViewPathTracker, Message = DynMessage>:
|
||||||
|
ViewMarker + 'static
|
||||||
|
{
|
||||||
/// The element type which this view operates on.
|
/// The element type which this view operates on.
|
||||||
type Element: ViewElement;
|
type Element: ViewElement;
|
||||||
/// State that is used over the lifetime of the retained representation of the view.
|
/// State that is used over the lifetime of the retained representation of the view.
|
||||||
|
@ -137,6 +163,7 @@ pub trait ViewPathTracker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V: ?Sized> ViewMarker for Box<V> {}
|
||||||
impl<State, Action, Context, Message, V> View<State, Action, Context, Message> for Box<V>
|
impl<State, Action, Context, Message, V> View<State, Action, Context, Message> for Box<V>
|
||||||
where
|
where
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
|
@ -185,6 +212,7 @@ pub struct ArcState<ViewState> {
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V: ?Sized> ViewMarker for Arc<V> {}
|
||||||
/// An implementation of [`View`] which only runs rebuild if the states are different
|
/// An implementation of [`View`] which only runs rebuild if the states are different
|
||||||
impl<State, Action, Context, Message, V> View<State, Action, Context, Message> for Arc<V>
|
impl<State, Action, Context, Message, V> View<State, Action, Context, Message> for Arc<V>
|
||||||
where
|
where
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{MessageResult, Mut, View, ViewId, ViewPathTracker};
|
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
/// A view that wraps a child view and modifies the state that callbacks have access to.
|
/// A view that wraps a child view and modifies the state that callbacks have access to.
|
||||||
pub struct Adapt<
|
pub struct Adapt<
|
||||||
|
@ -18,9 +18,7 @@ pub struct Adapt<
|
||||||
&mut ParentState,
|
&mut ParentState,
|
||||||
AdaptThunk<ChildState, ChildAction, Context, ChildView, Message>,
|
AdaptThunk<ChildState, ChildAction, Context, ChildView, Message>,
|
||||||
) -> MessageResult<ParentAction>,
|
) -> MessageResult<ParentAction>,
|
||||||
> where
|
> {
|
||||||
Context: ViewPathTracker,
|
|
||||||
{
|
|
||||||
proxy_fn: ProxyFn,
|
proxy_fn: ProxyFn,
|
||||||
child: ChildView,
|
child: ChildView,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
@ -147,6 +145,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<ParentState, ParentAction, ChildState, ChildAction, Context, Message, V, F> ViewMarker
|
||||||
|
for Adapt<ParentState, ParentAction, ChildState, ChildAction, Context, V, Message, F>
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<ParentState, ParentAction, ChildState, ChildAction, Context, Message, V, F>
|
impl<ParentState, ParentAction, ChildState, ChildAction, Context, Message, V, F>
|
||||||
View<ParentState, ParentAction, Context, Message>
|
View<ParentState, ParentAction, Context, Message>
|
||||||
for Adapt<ParentState, ParentAction, ChildState, ChildAction, Context, V, Message, F>
|
for Adapt<ParentState, ParentAction, ChildState, ChildAction, Context, V, Message, F>
|
||||||
|
|
|
@ -1,40 +1,37 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppendVec, ElementSplice, Mut, NoElement, View, ViewId, ViewPathTracker, ViewSequence,
|
AppendVec, ElementSplice, Mut, NoElement, View, ViewId, ViewMarker, ViewPathTracker,
|
||||||
|
ViewSequence,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Create a view which acts as `active_view`, whilst also running `alongside_view`, without inserting it into the tree.
|
/// Create a view which acts as `active_view`, whilst also running `alongside_view`, without inserting it into the tree.
|
||||||
///
|
///
|
||||||
/// `alongside_view` must be a `ViewSequence` with an element type of [`NoElement`].
|
/// `alongside_view` must be a `ViewSequence` with an element type of [`NoElement`].
|
||||||
pub fn fork<Active, Alongside, Marker>(
|
pub fn fork<Active, Alongside>(
|
||||||
active_view: Active,
|
active_view: Active,
|
||||||
alongside_view: Alongside,
|
alongside_view: Alongside,
|
||||||
) -> Fork<Active, Alongside, Marker> {
|
) -> Fork<Active, Alongside> {
|
||||||
Fork {
|
Fork {
|
||||||
active_view,
|
active_view,
|
||||||
alongside_view,
|
alongside_view,
|
||||||
marker: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The view for [`fork`].
|
/// The view for [`fork`].
|
||||||
pub struct Fork<Active, Alongside, Marker> {
|
pub struct Fork<Active, Alongside> {
|
||||||
active_view: Active,
|
active_view: Active,
|
||||||
alongside_view: Alongside,
|
alongside_view: Alongside,
|
||||||
marker: PhantomData<Marker>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, Context, Active, Alongside, Marker, Message>
|
impl<Active, Alongside> ViewMarker for Fork<Active, Alongside> {}
|
||||||
View<State, Action, Context, Message> for Fork<Active, Alongside, Marker>
|
impl<State, Action, Context, Active, Alongside, Message> View<State, Action, Context, Message>
|
||||||
|
for Fork<Active, Alongside>
|
||||||
where
|
where
|
||||||
Active: View<State, Action, Context, Message>,
|
Active: View<State, Action, Context, Message>,
|
||||||
Alongside: ViewSequence<State, Action, Context, NoElement, Marker, Message>,
|
Alongside: ViewSequence<State, Action, Context, NoElement, Message>,
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
Marker: 'static,
|
|
||||||
{
|
{
|
||||||
type Element = Active::Element;
|
type Element = Active::Element;
|
||||||
|
|
||||||
|
@ -111,12 +108,8 @@ where
|
||||||
|
|
||||||
/// A stub `ElementSplice` implementation for `NoElement`.
|
/// A stub `ElementSplice` implementation for `NoElement`.
|
||||||
///
|
///
|
||||||
/// We know that none of the methods will be called, because the `ViewSequence`
|
|
||||||
/// implementation for `NoElement` views does not use the provided `elements`.
|
|
||||||
///
|
|
||||||
/// It is technically possible for someone to create an implementation of `ViewSequence`
|
/// It is technically possible for someone to create an implementation of `ViewSequence`
|
||||||
/// which uses a `NoElement` `ElementSplice`. But we don't think that sequence could be meaningful,
|
/// which uses a `NoElement` `ElementSplice`. But we don't think that sequence could be meaningful.
|
||||||
/// so we still panic in that case.
|
|
||||||
struct NoElements;
|
struct NoElements;
|
||||||
|
|
||||||
impl ElementSplice<NoElement> for NoElements {
|
impl ElementSplice<NoElement> for NoElements {
|
||||||
|
@ -127,21 +120,15 @@ impl ElementSplice<NoElement> for NoElements {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, _: NoElement) {
|
fn insert(&mut self, _: NoElement) {}
|
||||||
unreachable!()
|
|
||||||
|
fn mutate<R>(&mut self, f: impl FnOnce(<NoElement as crate::ViewElement>::Mut<'_>) -> R) -> R {
|
||||||
|
f(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutate<R>(&mut self, _: impl FnOnce(<NoElement as crate::ViewElement>::Mut<'_>) -> R) -> R {
|
fn skip(&mut self, _: usize) {}
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn skip(&mut self, n: usize) {
|
fn delete<R>(&mut self, f: impl FnOnce(<NoElement as crate::ViewElement>::Mut<'_>) -> R) -> R {
|
||||||
if n > 0 {
|
f(())
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete<R>(&mut self, _: impl FnOnce(<NoElement as crate::ViewElement>::Mut<'_>) -> R) -> R {
|
|
||||||
unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{Mut, View, ViewId, ViewPathTracker};
|
use crate::{Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
/// A view that maps a child [`View<State,ChildAction,_>`] to [`View<State,ParentAction,_>`] while providing mutable access to `State` in the map function.
|
/// A view that maps a child [`View<State,ChildAction,_>`] to [`View<State,ParentAction,_>`] while providing mutable access to `State` in the map function.
|
||||||
///
|
///
|
||||||
|
@ -68,6 +68,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, ParentAction, ChildAction, V, F> ViewMarker
|
||||||
|
for MapAction<State, ParentAction, ChildAction, V, F>
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, ParentAction, ChildAction, Context: ViewPathTracker, Message, V, F>
|
impl<State, ParentAction, ChildAction, Context: ViewPathTracker, Message, V, F>
|
||||||
View<State, ParentAction, Context, Message>
|
View<State, ParentAction, Context, Message>
|
||||||
for MapAction<State, ParentAction, ChildAction, V, F>
|
for MapAction<State, ParentAction, ChildAction, V, F>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{MessageResult, Mut, View, ViewId, ViewPathTracker};
|
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
/// A view that "extracts" state from a [`View<ParentState,_,_>`] to [`View<ChildState,_,_>`].
|
/// A view that "extracts" state from a [`View<ParentState,_,_>`] to [`View<ChildState,_,_>`].
|
||||||
/// This allows modularization of views based on their state.
|
/// This allows modularization of views based on their state.
|
||||||
|
@ -56,6 +56,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<ParentState, ChildState, V, F> ViewMarker for MapState<ParentState, ChildState, V, F> {}
|
||||||
impl<ParentState, ChildState, Action, Context: ViewPathTracker, Message, V, F>
|
impl<ParentState, ChildState, Action, Context: ViewPathTracker, Message, V, F>
|
||||||
View<ParentState, Action, Context, Message> for MapState<ParentState, ChildState, V, F>
|
View<ParentState, Action, Context, Message> for MapState<ParentState, ChildState, V, F>
|
||||||
where
|
where
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
|
|
||||||
use crate::{MessageResult, Mut, View, ViewId, ViewPathTracker};
|
use crate::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
/// A view which supports Memoization.
|
/// A view which supports Memoization.
|
||||||
///
|
///
|
||||||
|
@ -64,6 +64,7 @@ pub struct MemoizeState<V, VState> {
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Data, ViewFn, State, Action> ViewMarker for Memoize<Data, ViewFn, State, Action> {}
|
||||||
impl<State, Action, Context, Data, V, ViewFn, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context, Data, V, ViewFn, Message> View<State, Action, Context, Message>
|
||||||
for Memoize<Data, ViewFn, State, Action>
|
for Memoize<Data, ViewFn, State, Action>
|
||||||
where
|
where
|
||||||
|
@ -172,6 +173,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<InitView, State, Action> ViewMarker for Frozen<InitView, State, Action> {}
|
||||||
impl<State, Action, Context, Message, V, InitView> View<State, Action, Context, Message>
|
impl<State, Action, Context, Message, V, InitView> View<State, Action, Context, Message>
|
||||||
for Frozen<InitView, State, Action>
|
for Frozen<InitView, State, Action>
|
||||||
where
|
where
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
//! Statically typed alternatives to the type-erased [`AnyView`](`crate::AnyView`).
|
//! Statically typed alternatives to the type-erased [`AnyView`](`crate::AnyView`).
|
||||||
|
|
||||||
use crate::{MessageResult, Mut, View, ViewElement, ViewId, ViewPathTracker};
|
use crate::{MessageResult, Mut, View, ViewElement, ViewId, ViewMarker, ViewPathTracker};
|
||||||
use hidden::OneOfState;
|
use hidden::OneOfState;
|
||||||
|
|
||||||
/// This trait allows, specifying a type as `ViewElement`, which should never be constructed or used,
|
/// This trait allows, specifying a type as `ViewElement`, which should never be constructed or used,
|
||||||
|
@ -146,6 +146,7 @@ pub trait OneOfCtx<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<A, B, C, D, E, F, G, H, I> ViewMarker for OneOf<A, B, C, D, E, F, G, H, I> {}
|
||||||
/// The `OneOf` types and `Either` are [`View`]s if all of their possible types are themselves `View`s.
|
/// The `OneOf` types and `Either` are [`View`]s if all of their possible types are themselves `View`s.
|
||||||
impl<State, Action, Context, Message, A, B, C, D, E, F, G, H, I>
|
impl<State, Action, Context, Message, A, B, C, D, E, F, G, H, I>
|
||||||
View<State, Action, Context, Message> for OneOf<A, B, C, D, E, F, G, H, I>
|
View<State, Action, Context, Message> for OneOf<A, B, C, D, E, F, G, H, I>
|
||||||
|
@ -517,13 +518,14 @@ where
|
||||||
// to export it. Since this (`one_of`) module is public, we create a new module, allowing it to be pub but not exposed.
|
// to export it. Since this (`one_of`) module is public, we create a new module, allowing it to be pub but not exposed.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
mod hidden {
|
mod hidden {
|
||||||
use crate::View;
|
use crate::{View, ViewMarker};
|
||||||
|
|
||||||
use super::PhantomElementCtx;
|
use super::PhantomElementCtx;
|
||||||
|
|
||||||
#[allow(unreachable_pub)]
|
#[allow(unreachable_pub)]
|
||||||
pub enum Never {}
|
pub enum Never {}
|
||||||
|
|
||||||
|
impl ViewMarker for Never {}
|
||||||
impl<State, Action, Context: PhantomElementCtx, Message> View<State, Action, Context, Message>
|
impl<State, Action, Context: PhantomElementCtx, Message> View<State, Action, Context, Message>
|
||||||
for Never
|
for Never
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright 2024 the Xilem Authors
|
// Copyright 2024 the Xilem Authors
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::{DynMessage, MessageResult, Mut, View, ViewElement, ViewId, ViewPathTracker};
|
use crate::{
|
||||||
|
DynMessage, MessageResult, Mut, View, ViewElement, ViewId, ViewMarker, ViewPathTracker,
|
||||||
|
};
|
||||||
|
|
||||||
/// This trait provides a way to add [`View`] implementations for types that would be restricted otherwise by the orphan rules.
|
/// This trait provides a way to add [`View`] implementations for types that would be restricted otherwise by the orphan rules.
|
||||||
/// Every type that can be supported with this trait, needs a concrete `View` implementation in `xilem_core`, possibly feature-gated.
|
/// Every type that can be supported with this trait, needs a concrete `View` implementation in `xilem_core`, possibly feature-gated.
|
||||||
|
@ -43,6 +45,8 @@ pub trait OrphanView<V, State, Action, Message = DynMessage>: ViewPathTracker +
|
||||||
|
|
||||||
macro_rules! impl_orphan_view_for {
|
macro_rules! impl_orphan_view_for {
|
||||||
($ty: ty) => {
|
($ty: ty) => {
|
||||||
|
impl ViewMarker for $ty {}
|
||||||
|
|
||||||
impl<State, Action, Context, Message> View<State, Action, Context, Message> for $ty
|
impl<State, Action, Context, Message> View<State, Action, Context, Message> for $ty
|
||||||
where
|
where
|
||||||
Context: OrphanView<$ty, State, Action, Message>,
|
Context: OrphanView<$ty, State, Action, Message>,
|
||||||
|
@ -111,7 +115,7 @@ impl_orphan_view_for!(usize);
|
||||||
/// These [`OrphanView`] implementations can e.g. be used in a vector graphics context, as for example seen in `xilem_web` within svg nodes
|
/// These [`OrphanView`] implementations can e.g. be used in a vector graphics context, as for example seen in `xilem_web` within svg nodes
|
||||||
mod kurbo {
|
mod kurbo {
|
||||||
use super::OrphanView;
|
use super::OrphanView;
|
||||||
use crate::{MessageResult, Mut, View, ViewId};
|
use crate::{MessageResult, Mut, View, ViewId, ViewMarker};
|
||||||
impl_orphan_view_for!(kurbo::PathSeg);
|
impl_orphan_view_for!(kurbo::PathSeg);
|
||||||
impl_orphan_view_for!(kurbo::Arc);
|
impl_orphan_view_for!(kurbo::Arc);
|
||||||
impl_orphan_view_for!(kurbo::BezPath);
|
impl_orphan_view_for!(kurbo::BezPath);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use crate::{MessageResult, NoElement, View, ViewPathTracker};
|
use crate::{MessageResult, NoElement, View, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
/// A view which executes `once` exactly once.
|
/// A view which executes `once` exactly once.
|
||||||
///
|
///
|
||||||
|
@ -75,6 +75,7 @@ pub struct RunOnce<F> {
|
||||||
once: F,
|
once: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F> ViewMarker for RunOnce<F> {}
|
||||||
impl<F, State, Action, Context, Message> View<State, Action, Context, Message> for RunOnce<F>
|
impl<F, State, Action, Context, Message> View<State, Action, Context, Message> for RunOnce<F>
|
||||||
where
|
where
|
||||||
Context: ViewPathTracker,
|
Context: ViewPathTracker,
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
#![allow(dead_code)] // This is a utility module, which means that some exposed items aren't
|
#![allow(dead_code)] // This is a utility module, which means that some exposed items aren't
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use xilem_core::*;
|
use xilem_core::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -68,27 +66,22 @@ pub(super) struct Action {
|
||||||
_priv: (),
|
_priv: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct SequenceView<Seq, Marker> {
|
pub(super) struct SequenceView<Seq> {
|
||||||
id: u32,
|
id: u32,
|
||||||
seq: Seq,
|
seq: Seq,
|
||||||
phantom: PhantomData<Marker>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn sequence<Seq, Marker>(id: u32, seq: Seq) -> SequenceView<Seq, Marker>
|
pub(super) fn sequence<Seq>(id: u32, seq: Seq) -> SequenceView<Seq>
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<(), Action, TestCtx, TestElement, Marker>,
|
Seq: ViewSequence<(), Action, TestCtx, TestElement>,
|
||||||
{
|
{
|
||||||
SequenceView {
|
SequenceView { id, seq }
|
||||||
id,
|
|
||||||
seq,
|
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Seq, Marker> View<(), Action, TestCtx> for SequenceView<Seq, Marker>
|
impl<Seq> ViewMarker for SequenceView<Seq> {}
|
||||||
|
impl<Seq> View<(), Action, TestCtx> for SequenceView<Seq>
|
||||||
where
|
where
|
||||||
Seq: ViewSequence<(), Action, TestCtx, TestElement, Marker>,
|
Seq: ViewSequence<(), Action, TestCtx, TestElement>,
|
||||||
Marker: 'static,
|
|
||||||
{
|
{
|
||||||
type Element = TestElement;
|
type Element = TestElement;
|
||||||
|
|
||||||
|
@ -160,6 +153,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<const N: u32> ViewMarker for OperationView<N> {}
|
||||||
impl<const N: u32> View<(), Action, TestCtx> for OperationView<N> {
|
impl<const N: u32> View<(), Action, TestCtx> for OperationView<N> {
|
||||||
type Element = TestElement;
|
type Element = TestElement;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId};
|
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId, ViewMarker};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
vecmap::VecMap, AttributeValue, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx,
|
vecmap::VecMap, AttributeValue, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx,
|
||||||
|
@ -249,7 +249,8 @@ impl<E, T, A> Attr<E, T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A, E> View<T, A, ViewCtx, DynMessage> for Attr<E, T, A>
|
impl<E, T, A> ViewMarker for Attr<E, T, A> {}
|
||||||
|
impl<E, T, A> View<T, A, ViewCtx, DynMessage> for Attr<E, T, A>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
A: 'static,
|
A: 'static,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
|
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId};
|
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId, ViewMarker};
|
||||||
|
|
||||||
use crate::{vecmap::VecMap, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx};
|
use crate::{vecmap::VecMap, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx};
|
||||||
|
|
||||||
|
@ -289,6 +289,7 @@ impl<E, C, T, A> Class<E, C, T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E, C, T, A> ViewMarker for Class<E, C, T, A> {}
|
||||||
impl<E, C, T, A> View<T, A, ViewCtx, DynMessage> for Class<E, C, T, A>
|
impl<E, C, T, A> View<T, A, ViewCtx, DynMessage> for Class<E, C, T, A>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
use wasm_bindgen::{closure::Closure, JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{closure::Closure, JsCast, UnwrapThrowExt};
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use xilem_core::{MessageResult, Mut, NoElement, View, ViewId, ViewPathTracker};
|
use xilem_core::{MessageResult, Mut, NoElement, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
use crate::{DynMessage, OptionalAction, ViewCtx};
|
use crate::{DynMessage, OptionalAction, ViewCtx};
|
||||||
|
|
||||||
|
@ -153,6 +153,10 @@ enum MemoizedAwaitMessage<Output: std::fmt::Debug> {
|
||||||
ScheduleUpdate,
|
ScheduleUpdate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<State, Action, OA, InitFuture, Data, CB, F, FOut> ViewMarker
|
||||||
|
for MemoizedAwait<State, Action, OA, InitFuture, Data, CB, F, FOut>
|
||||||
|
{
|
||||||
|
}
|
||||||
impl<State, Action, InitFuture, F, FOut, Data, CB, OA> View<State, Action, ViewCtx, DynMessage>
|
impl<State, Action, InitFuture, F, FOut, Data, CB, OA> View<State, Action, ViewCtx, DynMessage>
|
||||||
for MemoizedAwait<State, Action, OA, InitFuture, Data, CB, F, FOut>
|
for MemoizedAwait<State, Action, OA, InitFuture, Data, CB, F, FOut>
|
||||||
where
|
where
|
||||||
|
|
|
@ -8,23 +8,17 @@ use std::{any::Any, rc::Rc};
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{AppendVec, ElementSplice, MessageResult, Mut, View, ViewId, ViewSequence},
|
core::{AppendVec, ElementSplice, MessageResult, Mut, View, ViewId, ViewMarker},
|
||||||
document,
|
document,
|
||||||
element_props::ElementProps,
|
element_props::ElementProps,
|
||||||
vec_splice::VecSplice,
|
vec_splice::VecSplice,
|
||||||
AnyPod, DomNode, DynMessage, Pod, ViewCtx, HTML_NS,
|
AnyPod, DomFragment, DomNode, DynMessage, Pod, ViewCtx, HTML_NS,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod sealed {
|
|
||||||
pub trait Sealed<State, Action, SeqMarker> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sealed, because this should only cover `ViewSequences` with the blanket impl below
|
// sealed, because this should only cover `ViewSequences` with the blanket impl below
|
||||||
/// This is basically a specialized dynamically dispatchable [`ViewSequence`], It's currently not able to change the underlying type unlike [`AnyDomView`](crate::AnyDomView), so it should not be used as `dyn DomViewSequence`.
|
/// This is basically a specialized dynamically dispatchable [`ViewSequence`], It's currently not able to change the underlying type unlike [`AnyDomView`](crate::AnyDomView), so it should not be used as `dyn DomViewSequence`.
|
||||||
/// It's mostly a hack to avoid a completely static view tree, which unfortunately brings rustc (type-checking) down to its knees and results in long compile-times
|
/// It's mostly a hack to avoid a completely static view tree, which unfortunately brings rustc (type-checking) down to its knees and results in long compile-times
|
||||||
pub(crate) trait DomViewSequence<State, Action, SeqMarker>:
|
pub(crate) trait DomViewSequence<State, Action>: 'static {
|
||||||
sealed::Sealed<State, Action, SeqMarker> + 'static
|
|
||||||
{
|
|
||||||
/// Get an [`Any`] reference to `self`.
|
/// Get an [`Any`] reference to `self`.
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
@ -35,7 +29,7 @@ pub(crate) trait DomViewSequence<State, Action, SeqMarker>:
|
||||||
/// Update the associated widgets.
|
/// Update the associated widgets.
|
||||||
fn dyn_seq_rebuild(
|
fn dyn_seq_rebuild(
|
||||||
&self,
|
&self,
|
||||||
prev: &dyn DomViewSequence<State, Action, SeqMarker>,
|
prev: &dyn DomViewSequence<State, Action>,
|
||||||
seq_state: &mut Box<dyn Any>,
|
seq_state: &mut Box<dyn Any>,
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
elements: &mut DomChildrenSplice,
|
elements: &mut DomChildrenSplice,
|
||||||
|
@ -62,21 +56,11 @@ pub(crate) trait DomViewSequence<State, Action, SeqMarker>:
|
||||||
) -> MessageResult<Action, DynMessage>;
|
) -> MessageResult<Action, DynMessage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, SeqMarker, S> sealed::Sealed<State, Action, SeqMarker> for S
|
impl<State, Action, S> DomViewSequence<State, Action> for S
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
S: ViewSequence<State, Action, ViewCtx, AnyPod, SeqMarker, DynMessage>,
|
S: DomFragment<State, Action>,
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<State, Action, SeqMarker, S> DomViewSequence<State, Action, SeqMarker> for S
|
|
||||||
where
|
|
||||||
State: 'static,
|
|
||||||
SeqMarker: 'static,
|
|
||||||
Action: 'static,
|
|
||||||
S: ViewSequence<State, Action, ViewCtx, AnyPod, SeqMarker, DynMessage>,
|
|
||||||
{
|
{
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
|
@ -88,7 +72,7 @@ where
|
||||||
|
|
||||||
fn dyn_seq_rebuild(
|
fn dyn_seq_rebuild(
|
||||||
&self,
|
&self,
|
||||||
prev: &dyn DomViewSequence<State, Action, SeqMarker>,
|
prev: &dyn DomViewSequence<State, Action>,
|
||||||
seq_state: &mut Box<dyn Any>,
|
seq_state: &mut Box<dyn Any>,
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
elements: &mut DomChildrenSplice,
|
elements: &mut DomChildrenSplice,
|
||||||
|
@ -233,8 +217,8 @@ impl ElementState {
|
||||||
|
|
||||||
// These (boilerplatey) functions are there to reduce the boilerplate created by the macro-expansion below.
|
// These (boilerplatey) functions are there to reduce the boilerplate created by the macro-expansion below.
|
||||||
|
|
||||||
pub(crate) fn build_element<State, Action, Element, SeqMarker>(
|
pub(crate) fn build_element<State, Action, Element>(
|
||||||
children: &dyn DomViewSequence<State, Action, SeqMarker>,
|
children: &dyn DomViewSequence<State, Action>,
|
||||||
tag_name: &str,
|
tag_name: &str,
|
||||||
ns: &str,
|
ns: &str,
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
|
@ -243,7 +227,6 @@ where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
Element: 'static,
|
Element: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
Element: From<Pod<web_sys::Element, ElementProps>>,
|
Element: From<Pod<web_sys::Element, ElementProps>>,
|
||||||
{
|
{
|
||||||
let mut elements = AppendVec::default();
|
let mut elements = AppendVec::default();
|
||||||
|
@ -254,9 +237,9 @@ where
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn rebuild_element<'el, State, Action, Element, SeqMarker>(
|
pub(crate) fn rebuild_element<'el, State, Action, Element>(
|
||||||
children: &dyn DomViewSequence<State, Action, SeqMarker>,
|
children: &dyn DomViewSequence<State, Action>,
|
||||||
prev_children: &dyn DomViewSequence<State, Action, SeqMarker>,
|
prev_children: &dyn DomViewSequence<State, Action>,
|
||||||
element: Mut<'el, Pod<Element, ElementProps>>,
|
element: Mut<'el, Pod<Element, ElementProps>>,
|
||||||
state: &mut ElementState,
|
state: &mut ElementState,
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
|
@ -265,7 +248,6 @@ where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
Element: 'static,
|
Element: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
Element: DomNode<ElementProps>,
|
Element: DomNode<ElementProps>,
|
||||||
{
|
{
|
||||||
let mut dom_children_splice = DomChildrenSplice::new(
|
let mut dom_children_splice = DomChildrenSplice::new(
|
||||||
|
@ -285,8 +267,8 @@ where
|
||||||
element
|
element
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn teardown_element<State, Action, Element, SeqMarker>(
|
pub(crate) fn teardown_element<State, Action, Element>(
|
||||||
children: &dyn DomViewSequence<State, Action, SeqMarker>,
|
children: &dyn DomViewSequence<State, Action>,
|
||||||
element: Mut<'_, Pod<Element, ElementProps>>,
|
element: Mut<'_, Pod<Element, ElementProps>>,
|
||||||
state: &mut ElementState,
|
state: &mut ElementState,
|
||||||
ctx: &mut ViewCtx,
|
ctx: &mut ViewCtx,
|
||||||
|
@ -294,7 +276,6 @@ pub(crate) fn teardown_element<State, Action, Element, SeqMarker>(
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
Element: 'static,
|
Element: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
Element: DomNode<ElementProps>,
|
Element: DomNode<ElementProps>,
|
||||||
{
|
{
|
||||||
let mut dom_children_splice = DomChildrenSplice::new(
|
let mut dom_children_splice = DomChildrenSplice::new(
|
||||||
|
@ -309,34 +290,31 @@ pub(crate) fn teardown_element<State, Action, Element, SeqMarker>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An element that can change its tag, it's useful for autonomous custom elements (i.e. web components)
|
/// An element that can change its tag, it's useful for autonomous custom elements (i.e. web components)
|
||||||
pub struct CustomElement<State, Action, SeqMarker> {
|
pub struct CustomElement<State, Action> {
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
children: Box<dyn DomViewSequence<State, Action, SeqMarker>>,
|
children: Box<dyn DomViewSequence<State, Action>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An element that can change its tag, it's useful for autonomous custom elements (i.e. web components)
|
/// An element that can change its tag, it's useful for autonomous custom elements (i.e. web components)
|
||||||
pub fn custom_element<State, Action, SeqMarker, Children>(
|
pub fn custom_element<State, Action, Children>(
|
||||||
name: impl Into<Cow<'static, str>>,
|
name: impl Into<Cow<'static, str>>,
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> CustomElement<State, Action, SeqMarker>
|
) -> CustomElement<State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
SeqMarker: 'static,
|
Children: DomFragment<State, Action>,
|
||||||
Children: ViewSequence<State, Action, ViewCtx, AnyPod, SeqMarker, DynMessage>,
|
|
||||||
{
|
{
|
||||||
CustomElement {
|
CustomElement {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
children: Box::new(children),
|
children: Box::new(children),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<State, Action> ViewMarker for CustomElement<State, Action> {}
|
||||||
impl<State, Action, SeqMarker> View<State, Action, ViewCtx, DynMessage>
|
impl<State, Action> View<State, Action, ViewCtx, DynMessage> for CustomElement<State, Action>
|
||||||
for CustomElement<State, Action, SeqMarker>
|
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
{
|
{
|
||||||
type Element = Pod<web_sys::HtmlElement, ElementProps>;
|
type Element = Pod<web_sys::HtmlElement, ElementProps>;
|
||||||
|
|
||||||
|
@ -403,32 +381,26 @@ macro_rules! define_element {
|
||||||
define_element!($ns, ($ty_name, $name, $dom_interface, stringify!($name)));
|
define_element!($ns, ($ty_name, $name, $dom_interface, stringify!($name)));
|
||||||
};
|
};
|
||||||
($ns:expr, ($ty_name:ident, $name:ident, $dom_interface:ident, $tag_name:expr)) => {
|
($ns:expr, ($ty_name:ident, $name:ident, $dom_interface:ident, $tag_name:expr)) => {
|
||||||
pub struct $ty_name<State, Action, SeqMarker> {
|
pub struct $ty_name<State, Action> {
|
||||||
children: Box<dyn DomViewSequence<State, Action, SeqMarker>>,
|
children: Box<dyn DomViewSequence<State, Action>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder function for a
|
/// Builder function for a
|
||||||
#[doc = concat!("`", $tag_name, "`")]
|
#[doc = concat!("`", $tag_name, "`")]
|
||||||
/// element view.
|
/// element view.
|
||||||
pub fn $name<
|
pub fn $name<State: 'static, Action: 'static, Children: DomFragment<State, Action>>(
|
||||||
State: 'static,
|
|
||||||
Action: 'static,
|
|
||||||
SeqMarker: 'static,
|
|
||||||
Children: ViewSequence<State, Action, ViewCtx, AnyPod, SeqMarker, DynMessage>,
|
|
||||||
>(
|
|
||||||
children: Children,
|
children: Children,
|
||||||
) -> $ty_name<State, Action, SeqMarker> {
|
) -> $ty_name<State, Action> {
|
||||||
$ty_name {
|
$ty_name {
|
||||||
children: Box::new(children),
|
children: Box::new(children),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, Action, SeqMarker> View<State, Action, ViewCtx, DynMessage>
|
impl<State, Action> ViewMarker for $ty_name<State, Action> {}
|
||||||
for $ty_name<State, Action, SeqMarker>
|
impl<State, Action> View<State, Action, ViewCtx, DynMessage> for $ty_name<State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
Action: 'static,
|
Action: 'static,
|
||||||
SeqMarker: 'static,
|
|
||||||
{
|
{
|
||||||
type Element = Pod<web_sys::$dom_interface, ElementProps>;
|
type Element = Pod<web_sys::$dom_interface, ElementProps>;
|
||||||
|
|
||||||
|
@ -485,8 +457,8 @@ macro_rules! define_elements {
|
||||||
($ns:ident, $($element_def:tt,)*) => {
|
($ns:ident, $($element_def:tt,)*) => {
|
||||||
use super::{build_element, rebuild_element, teardown_element, DomViewSequence, ElementState};
|
use super::{build_element, rebuild_element, teardown_element, DomViewSequence, ElementState};
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{MessageResult, Mut, ViewId, ViewSequence},
|
core::{MessageResult, Mut, ViewId, ViewMarker},
|
||||||
AnyPod, DynMessage, ElementProps, Pod, View, ViewCtx,
|
DomFragment, DynMessage, ElementProps, Pod, View, ViewCtx,
|
||||||
};
|
};
|
||||||
$(define_element!(crate::$ns, $element_def);)*
|
$(define_element!(crate::$ns, $element_def);)*
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use std::{borrow::Cow, marker::PhantomData};
|
use std::{borrow::Cow, marker::PhantomData};
|
||||||
use wasm_bindgen::{prelude::Closure, throw_str, JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{prelude::Closure, throw_str, JsCast, UnwrapThrowExt};
|
||||||
use web_sys::AddEventListenerOptions;
|
use web_sys::AddEventListenerOptions;
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewId, ViewPathTracker};
|
use xilem_core::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
use crate::{DynMessage, ElementAsRef, OptionalAction, ViewCtx};
|
use crate::{DynMessage, ElementAsRef, OptionalAction, ViewCtx};
|
||||||
|
|
||||||
|
@ -224,6 +224,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action, Event, Callback> ViewMarker for OnEvent<V, State, Action, Event, Callback> {}
|
||||||
impl<V, State, Action, Event, Callback, OA> View<State, Action, ViewCtx, DynMessage>
|
impl<V, State, Action, Event, Callback, OA> View<State, Action, ViewCtx, DynMessage>
|
||||||
for OnEvent<V, State, Action, Event, Callback>
|
for OnEvent<V, State, Action, Event, Callback>
|
||||||
where
|
where
|
||||||
|
@ -327,6 +328,7 @@ macro_rules! event_definitions {
|
||||||
pub(crate) phantom_event_ty: PhantomData<fn() -> (State, Action)>,
|
pub(crate) phantom_event_ty: PhantomData<fn() -> (State, Action)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action, Callback> ViewMarker for $ty_name<V, State, Action, Callback> {}
|
||||||
impl<V, State, Action, Callback> $ty_name<V, State, Action, Callback> {
|
impl<V, State, Action, Callback> $ty_name<V, State, Action, Callback> {
|
||||||
pub fn new(element: V, handler: Callback) -> Self {
|
pub fn new(element: V, handler: Callback) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
@ -59,6 +59,7 @@ pub use optional_action::{Action, OptionalAction};
|
||||||
pub use pointer::{Pointer, PointerDetails, PointerMsg};
|
pub use pointer::{Pointer, PointerDetails, PointerMsg};
|
||||||
pub use style::{style, ElementWithStyle, IntoStyles, Style, Styles, WithStyle};
|
pub use style::{style, ElementWithStyle, IntoStyles, Style, Styles, WithStyle};
|
||||||
pub use xilem_core as core;
|
pub use xilem_core as core;
|
||||||
|
use xilem_core::ViewSequence;
|
||||||
|
|
||||||
/// A trait used for type erasure of [`DomNode`]s
|
/// A trait used for type erasure of [`DomNode`]s
|
||||||
/// It is e.g. used in [`AnyPod`]
|
/// It is e.g. used in [`AnyPod`]
|
||||||
|
@ -169,6 +170,26 @@ where
|
||||||
type Props = P;
|
type Props = P;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ordered sequence of views, or sometimes also called fragment, it's used for `0..N` [`DomView`]s.
|
||||||
|
/// See [`ViewSequence`] for more technical details.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// fn huzzah(clicks: i32) -> impl xilem_web::DomFragment<i32> {
|
||||||
|
/// (clicks >= 5).then_some("Huzzah, clicked at least 5 times")
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait DomFragment<State, Action = ()>:
|
||||||
|
ViewSequence<State, Action, ViewCtx, AnyPod, DynMessage>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action> DomFragment<State, Action> for V where
|
||||||
|
V: ViewSequence<State, Action, ViewCtx, AnyPod, DynMessage>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// A container, which holds the actual DOM node, and associated props, such as attributes or classes.
|
/// A container, which holds the actual DOM node, and associated props, such as attributes or classes.
|
||||||
/// These attributes are not directly set on the DOM node to avoid mutating or reading from the DOM tree unnecessarily, and to have more control over the whole update flow.
|
/// These attributes are not directly set on the DOM node to avoid mutating or reading from the DOM tree unnecessarily, and to have more control over the whole update flow.
|
||||||
pub struct Pod<E, P> {
|
pub struct Pod<E, P> {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::marker::PhantomData;
|
||||||
use wasm_bindgen::{prelude::Closure, throw_str, JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{prelude::Closure, throw_str, JsCast, UnwrapThrowExt};
|
||||||
use web_sys::PointerEvent;
|
use web_sys::PointerEvent;
|
||||||
|
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewId, ViewPathTracker};
|
use xilem_core::{MessageResult, Mut, View, ViewId, ViewMarker, ViewPathTracker};
|
||||||
|
|
||||||
use crate::{interfaces::Element, DynMessage, ElementAsRef, ViewCtx};
|
use crate::{interfaces::Element, DynMessage, ElementAsRef, ViewCtx};
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ pub fn pointer<T, A, F: Fn(&mut T, PointerMsg), V: Element<T, A>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action, Callback> ViewMarker for Pointer<V, State, Action, Callback> {}
|
||||||
impl<State, Action, Callback, V> View<State, Action, ViewCtx, DynMessage>
|
impl<State, Action, Callback, V> View<State, Action, ViewCtx, DynMessage>
|
||||||
for Pointer<V, State, Action, Callback>
|
for Pointer<V, State, Action, Callback>
|
||||||
where
|
where
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId};
|
use xilem_core::{MessageResult, Mut, View, ViewElement, ViewId, ViewMarker};
|
||||||
|
|
||||||
use crate::{vecmap::VecMap, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx};
|
use crate::{vecmap::VecMap, DomNode, DynMessage, ElementProps, Pod, PodMut, ViewCtx};
|
||||||
|
|
||||||
|
@ -299,6 +299,7 @@ impl<E, T, A> Style<E, T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E, T, A> ViewMarker for Style<E, T, A> {}
|
||||||
impl<T, A, E> View<T, A, ViewCtx, DynMessage> for Style<E, T, A>
|
impl<T, A, E> View<T, A, ViewCtx, DynMessage> for Style<E, T, A>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::borrow::Cow;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use peniko::Brush;
|
use peniko::Brush;
|
||||||
use xilem_core::{MessageResult, Mut, View, ViewId};
|
use xilem_core::{MessageResult, Mut, View, ViewId, ViewMarker};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attribute::{ElementWithAttributes, WithAttributes},
|
attribute::{ElementWithAttributes, WithAttributes},
|
||||||
|
@ -61,6 +61,7 @@ fn brush_to_string(brush: &Brush) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action> ViewMarker for Fill<V, State, Action> {}
|
||||||
impl<State, Action, V> View<State, Action, ViewCtx, DynMessage> for Fill<V, State, Action>
|
impl<State, Action, V> View<State, Action, ViewCtx, DynMessage> for Fill<V, State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
|
@ -116,6 +117,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<V, State, Action> ViewMarker for Stroke<V, State, Action> {}
|
||||||
impl<State, Action, V> View<State, Action, ViewCtx, DynMessage> for Stroke<V, State, Action>
|
impl<State, Action, V> View<State, Action, ViewCtx, DynMessage> for Stroke<V, State, Action>
|
||||||
where
|
where
|
||||||
State: 'static,
|
State: 'static,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use xilem_web::{
|
||||||
document_body,
|
document_body,
|
||||||
elements::html as el,
|
elements::html as el,
|
||||||
interfaces::{Element, HtmlButtonElement, HtmlDivElement},
|
interfaces::{Element, HtmlButtonElement, HtmlDivElement},
|
||||||
App,
|
App, DomFragment,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -50,9 +50,15 @@ fn btn(
|
||||||
el::button(label).on_click(click_fn)
|
el::button(label).on_click(click_fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// And functions that return a sequence of views.
|
||||||
|
fn huzzah(state: &mut AppState) -> impl DomFragment<AppState> {
|
||||||
|
(state.clicks >= 5).then_some("Huzzah, clicked at least 5 times")
|
||||||
|
}
|
||||||
|
|
||||||
fn app_logic(state: &mut AppState) -> impl HtmlDivElement<AppState> {
|
fn app_logic(state: &mut AppState) -> impl HtmlDivElement<AppState> {
|
||||||
el::div((
|
el::div((
|
||||||
el::span(format!("clicked {} times", state.clicks)).class(state.class),
|
el::span(format!("clicked {} times", state.clicks)).class(state.class),
|
||||||
|
huzzah(state),
|
||||||
el::br(()),
|
el::br(()),
|
||||||
btn("+1 click", |state, _| state.increment()),
|
btn("+1 click", |state, _| state.increment()),
|
||||||
btn("-1 click", |state, _| state.decrement()),
|
btn("-1 click", |state, _| state.decrement()),
|
||||||
|
|
Loading…
Reference in New Issue