@@ -432,7 +432,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
432
432
p .printAttributesToObject (n )
433
433
} else if isSlot {
434
434
if len (n .Attr ) == 0 {
435
- p .print (`"default"` )
435
+ p .print (DEFAULT_SLOT_PROP )
436
436
} else {
437
437
slotted := false
438
438
for _ , a := range n .Attr {
@@ -454,7 +454,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
454
454
}
455
455
}
456
456
if ! slotted {
457
- p .print (`"default"` )
457
+ p .print (DEFAULT_SLOT_PROP )
458
458
}
459
459
}
460
460
p .print (`]` )
@@ -559,7 +559,7 @@ func render1(p *printer, n *Node, opts RenderOptions) {
559
559
switch true {
560
560
case n .CustomElement :
561
561
p .print (`,({` )
562
- p .print (fmt .Sprintf (`"%s" : () => ` , "default" ))
562
+ p .print (fmt .Sprintf (`%s : () => ` , DEFAULT_SLOT_PROP ))
563
563
p .printTemplateLiteralOpen ()
564
564
for c := n .FirstChild ; c != nil ; c = c .NextSibling {
565
565
render1 (p , c , RenderOptions {
@@ -638,6 +638,8 @@ func render1(p *printer, n *Node, opts RenderOptions) {
638
638
}
639
639
}
640
640
641
+ const DEFAULT_SLOT_PROP = `"default"`
642
+
641
643
// Section 12.1.2, "Elements", gives this list of void elements. Void elements
642
644
// are those that can't have any contents.
643
645
// nolint
@@ -662,12 +664,14 @@ var voidElements = map[string]bool{
662
664
func handleSlots (p * printer , n * Node , opts RenderOptions , depth int ) {
663
665
p .print (`,` )
664
666
slottedChildren := make (map [string ][]* Node )
665
- hasAnyDynamicSlots := false
667
+ hasAnyNestedDynamicSlot := false
666
668
nestedSlotChildren := make ([]* NestedSlotChild , 0 )
667
- numberOfNestedSlots := 0
669
+
670
+ // the highest number of nested slots in an expression
671
+ maxNestedSlotsCount := 0
668
672
669
673
for c := n .FirstChild ; c != nil ; c = c .NextSibling {
670
- slotProp := `"default"`
674
+ slotProp := DEFAULT_SLOT_PROP
671
675
for _ , a := range c .Attr {
672
676
if a .Key == "slot" {
673
677
if a .Type == QuotedAttribute {
@@ -686,82 +690,79 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) {
686
690
}
687
691
}
688
692
if c .Expression {
689
- nestedSlotsCount := 0
690
- var firstNestedSlotProp string
693
+ // Only slot ElementNodes (except expressions containing only comments) or non-empty TextNodes!
694
+ // CommentNode, JSX comments and others should not be slotted
695
+ if expressionOnlyHasComment (c ) {
696
+ continue
697
+ }
698
+ nestedSlotsInExprCount := 0
699
+ hasAnyDynamicSlotsInExpr := false
700
+ var slotProp = DEFAULT_SLOT_PROP
691
701
for c1 := c .FirstChild ; c1 != nil ; c1 = c1 .NextSibling {
692
- var slotProp = ""
693
702
for _ , a := range c1 .Attr {
694
703
if a .Key == "slot" {
695
704
if a .Type == QuotedAttribute {
696
705
slotProp = fmt .Sprintf (`"%s"` , escapeDoubleQuote (a .Val ))
697
706
} else if a .Type == ExpressionAttribute {
698
707
slotProp = fmt .Sprintf (`[%s]` , a .Val )
699
- hasAnyDynamicSlots = true
708
+ hasAnyNestedDynamicSlot , hasAnyDynamicSlotsInExpr = true , true
700
709
} else if a .Type == TemplateLiteralAttribute {
701
710
slotProp = fmt .Sprintf (`[%s%s%s]` , BACKTICK , a .Val , BACKTICK )
702
- hasAnyDynamicSlots = true
711
+ hasAnyNestedDynamicSlot , hasAnyDynamicSlotsInExpr = true , true
703
712
} else {
704
713
panic (`unknown slot attribute type` )
705
714
}
706
715
}
707
- if firstNestedSlotProp == "" && slotProp != "" {
708
- firstNestedSlotProp = slotProp
709
- }
710
716
}
711
- if firstNestedSlotProp != "" {
712
- nestedSlotsCount ++
717
+ if c1 . Type == ElementNode {
718
+ nestedSlotsInExprCount ++
713
719
}
714
720
}
715
721
716
- if nestedSlotsCount == 1 && ! hasAnyDynamicSlots {
717
- slottedChildren [firstNestedSlotProp ] = append (slottedChildren [firstNestedSlotProp ], c )
722
+ if nestedSlotsInExprCount == 1 && ! hasAnyDynamicSlotsInExpr {
723
+ slottedChildren [slotProp ] = append (slottedChildren [slotProp ], c )
718
724
continue
719
- } else if nestedSlotsCount > 1 || hasAnyDynamicSlots {
725
+ } else if nestedSlotsInExprCount > 1 || hasAnyDynamicSlotsInExpr {
726
+ if nestedSlotsInExprCount > maxNestedSlotsCount {
727
+ maxNestedSlotsCount = nestedSlotsInExprCount
728
+ }
720
729
child_loop:
721
730
for c1 := c .FirstChild ; c1 != nil ; c1 = c1 .NextSibling {
722
731
foundNamedSlot := false
732
+ isFirstInGroup := c1 == c .FirstChild
723
733
for _ , a := range c1 .Attr {
724
734
if a .Key == "slot" {
725
735
var nestedSlotProp string
726
736
var nestedSlotEntry * NestedSlotChild
727
737
if a .Type == QuotedAttribute {
728
738
nestedSlotProp = fmt .Sprintf (`"%s"` , escapeDoubleQuote (a .Val ))
729
- hasAnyDynamicSlots = true
730
739
} else if a .Type == ExpressionAttribute {
731
740
nestedSlotProp = fmt .Sprintf (`[%s]` , a .Val )
732
- hasAnyDynamicSlots = true
741
+ hasAnyNestedDynamicSlot = true
733
742
} else if a .Type == TemplateLiteralAttribute {
734
- hasAnyDynamicSlots = true
743
+ hasAnyNestedDynamicSlot = true
735
744
nestedSlotProp = fmt .Sprintf (`[%s%s%s]` , BACKTICK , a .Val , BACKTICK )
736
745
} else {
737
746
panic (`unknown slot attribute type` )
738
747
}
739
748
foundNamedSlot = true
740
- isFirstInGroup := c1 == c .FirstChild
741
749
nestedSlotEntry = & NestedSlotChild {nestedSlotProp , []* Node {c1 }, isFirstInGroup }
742
750
nestedSlotChildren = append (nestedSlotChildren , nestedSlotEntry )
743
751
continue child_loop
744
752
}
745
753
}
746
- isFirstInGroup := c1 == c .FirstChild
747
754
if ! foundNamedSlot && c1 .Type == ElementNode {
748
- pseudoSlotEntry := & NestedSlotChild {`"default"` , []* Node {c1 }, isFirstInGroup }
755
+ pseudoSlotEntry := & NestedSlotChild {DEFAULT_SLOT_PROP , []* Node {c1 }, isFirstInGroup }
749
756
nestedSlotChildren = append (nestedSlotChildren , pseudoSlotEntry )
750
757
} else {
751
758
nestedSlotEntry := & NestedSlotChild {`"@@NON_ELEMENT_ENTRY"` , []* Node {c1 }, isFirstInGroup }
752
759
nestedSlotChildren = append (nestedSlotChildren , nestedSlotEntry )
753
760
}
754
- numberOfNestedSlots ++
755
761
}
756
762
continue
757
763
}
758
764
}
759
765
760
- // Only slot ElementNodes (except expressions containing only comments) or non-empty TextNodes!
761
- // CommentNode, JSX comments and others should not be slotted
762
- if expressionOnlyHasComment (c ) {
763
- continue
764
- }
765
766
if c .Type == ElementNode || c .Type == TextNode && ! emptyTextNodeWithoutSiblings (c ) {
766
767
slottedChildren [slotProp ] = append (slottedChildren [slotProp ], c )
767
768
}
@@ -772,7 +773,12 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) {
772
773
slottedKeys = append (slottedKeys , k )
773
774
}
774
775
sort .Strings (slottedKeys )
775
- if numberOfNestedSlots > 0 || hasAnyDynamicSlots {
776
+
777
+ // if any slotted expression contains more than one nested slot (e.g. <Component>{true ? <div slot="bar">Bar</div> : <div slot="foo">Foo</div> }</Component>)
778
+ // OR if any expression contains a dynamic slot (e.g. <Component>{items.map((item)=> (<div slot={item.id}>{item.name}</div>)}</Component>)
779
+ // we need to use $$mergeSlots
780
+ shouldPrintMergeSlots := maxNestedSlotsCount > 1 || hasAnyNestedDynamicSlot
781
+ if shouldPrintMergeSlots {
776
782
p .print (`$$mergeSlots(` )
777
783
}
778
784
p .print (`({` )
@@ -783,7 +789,7 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) {
783
789
children := slottedChildren [slotProp ]
784
790
785
791
// If there are named slots, the default slot cannot be only whitespace
786
- if numberOfSlots > 1 && slotProp == " \" default \" " {
792
+ if numberOfSlots > 1 && slotProp == DEFAULT_SLOT_PROP {
787
793
// Loop over the children and verify that at least one non-whitespace node exists.
788
794
foundNonWhitespace := false
789
795
for _ , child := range children {
@@ -820,10 +826,9 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) {
820
826
}
821
827
p .print (`})` )
822
828
// print nested slots
823
- if numberOfNestedSlots > 0 || hasAnyDynamicSlots {
829
+ if len ( nestedSlotChildren ) > 0 {
824
830
endSlotIndexes := generateEndSlotIndexes (nestedSlotChildren )
825
- mergeDefaultSlotsAndUpdateIndexes (& nestedSlotChildren , endSlotIndexes )
826
-
831
+ mergeDefaultSlotsAndUpdateIndexes (& nestedSlotChildren , & endSlotIndexes )
827
832
hasFoundFirstElementNode := false
828
833
for j , nestedSlot := range nestedSlotChildren {
829
834
if nestedSlot .FirstInGroup {
@@ -843,6 +848,9 @@ func handleSlots(p *printer, n *Node, opts RenderOptions, depth int) {
843
848
hasFoundFirstElementNode = false
844
849
}
845
850
}
851
+ }
852
+ if shouldPrintMergeSlots {
853
+ // close $$mergeSlots call
846
854
p .print (`)` )
847
855
}
848
856
}
@@ -907,25 +915,42 @@ func generateEndSlotIndexes(nestedSlotChildren []*NestedSlotChild) map[int]bool
907
915
return endSlotIndexes
908
916
}
909
917
910
- func mergeDefaultSlotsAndUpdateIndexes (nestedSlotChildren * []* NestedSlotChild , endSlotIndexes map [int ]bool ) {
911
- defaultSlot := & NestedSlotChild {SlotProp : `"default"` , Children : []* Node {}}
912
- mergedSlotChildren := make ([]* NestedSlotChild , 0 )
913
- numberOfMergedSlotsInSlotChain := 0
918
+ func mergeDefaultSlotsAndUpdateIndexes (nestedSlotChildren * []* NestedSlotChild , endSlotIndexes * map [int ]bool ) {
919
+ bufferedDefaultSlot := & NestedSlotChild {SlotProp : DEFAULT_SLOT_PROP , Children : []* Node {}}
920
+ updatedNestedSlotChildren := make ([]* NestedSlotChild , 0 )
921
+ updatedEndSlotIndexes := make ( map [ int ] bool )
914
922
915
923
for i , nestedSlot := range * nestedSlotChildren {
916
924
if isDefaultSlot (nestedSlot ) {
917
- defaultSlot .Children = append (defaultSlot .Children , nestedSlot .Children ... )
918
- numberOfMergedSlotsInSlotChain ++
925
+ bufferedDefaultSlot .Children = append (bufferedDefaultSlot .Children , nestedSlot .Children ... )
919
926
} else {
920
- mergedSlotChildren = append (mergedSlotChildren , nestedSlot )
927
+ updatedNestedSlotChildren = append (updatedNestedSlotChildren , nestedSlot )
921
928
}
922
- if shouldMergeDefaultSlot (endSlotIndexes , i , defaultSlot ) {
923
- resetEndSlotIndexes (endSlotIndexes , i , & numberOfMergedSlotsInSlotChain )
924
- mergedSlotChildren = append (mergedSlotChildren , defaultSlot )
925
- defaultSlot = & NestedSlotChild {SlotProp : `"default"` , Children : []* Node {}}
929
+
930
+ // we reached the end of a slot chain
931
+ if (* endSlotIndexes )[i ] {
932
+ // free up memory, this information is now outdated
933
+ // the updated information is stored in updatedEndSlotIndexes
934
+ delete (* endSlotIndexes , i )
935
+
936
+ if len (bufferedDefaultSlot .Children ) > 0 {
937
+ // if the buffered default slot contains any children
938
+ // add it to the updated nested slot children
939
+ updatedNestedSlotChildren = append (updatedNestedSlotChildren , bufferedDefaultSlot )
940
+
941
+ // reset the buffered default slot
942
+ bufferedDefaultSlot = & NestedSlotChild {SlotProp : DEFAULT_SLOT_PROP , Children : []* Node {}}
943
+ }
944
+ // record the index of the last slot in the chain
945
+ updatedEndSlotIndexes [len (updatedNestedSlotChildren )- 1 ] = true
926
946
}
947
+
948
+ // free up memory, the actual information of nested slot
949
+ // is now stored in updatedNestedSlotChildren
950
+ (* nestedSlotChildren )[i ] = nil
927
951
}
928
- * nestedSlotChildren = mergedSlotChildren
952
+ * nestedSlotChildren = updatedNestedSlotChildren
953
+ * endSlotIndexes = updatedEndSlotIndexes
929
954
}
930
955
931
956
func getSlotRenderFunction (isNewSlotObject bool ) string {
@@ -943,15 +968,5 @@ func isNonWhitespaceTextNode(n *Node) bool {
943
968
}
944
969
945
970
func isDefaultSlot (slot * NestedSlotChild ) bool {
946
- return slot .SlotProp == `"default"`
947
- }
948
-
949
- func shouldMergeDefaultSlot (endSlotIndexes map [int ]bool , i int , defaultSlot * NestedSlotChild ) bool {
950
- return endSlotIndexes [i ] && len (defaultSlot .Children ) > 0
951
- }
952
-
953
- func resetEndSlotIndexes (endSlotIndexes map [int ]bool , i int , numberOfMergedSlotsInSlotChain * int ) {
954
- endSlotIndexes [i ] = false
955
- endSlotIndexes [i - (* numberOfMergedSlotsInSlotChain )+ 1 ] = true
956
- (* numberOfMergedSlotsInSlotChain ) = 0
971
+ return slot .SlotProp == DEFAULT_SLOT_PROP
957
972
}
0 commit comments