Created
October 20, 2020 21:28
-
-
Save PoignardAzur/7336b1fa1e2a31daf83581c799ce60b7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| pub trait VirtualDom { | |
| fn update_value(&mut self, other: Self); | |
| #[track_caller] | |
| fn init_tree(&self, cx: &mut Cx); | |
| fn apply_diff(&self, other: &Self, cx: &mut Cx) -> bool; | |
| } | |
| pub enum VDomLeaf { | |
| Button(String), | |
| Label(String), | |
| }; | |
| impl VirtualDom for VDomLeaf { | |
| fn update_value(&mut self, other: Self) { | |
| self = other; | |
| } | |
| #[track_caller] | |
| fn init_tree(&self, cx: &mut Cx) { | |
| match &self { | |
| Button(text) => cx.leaf_view(crate::Button(text, Location::caller())), | |
| Label(text) => cx.leaf_view(crate::Label(text, Location::caller())), | |
| }; | |
| } | |
| fn apply_diff(&self, other: &Self, cx: &mut Cx) { | |
| if (&self == &other) { | |
| cx.skip(1); | |
| } | |
| else { | |
| match &self { | |
| Button(text) => cx.leaf_view(crate::Button(text, Location::caller())), | |
| Label(text) => cx.leaf_view(crate::Label(text, Location::caller())), | |
| }; | |
| } | |
| } | |
| } | |
| pub struct ComponentTuple<C0, C1, C2, C3, C4, C5, C6, C7>(C0, C1, C2, C3, C4, C5, C6, C7); | |
| impl<C0, C1, C2, C3, C4, C5, C6, C7> VirtualDom for ComponentTuple<C0, C1, C2, C3, C4, C5, C6, C7> { | |
| fn update_value(&mut self, other: Self) { | |
| self = other; | |
| } | |
| #[track_caller] | |
| fn init_tree(&self, cx: &mut Cx) { | |
| self.0.init_tree(cx); | |
| self.1.init_tree(cx); | |
| self.2.init_tree(cx); | |
| self.3.init_tree(cx); | |
| self.4.init_tree(cx); | |
| self.5.init_tree(cx); | |
| self.6.init_tree(cx); | |
| self.7.init_tree(cx); | |
| } | |
| fn apply_diff(&self, other: &Self, cx: &mut Cx) { | |
| self.0.apply_diff(other.0, cx); | |
| self.1.apply_diff(other.1, cx); | |
| self.2.apply_diff(other.2, cx); | |
| self.3.apply_diff(other.3, cx); | |
| self.4.apply_diff(other.4, cx); | |
| self.5.apply_diff(other.5, cx); | |
| self.6.apply_diff(other.6, cx); | |
| self.7.apply_diff(other.7, cx); | |
| } | |
| } | |
| // Instead of doing multiple implementations of TupleComponent for different tuple sizes, | |
| // I'm being lazy and doing one implem for a huge tuple, and stuffing it with EmptyComponent | |
| // when using it. It's *a lot* easier. | |
| pub struct EmptyComponent(); | |
| impl VirtualDom for EmptyComponent { | |
| fn update_value(&mut self, other: Self) {} | |
| #[track_caller] | |
| fn init_tree(&self, cx: &mut Cx) {} | |
| fn apply_diff(&self, other: &Self, cx: &mut Cx) {} | |
| } | |
| pub struct ComponentList<Comp> { | |
| components: Vec<(String, Comp)> | |
| } | |
| impl VirtualDom for ComponentList<Comp> { | |
| fn update_value(&mut self, other: Self) { | |
| self = other; | |
| } | |
| #[track_caller] | |
| fn init_tree(&self, cx: &mut Cx) { | |
| cx.begin_insert(); | |
| for (_, comp) in self.components { | |
| comp.init_tree(cx); | |
| } | |
| cx.end(); | |
| } | |
| // This only works if we assume that items are ever only added at the end of the list. | |
| // Sounds perfectly reasonable to me. | |
| // (seriously though, a serious implementation would try to do whatever crochet::List::run does) | |
| fn apply_diff(&self, other: &Self, cx: &mut Cx) { | |
| for (other_id, other_comp) in other.components { | |
| if let (_, comp) = self.components.find(|(id, _)| id == other_id) { | |
| cx.begin_update(); | |
| comp.apply_diff(other_comp, cx); | |
| cx.end(); | |
| } | |
| else { | |
| cx.delete(1); | |
| } | |
| } | |
| for (id, comp) in self.components { | |
| if other.components.find(|(other_id, _)| id == other_id).is_none() { | |
| cx.begin_insert(); | |
| comp.init_tree(cx); | |
| cx.end(); | |
| } | |
| } | |
| } | |
| } | |
| pub struct ReactComponent<Props, VDom : VirtualDom> { | |
| component: Fn(Props) -> VDom, | |
| prev_vdom: VDom | |
| } | |
| impl ReactComponent<Props> { | |
| fn run(&mut self, cx: &mut Cx, props: &Props) { | |
| let vdom = self.component(props); | |
| } | |
| } | |
| struct Props { | |
| data: ListData<String>, | |
| selected_row: Option<i32>, | |
| counter: usize, | |
| } | |
| fn some_component(props: Props) -> impl VirtualDom { | |
| let buttonCreate = Button::new("Create"); | |
| // TODO - on pressed Create | |
| let buttonDelete = Button::new("Delete"); | |
| // TODO - on pressed Delete | |
| let buttonUpdate = Button::new("Update"); | |
| // TODO - on pressed Update | |
| let listView = props.data.map_i(|txt: &String, id: i32| { | |
| list_row(txt, id == props.selected_row.or(-1)); | |
| }); | |
| ComponentTuple( | |
| buttonCreate, | |
| buttonDelete, | |
| buttonUpdate, | |
| listView, | |
| ) | |
| } | |
| fn some_component(row_str: &String, is_selected: bool) -> impl VirtualDom { | |
| ComponentTuple( | |
| Button::new("Select"), // TODO - change selected | |
| Label::new(if is_selected { "[*]" } else { "[ ]" }), | |
| Label::new(row_str) | |
| ) | |
| } | |
| impl MyAppLogic { | |
| fn run(&mut self, cx: &mut Cx) { | |
| Row::new().build(cx, |cx| { | |
| if Button::new("Create").build(cx) { | |
| self.data.push(format!("item {}", self.counter)); | |
| self.counter += 1; | |
| } | |
| if Button::new("Delete").build(cx) { | |
| if let Some(id) = self.list_view.selected() { | |
| if let Some(ix) = self.data.find_id(id) { | |
| self.data.remove_at_ix(ix); | |
| } | |
| } | |
| } | |
| if Button::new("Update").build(cx) { | |
| if let Some(id) = self.list_view.selected() { | |
| if let Some(ix) = self.data.find_id(id) { | |
| self.data.set_at_ix(ix, format!("update {}", self.counter)); | |
| self.counter += 1; | |
| } | |
| } | |
| } | |
| }); | |
| let mut new_sel = None; | |
| self.list_view | |
| .run(cx, &self.data, |cx, is_selected, id: Id, item| { | |
| Row::new().build(cx, |cx| { | |
| if Button::new("Select").build(cx) { | |
| new_sel = Some(id); | |
| } | |
| let sel_str = if is_selected { "[*]" } else { "[ ]" }; | |
| Label::new(format!("{} {}", sel_str, item)).build(cx); | |
| }); | |
| }); | |
| if let Some(id) = new_sel { | |
| self.list_view.select(id); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment