1use super::{Key, VDiff, VNode, VText};
3use crate::html::{AnyScope, NodeRef};
4use cfg_if::cfg_if;
5use std::collections::{HashMap, HashSet};
6use std::ops::{Deref, DerefMut};
7cfg_if! {
8 if #[cfg(feature = "std_web")] {
9 use stdweb::web::Element;
10 } else if #[cfg(feature = "web_sys")] {
11 use web_sys::Element;
12 }
13}
14
15#[derive(Clone, Debug, PartialEq, Default)]
17pub struct VList {
18 pub children: Vec<VNode>,
20 pub key: Option<Key>,
21}
22
23impl Deref for VList {
24 type Target = Vec<VNode>;
25
26 fn deref(&self) -> &Self::Target {
27 &self.children
28 }
29}
30
31impl DerefMut for VList {
32 fn deref_mut(&mut self) -> &mut Self::Target {
33 &mut self.children
34 }
35}
36
37impl VList {
38 pub fn new() -> Self {
40 Self::default()
41 }
42
43 pub fn new_with_children(children: Vec<VNode>, key: Option<Key>) -> Self {
45 VList { children, key }
46 }
47
48 pub fn add_child(&mut self, child: VNode) {
50 self.children.push(child);
51 }
52
53 pub fn add_children(&mut self, children: impl IntoIterator<Item = VNode>) {
55 self.children.extend(children);
56 }
57
58 fn children_keys(&self, warn: bool) -> HashSet<Key> {
59 let mut hash_set = HashSet::with_capacity(self.children.len());
60 for l in self.children.iter() {
61 if let Some(k) = l.key() {
62 if !hash_set.insert(k.clone()) && warn {
63 log::warn!("Key '{}' is not unique in list but must be.", k);
64 }
65 }
66 }
67 hash_set
68 }
69}
70
71impl VDiff for VList {
72 fn detach(&mut self, parent: &Element) {
73 for mut child in self.children.drain(..) {
74 child.detach(parent);
75 }
76 }
77
78 fn apply(
79 &mut self,
80 parent_scope: &AnyScope,
81 parent: &Element,
82 next_sibling: NodeRef,
83 ancestor: Option<VNode>,
84 ) -> NodeRef {
85 if self.children.is_empty() {
95 let placeholder = VText::new("");
99 self.children.push(placeholder.into());
100 }
101
102 let left_keys = self.children_keys(true);
103 let lefts_keyed = left_keys.len() == self.children.len();
104
105 let right_keys = if let Some(VNode::VList(vlist)) = &ancestor {
106 vlist.children_keys(false)
107 } else {
108 HashSet::new()
109 };
110
111 let mut right_children = match ancestor {
112 Some(VNode::VList(vlist)) => vlist.children,
115 Some(vnode) => vec![vnode],
117 None => vec![],
118 };
119 let rights_keyed = right_keys.len() == right_children.len();
120
121 if lefts_keyed && rights_keyed {
124 let matched_keys: HashSet<_> = left_keys.intersection(&right_keys).collect();
126
127 right_children = right_children
129 .into_iter()
130 .filter_map(|mut right| {
131 if matched_keys.contains(right.key().as_ref().unwrap()) {
132 Some(right)
133 } else {
134 right.detach(parent);
135 None
136 }
137 })
138 .collect();
139
140 let mut rights_to_move = HashMap::with_capacity(right_children.len());
143 let mut matched_lefts = self
144 .children
145 .iter()
146 .filter(|left| matched_keys.contains(left.key().as_ref().unwrap()))
147 .peekable();
148 let mut left = matched_lefts.next();
149
150 #[allow(clippy::unnecessary_filter_map)]
152 let rights_in_place: Vec<_> = right_children
153 .into_iter()
154 .filter_map(|right| {
155 if right.key() == left.and_then(|l| l.key()) {
156 left = matched_lefts.next();
157 return Some(right);
158 } else if right.key() == matched_lefts.peek().and_then(|l| l.key()) {
159 matched_lefts.next();
160 left = matched_lefts.next();
161 return Some(right);
162 }
163
164 rights_to_move.insert(right.key().unwrap(), right);
165 None
166 })
167 .collect();
168
169 right_children = Vec::with_capacity(matched_keys.len());
171 let mut matched_lefts = self
172 .children
173 .iter()
174 .filter(|left| matched_keys.contains(left.key().as_ref().unwrap()));
175
176 for right in rights_in_place.into_iter() {
177 let mut left = matched_lefts.next().unwrap();
178 while right.key() != left.key() {
179 let right_to_move = rights_to_move.remove(&left.key().unwrap()).unwrap();
180 right_to_move.move_before(parent, Some(right.first_node()));
181 right_children.push(right_to_move);
182 left = matched_lefts.next().unwrap();
183 }
184 right_children.push(right);
185 }
186
187 for left in matched_lefts {
188 let right_to_move = rights_to_move.remove(&left.key().unwrap()).unwrap();
189 right_to_move.move_before(parent, next_sibling.get());
190 right_children.push(right_to_move);
191 }
192
193 assert!(rights_to_move.is_empty())
194 }
195
196 let mut rights = right_children.into_iter().peekable();
197 let mut last_next_sibling = NodeRef::default();
198 let mut nodes: Vec<NodeRef> = self
199 .children
200 .iter_mut()
201 .map(|left| {
202 let ancestor = rights.next();
203
204 let new_next_sibling = NodeRef::default();
207 if let Some(next_right) = rights.peek() {
208 new_next_sibling.set(Some(next_right.first_node()));
209 } else {
210 new_next_sibling.link(next_sibling.clone());
211 }
212
213 let node = left.apply(parent_scope, parent, new_next_sibling.clone(), ancestor);
218 last_next_sibling.link(node.clone());
219 last_next_sibling = new_next_sibling;
220 node
221 })
222 .collect();
223
224 last_next_sibling.link(next_sibling);
227
228 for mut right in rights {
230 right.detach(parent);
231 }
232
233 assert!(!nodes.is_empty(), "VList should have at least one child");
234 nodes.swap_remove(0)
235 }
236}
237
238#[cfg(all(test, feature = "web_sys"))]
239mod layout_tests {
240 extern crate self as yew;
241
242 use crate::html;
243 use crate::virtual_dom::layout_tests::{diff_layouts, TestLayout};
244
245 #[cfg(feature = "wasm_test")]
246 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
247
248 #[cfg(feature = "wasm_test")]
249 wasm_bindgen_test_configure!(run_in_browser);
250
251 #[test]
252 fn diff() {
253 let layout1 = TestLayout {
254 name: "1",
255 node: html! {
256 <>
257 {"a"}
258 {"b"}
259 <>
260 {"c"}
261 {"d"}
262 </>
263 {"e"}
264 </>
265 },
266 expected: "abcde",
267 };
268
269 let layout2 = TestLayout {
270 name: "2",
271 node: html! {
272 <>
273 {"a"}
274 {"b"}
275 <></>
276 {"e"}
277 {"f"}
278 </>
279 },
280 expected: "abef",
281 };
282
283 let layout3 = TestLayout {
284 name: "3",
285 node: html! {
286 <>
287 {"a"}
288 <></>
289 {"b"}
290 {"e"}
291 </>
292 },
293 expected: "abe",
294 };
295
296 let layout4 = TestLayout {
297 name: "4",
298 node: html! {
299 <>
300 {"a"}
301 <>
302 {"c"}
303 {"d"}
304 </>
305 {"b"}
306 {"e"}
307 </>
308 },
309 expected: "acdbe",
310 };
311
312 diff_layouts(vec![layout1, layout2, layout3, layout4]);
313 }
314}
315
316#[cfg(all(test, feature = "web_sys"))]
317mod layout_tests_keys {
318 extern crate self as yew;
319
320 use crate::html;
321 use crate::virtual_dom::layout_tests::{diff_layouts, TestLayout};
322 use crate::virtual_dom::VNode;
323 use crate::{Children, Component, ComponentLink, Html, Properties, ShouldRender};
324 use web_sys::Node;
325
326 #[cfg(feature = "wasm_test")]
327 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
328
329 #[cfg(feature = "wasm_test")]
330 wasm_bindgen_test_configure!(run_in_browser);
331
332 struct Comp {
333 id: usize,
334 panic_if_changes: bool,
335 }
336
337 #[derive(Properties, Clone)]
338 struct CountingCompProps {
339 id: usize,
340 #[prop_or(false)]
341 can_change: bool,
342 }
343
344 impl Component for Comp {
345 type Message = ();
346 type Properties = CountingCompProps;
347
348 fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
349 Comp {
350 id: props.id,
351 panic_if_changes: props.can_change,
352 }
353 }
354
355 fn change(&mut self, props: Self::Properties) -> ShouldRender {
356 #[cfg(feature = "wasm_test")]
357 wasm_bindgen_test::console_log!("Comp changed: {} -> {}", self.id, props.id);
358 let changed = self.id != props.id;
359 if self.panic_if_changes && changed {
360 panic!(
361 "VComp changed but should not have: {} -> {}.",
362 self.id, props.id
363 );
364 }
365 self.id = props.id;
366 changed
367 }
368
369 fn update(&mut self, _: Self::Message) -> ShouldRender {
370 unimplemented!();
371 }
372
373 fn view(&self) -> Html {
374 html! { <p>{ self.id }</p> }
375 }
376 }
377
378 #[derive(Clone, Properties)]
379 pub struct ListProps {
380 pub children: Children,
381 }
382
383 pub struct List(ListProps);
384
385 impl Component for List {
386 type Message = ();
387 type Properties = ListProps;
388
389 fn create(props: Self::Properties, _: ComponentLink<Self>) -> Self {
390 Self(props)
391 }
392
393 fn update(&mut self, _: Self::Message) -> ShouldRender {
394 unimplemented!();
395 }
396
397 fn change(&mut self, mut props: Self::Properties) -> ShouldRender {
398 std::mem::swap(&mut self.0, &mut props);
399 self.0.children != props.children
400 }
401
402 fn view(&self) -> Html {
403 html! { <>{ for self.0.children.iter() }</> }
404 }
405 }
406
407 #[test]
408 fn diff() {
409 let mut layouts = vec![];
410
411 let vref_node: Node = crate::utils::document().create_element("i").unwrap().into();
412 layouts.push(TestLayout {
413 name: "All VNode types as children",
414 node: html! {
415 <>
416 {"a"}
417 <span key="vtag"></span>
418 {"c"}
419 {"d"}
420 <Comp id=0 key="vchild" />
421 <key="vlist">
422 {"foo"}
423 {"bar"}
424 </>
425 {VNode::VRef(vref_node)}
426 </>
427 },
428 expected: "a<span></span>cd<p>0</p>foobar<i></i>",
429 });
430
431 layouts.extend(vec![
432 TestLayout {
433 name: "Inserting into VList first child - before",
434 node: html! {
435 <>
436 <key="VList">
437 <i key="i"></i>
438 </>
439 <p key="p"></p>
440 </>
441 },
442 expected: "<i></i><p></p>",
443 },
444 TestLayout {
445 name: "Inserting into VList first child - after",
446 node: html! {
447 <>
448 <key="VList">
449 <i key="i"></i>
450 <e key="e"></e>
451 </>
452 <p key="p"></p>
453 </>
454 },
455 expected: "<i></i><e></e><p></p>",
456 },
457 ]);
458
459 layouts.extend(vec![
460 TestLayout {
461 name: "No matches - before",
462 node: html! {
463 <>
464 <i key="i"></i>
465 <e key="e"></e>
466 </>
467 },
468 expected: "<i></i><e></e>",
469 },
470 TestLayout {
471 name: "No matches - after",
472 node: html! {
473 <>
474 <a key="a"></a>
475 <p key="p"></p>
476 </>
477 },
478 expected: "<a></a><p></p>",
479 },
480 ]);
481
482 layouts.extend(vec![
483 TestLayout {
484 name: "Append - before",
485 node: html! {
486 <>
487 <i key="i"></i>
488 <e key="e"></e>
489 </>
490 },
491 expected: "<i></i><e></e>",
492 },
493 TestLayout {
494 name: "Append - after",
495 node: html! {
496 <>
497 <i key="i"></i>
498 <e key="e"></e>
499 <p key="p"></p>
500 </>
501 },
502 expected: "<i></i><e></e><p></p>",
503 },
504 ]);
505
506 layouts.extend(vec![
507 TestLayout {
508 name: "Prepend - before",
509 node: html! {
510 <>
511 <i key="i"></i>
512 <e key="e"></e>
513 </>
514 },
515 expected: "<i></i><e></e>",
516 },
517 TestLayout {
518 name: "Prepend - after",
519 node: html! {
520 <>
521 <p key="p"></p>
522 <i key="i"></i>
523 <e key="e"></e>
524 </>
525 },
526 expected: "<p></p><i></i><e></e>",
527 },
528 ]);
529
530 layouts.extend(vec![
531 TestLayout {
532 name: "Delete first - before",
533 node: html! {
534 <>
535 <i key="i"></i>
536 <e key="e"></e>
537 <p key="p"></p>
538 </>
539 },
540 expected: "<i></i><e></e><p></p>",
541 },
542 TestLayout {
543 name: "Delete first - after",
544 node: html! {
545 <>
546 <e key="e"></e>
547 <p key="p"></p>
548 </>
549 },
550 expected: "<e></e><p></p>",
551 },
552 ]);
553
554 layouts.extend(vec![
555 TestLayout {
556 name: "Delete last - before",
557 node: html! {
558 <>
559 <i key="i"></i>
560 <e key="e"></e>
561 <p key="p"></p>
562 </>
563 },
564 expected: "<i></i><e></e><p></p>",
565 },
566 TestLayout {
567 name: "Delete last - after",
568 node: html! {
569 <>
570 <i key="i"></i>
571 <e key="e"></e>
572 </>
573 },
574 expected: "<i></i><e></e>",
575 },
576 ]);
577
578 layouts.extend(vec![
579 TestLayout {
580 name: "Delete last and change node type - before",
581 node: html! {
582 <>
583 <i key="i"></i>
584 <e key="e"></e>
585 <p key="p"></p>
586 </>
587 },
588 expected: "<i></i><e></e><p></p>",
589 },
590 TestLayout {
591 name: "Delete last - after",
592 node: html! {
593 <>
594 <List key="i"><i/></List>
595 <List key="e"><e/></List>
596 <List key="a"><a/></List>
597 </>
598 },
599 expected: "<i></i><e></e><a></a>",
600 },
601 ]);
602
603 layouts.extend(vec![
604 TestLayout {
605 name: "Delete middle - before",
606 node: html! {
607 <>
608 <i key="i"></i>
609 <e key="e"></e>
610 <p key="p"></p>
611 <a key="a"></a>
612 </>
613 },
614 expected: "<i></i><e></e><p></p><a></a>",
615 },
616 TestLayout {
617 name: "Delete middle - after",
618 node: html! {
619 <>
620 <i key="i"></i>
621 <e key="e2"></e>
622 <p key="p2"></p>
623 <a key="a"></a>
624 </>
625 },
626 expected: "<i></i><e></e><p></p><a></a>",
627 },
628 ]);
629
630 layouts.extend(vec![
631 TestLayout {
632 name: "Delete middle and change node type - before",
633 node: html! {
634 <>
635 <i key="i"></i>
636 <e key="e"></e>
637 <p key="p"></p>
638 <a key="a"></a>
639 </>
640 },
641 expected: "<i></i><e></e><p></p><a></a>",
642 },
643 TestLayout {
644 name: "Delete middle and change node type- after",
645 node: html! {
646 <>
647 <List key="i2"><i/></List>
648 <e key="e"></e>
649 <List key="p"><p/></List>
650 <List key="a2"><a/></List>
651 </>
652 },
653 expected: "<i></i><e></e><p></p><a></a>",
654 },
655 ]);
656
657 layouts.extend(vec![
658 TestLayout {
659 name: "Reverse - before",
660 node: html! {
661 <>
662 <i key="i"></i>
663 <e key="e"></e>
664 <p key="p"></p>
665 <u key="u"></u>
666 </>
667 },
668 expected: "<i></i><e></e><p></p><u></u>",
669 },
670 TestLayout {
671 name: "Reverse - after",
672 node: html! {
673 <>
674 <u key="u"></u>
675 <p key="p"></p>
676 <e key="e"></e>
677 <i key="i"></i>
678 </>
679 },
680 expected: "<u></u><p></p><e></e><i></i>",
681 },
682 ]);
683
684 layouts.extend(vec![
685 TestLayout {
686 name: "Reverse and change node type - before",
687 node: html! {
688 <>
689 <i key="i"></i>
690 <key="i1"></>
691 <key="i2"></>
692 <key="i3"></>
693 <e key="e"></e>
694 <key="yo">
695 <p key="p"></p>
696 </>
697 <u key="u"></u>
698 </>
699 },
700 expected: "<i></i><e></e><p></p><u></u>",
701 },
702 TestLayout {
703 name: "Reverse and change node type - after",
704 node: html! {
705 <>
706 <List key="u"><u/></List>
707 <List key="p"><p/></List>
708 <List key="e"><e/></List>
709 <List key="i"><i/></List>
710 </>
711 },
712 expected: "<u></u><p></p><e></e><i></i>",
713 },
714 ]);
715
716 layouts.extend(vec![
717 TestLayout {
718 name: "Swap 1&2 - before",
719 node: html! {
720 <>
721 <i key="1"></i>
722 <e key="2"></e>
723 <p key="3"></p>
724 <a key="4"></a>
725 <u key="5"></u>
726 </>
727 },
728 expected: "<i></i><e></e><p></p><a></a><u></u>",
729 },
730 TestLayout {
731 name: "Swap 1&2 - after",
732 node: html! {
733 <>
734 <e key="2"></e>
735 <i key="1"></i>
736 <p key="3"></p>
737 <a key="4"></a>
738 <u key="5"></u>
739 </>
740 },
741 expected: "<e></e><i></i><p></p><a></a><u></u>",
742 },
743 ]);
744
745 layouts.extend(vec![
746 TestLayout {
747 name: "Swap 1&2 and change node type - before",
748 node: html! {
749 <>
750 <i key="1"></i>
751 <e key="2"></e>
752 <p key="3"></p>
753 <a key="4"></a>
754 <u key="5"></u>
755 </>
756 },
757 expected: "<i></i><e></e><p></p><a></a><u></u>",
758 },
759 TestLayout {
760 name: "Swap 1&2 and change node type - after",
761 node: html! {
762 <>
763 <List key="2"><e/></List>
764 <List key="1"><i/></List>
765 <List key="3"><p/></List>
766 <List key="4"><a/></List>
767 <List key="5"><u/></List>
768 </>
769 },
770 expected: "<e></e><i></i><p></p><a></a><u></u>",
771 },
772 ]);
773
774 layouts.extend(vec![
775 TestLayout {
776 name: "test - before",
777 node: html! {
778 <>
779 <key="1">
780 <e key="e"></e>
781 <p key="p"></p>
782 <a key="a"></a>
783 <u key="u"></u>
784 </>
785 <key="2">
786 <e key="e"></e>
787 <p key="p"></p>
788 <a key="a"></a>
789 <u key="u"></u>
790 </>
791 </>
792 },
793 expected: "<e></e><p></p><a></a><u></u><e></e><p></p><a></a><u></u>",
794 },
795 TestLayout {
796 name: "Swap 4&5 - after",
797 node: html! {
798 <>
799 <e key="1"></e>
800 <key="2">
801 <p key="p"></p>
802 <i key="i"></i>
803 </>
804 </>
805 },
806 expected: "<e></e><p></p><i></i>",
807 },
808 ]);
809
810 layouts.extend(vec![
811 TestLayout {
812 name: "Swap 4&5 - before",
813 node: html! {
814 <>
815 <i key="1"></i>
816 <e key="2"></e>
817 <p key="3"></p>
818 <a key="4"></a>
819 <u key="5"></u>
820 </>
821 },
822 expected: "<i></i><e></e><p></p><a></a><u></u>",
823 },
824 TestLayout {
825 name: "Swap 4&5 - after",
826 node: html! {
827 <>
828 <i key="1"></i>
829 <e key="2"></e>
830 <p key="3"></p>
831 <u key="5"></u>
832 <a key="4"></a>
833 </>
834 },
835 expected: "<i></i><e></e><p></p><u></u><a></a>",
836 },
837 ]);
838
839 layouts.extend(vec![
840 TestLayout {
841 name: "Swap 1&5 - before",
842 node: html! {
843 <>
844 <i key="1"></i>
845 <e key="2"></e>
846 <p key="3"></p>
847 <a key="4"></a>
848 <u key="5"></u>
849 </>
850 },
851 expected: "<i></i><e></e><p></p><a></a><u></u>",
852 },
853 TestLayout {
854 name: "Swap 1&5 - after",
855 node: html! {
856 <>
857 <u key="5"></u>
858 <e key="2"></e>
859 <p key="3"></p>
860 <a key="4"></a>
861 <i key="1"></i>
862 </>
863 },
864 expected: "<u></u><e></e><p></p><a></a><i></i>",
865 },
866 ]);
867
868 layouts.extend(vec![
869 TestLayout {
870 name: "Move 2 after 4 - before",
871 node: html! {
872 <>
873 <i key="1"></i>
874 <e key="2"></e>
875 <p key="3"></p>
876 <a key="4"></a>
877 <u key="5"></u>
878 </>
879 },
880 expected: "<i></i><e></e><p></p><a></a><u></u>",
881 },
882 TestLayout {
883 name: "Move 2 after 4 - after",
884 node: html! {
885 <>
886 <i key="1"></i>
887 <p key="3"></p>
888 <a key="4"></a>
889 <e key="2"></e>
890 <u key="5"></u>
891 </>
892 },
893 expected: "<i></i><p></p><a></a><e></e><u></u>",
894 },
895 ]);
896
897 layouts.extend(vec![
898 TestLayout {
899 name: "Swap lists - before",
900 node: html! {
901 <>
902 <key="1">
903 <i></i>
904 <e></e>
905 </>
906 <key="2">
907 <a></a>
908 <u></u>
909 </>
910 </>
911 },
912 expected: "<i></i><e></e><a></a><u></u>",
913 },
914 TestLayout {
915 name: "Swap lists - after",
916 node: html! {
917 <>
918 <key="2">
919 <a></a>
920 <u></u>
921 </>
922 <key="1">
923 <i></i>
924 <e></e>
925 </>
926 </>
927 },
928 expected: "<a></a><u></u><i></i><e></e>",
929 },
930 ]);
931
932 layouts.extend(vec![
933 TestLayout {
934 name: "Swap lists with in-between - before",
935 node: html! {
936 <>
937 <key="1">
938 <i></i>
939 <e></e>
940 </>
941 <p key="between"></p>
942 <key="2">
943 <a></a>
944 <u></u>
945 </>
946 </>
947 },
948 expected: "<i></i><e></e><p></p><a></a><u></u>",
949 },
950 TestLayout {
951 name: "Swap lists with in-between - after",
952 node: html! {
953 <>
954 <key="2">
955 <a></a>
956 <u></u>
957 </>
958 <p key="between"></p>
959 <key="1">
960 <i></i>
961 <e></e>
962 </>
963 </>
964 },
965 expected: "<a></a><u></u><p></p><i></i><e></e>",
966 },
967 ]);
968
969 layouts.extend(vec![
970 TestLayout {
971 name: "Insert VComp front - before",
972 node: html! {
973 <>
974 <u key=1></u>
975 <a key=2></a>
976 </>
977 },
978 expected: "<u></u><a></a>",
979 },
980 TestLayout {
981 name: "Insert VComp front - after",
982 node: html! {
983 <>
984 <Comp id=0 key="comp"/>
985 <u key=1></u>
986 <a key=2></a>
987 </>
988 },
989 expected: "<p>0</p><u></u><a></a>",
990 },
991 ]);
992
993 layouts.extend(vec![
994 TestLayout {
995 name: "Insert VComp middle - before",
996 node: html! {
997 <>
998 <u key=1></u>
999 <a key=2></a>
1000 </>
1001 },
1002 expected: "<u></u><a></a>",
1003 },
1004 TestLayout {
1005 name: "Insert VComp middle - after",
1006 node: html! {
1007 <>
1008 <u key=1></u>
1009 <Comp id=0 key="comp"/>
1010 <a key=2></a>
1011 </>
1012 },
1013 expected: "<u></u><p>0</p><a></a>",
1014 },
1015 ]);
1016
1017 layouts.extend(vec![
1018 TestLayout {
1019 name: "Insert VComp back - before",
1020 node: html! {
1021 <>
1022 <u key=1></u>
1023 <a key=2></a>
1024 </>
1025 },
1026 expected: "<u></u><a></a>",
1027 },
1028 TestLayout {
1029 name: "Insert VComp back - after",
1030 node: html! {
1031 <>
1032 <u key=1></u>
1033 <a key=2></a>
1034 <Comp id=0 key="comp"/>
1035 </>
1036 },
1037 expected: "<u></u><a></a><p>0</p>",
1038 },
1039 ]);
1040
1041 layouts.extend(vec![
1042 TestLayout {
1043 name: "Reverse VComp children - before",
1044 node: html! {
1045 <>
1046 <Comp id=1 key="comp-1"/>
1047 <Comp id=2 key="comp-2"/>
1048 <Comp id=3 key="comp-3"/>
1049 </>
1050 },
1051 expected: "<p>1</p><p>2</p><p>3</p>",
1052 },
1053 TestLayout {
1054 name: "Reverse VComp children - after",
1055 node: html! {
1056 <>
1057 <Comp id=3 key="comp-3"/>
1058 <Comp id=2 key="comp-2"/>
1059 <Comp id=1 key="comp-1"/>
1060 </>
1061 },
1062 expected: "<p>3</p><p>2</p><p>1</p>",
1063 },
1064 ]);
1065
1066 layouts.extend(vec![
1067 TestLayout {
1068 name: "Reverse VComp children with children - before",
1069 node: html! {
1070 <>
1071 <List key="comp-1"><p>{"11"}</p><p>{"12"}</p></List>
1072 <List key="comp-2"><p>{"21"}</p><p>{"22"}</p></List>
1073 <List key="comp-3"><p>{"31"}</p><p>{"32"}</p></List>
1074 </>
1075 },
1076 expected: "<p>11</p><p>12</p><p>21</p><p>22</p><p>31</p><p>32</p>",
1077 },
1078 TestLayout {
1079 name: "Reverse VComp children with children - after",
1080 node: html! {
1081 <>
1082 <List key="comp-3"><p>{"31"}</p><p>{"32"}</p></List>
1083 <List key="comp-2"><p>{"21"}</p><p>{"22"}</p></List>
1084 <List key="comp-1"><p>{"11"}</p><p>{"12"}</p></List>
1085 </>
1086 },
1087 expected: "<p>31</p><p>32</p><p>21</p><p>22</p><p>11</p><p>12</p>",
1088 },
1089 ]);
1090
1091 layouts.extend(vec![
1092 TestLayout {
1093 name: "Complex component update - before",
1094 node: html! {
1095 <List>
1096 <Comp id=1 key="comp-1"/>
1097 <Comp id=2 key="comp-2"/>
1098 </List>
1099 },
1100 expected: "<p>1</p><p>2</p>",
1101 },
1102 TestLayout {
1103 name: "Complex component update - after",
1104 node: html! {
1105 <List>
1106 <List key="comp-1">
1107 <Comp id=1 />
1108 </List>
1109 <List key="comp-2">
1110 <p>{"2"}</p>
1111 </List>
1112 </List>
1113 },
1114 expected: "<p>1</p><p>2</p>",
1115 },
1116 ]);
1117
1118 layouts.extend(vec![
1119 TestLayout {
1120 name: "Reorder VComp children with children - before",
1121 node: html! {
1122 <>
1123 <List key="comp-1"><p>{"1"}</p></List>
1124 <List key="comp-3"><p>{"3"}</p></List>
1125 <List key="comp-5"><p>{"5"}</p></List>
1126 <List key="comp-2"><p>{"2"}</p></List>
1127 <List key="comp-4"><p>{"4"}</p></List>
1128 <List key="comp-6"><p>{"6"}</p></List>
1129 </>
1130 },
1131 expected: "<p>1</p><p>3</p><p>5</p><p>2</p><p>4</p><p>6</p>",
1132 },
1133 TestLayout {
1134 name: "Reorder VComp children with children - after",
1135 node: html! {
1136 <>
1137 <Comp id=6 key="comp-6"/>
1138 <Comp id=5 key="comp-5"/>
1139 <Comp id=4 key="comp-4"/>
1140 <Comp id=3 key="comp-3"/>
1141 <Comp id=2 key="comp-2"/>
1142 <Comp id=1 key="comp-1"/>
1143 </>
1144 },
1145 expected: "<p>6</p><p>5</p><p>4</p><p>3</p><p>2</p><p>1</p>",
1146 },
1147 ]);
1148
1149 layouts.extend(vec![
1150 TestLayout {
1151 name: "Replace and reorder components - before",
1152 node: html! {
1153 <List>
1154 <List key="comp-1"><p>{"1"}</p></List>
1155 <List key="comp-2"><p>{"2"}</p></List>
1156 <List key="comp-3"><p>{"3"}</p></List>
1157 </List>
1158 },
1159 expected: "<p>1</p><p>2</p><p>3</p>",
1160 },
1161 TestLayout {
1162 name: "Replace and reorder components - after",
1163 node: html! {
1164 <List>
1165 <Comp id=3 key="comp-3" />
1166 <Comp id=2 key="comp-2" />
1167 <Comp id=1 key="comp-1" />
1168 </List>
1169 },
1170 expected: "<p>3</p><p>2</p><p>1</p>",
1171 },
1172 ]);
1173
1174 diff_layouts(layouts);
1175 }
1176}