]> git.earlybird.gay Git - today/commitdiff
fix template behavior with slotted components
authorearly <me@earlybird.gay>
Wed, 11 Sep 2024 04:50:33 +0000 (22:50 -0600)
committerearly <me@earlybird.gay>
Wed, 11 Sep 2024 04:50:33 +0000 (22:50 -0600)
internal/compile/template.go

index 808c3fd55e580c17d707d52701802dba4762f82e..a1e0e2b26067c1112e04810f829f71dd9d83926c 100644 (file)
@@ -270,11 +270,11 @@ func replaceTemplateFields(n *html.Node) []string {
                        if token == tokenCloseTemplate {
                                inTemplate = false
                        }
-                       // If we're in a template and found a function identifier, replace it
+                       // If we're in a template and found a template value identifier, replace it
                        // with a namespaced version
                        if inTemplate && isField(token) ||
                                inAttrs && isDataAttr[i] {
-                               raised = append(raised, strings.Split(token, ".")[1])
+                               raised = append(raised, token[1:])
                                token = ".parent" + token
                        }
 
@@ -314,8 +314,18 @@ func insertTemplateSource(subSource TemplateSource, context *html.Node) (*comput
        // ===== CONTEXT PREPROCESSING =====
        // Raise any fields pre-existing in the context to .parent.field.
        raiseFields := make([]string, 0)
+       raiseDepth := 0
        htmltree.Walk(context.FirstChild, func(n *html.Node) (bool, error) {
-               raiseFields = append(raiseFields, replaceTemplateFields(n)...)
+               if raiseDepth == 0 {
+                       raiseFields = append(raiseFields, replaceTemplateFields(n)...)
+               }
+               if n.Type == html.TextNode {
+                       if scopesUp(n.Data) {
+                               raiseDepth++
+                       } else if scopesDown(n.Data) {
+                               raiseDepth--
+                       }
+               }
                return false, nil
        })
        // Remove :data attributes from the root of context, and prepare them
@@ -365,26 +375,67 @@ func insertTemplateSource(subSource TemplateSource, context *html.Node) (*comput
 
        // Mix stuff from the context into the template using slots...
        n := context.FirstChild
+       // slot context is the nodes currently considered candidates for slotting.
+       // Being in the slotCtx doesn't mean a node *will* be slotted, just that it
+       // might be, and if it is it needs to have its order preserved with every
+       // other node in the ctx.
+       slotCtx := make([]*html.Node, 0)
+       // nonslotCtx is a copy of slotCtx, but elements with no slot go here instead.
+       nonslotCtx := make([]*html.Node, 0)
+       var slotUsed, nonslotUsed bool
+       var targetSlot *html.Node
+       // slotCtxDepth is the depth of any template scope biz that surrounds a
+       // slotted node.
+       slotCtxDepth := 0
        for n != nil {
                next := n.NextSibling
                context.RemoveChild(n)
-               // Do not slot any non-slottable nodes, or comments, because I do not
-               // like them
-               if n.Type == html.CommentNode {
-                       n = next
-                       continue
-               }
-               slotName := htmltree.GetAttr(n, "slot")
-               slot := slots[slotName]
-               if slot != nil {
-                       if !isShadow {
-                               slot.Parent.InsertBefore(n, slot)
+               switch n.Type {
+               case html.TextNode:
+                       // Raise/lower the slot context depth if scope goes up or down.
+                       if scopesUp(n.Data) {
+                               slotCtxDepth++
+                       } else if scopesDown(n.Data) {
+                               slotCtxDepth--
+                       }
+                       // Add the node to slotCtx, and a copy to nonslotCtx
+                       slotCtx = append(slotCtx, n)
+                       nonslotCtx = append(nonslotCtx, &html.Node{
+                               Type: n.Type,
+                               Data: n.Data,
+                       })
+               case html.ElementNode:
+                       slotName := htmltree.GetAttr(n, "slot")
+                       slot, ok := slots[slotName]
+                       if slotName != "" && ok {
+                               // Add this element to the current slottable context.
+                               slotCtx = append(slotCtx, n)
+                               slotUsed = true
+                               targetSlot = slot
+                               // Mark the slot as used in usedSlot so its default content
+                               // is removed.
+                               usedSlot[slotName] = true
                        } else {
-                               context.AppendChild(n)
+                               // Add it to the nonslottable context.
+                               nonslotCtx = append(nonslotCtx, n)
+                               nonslotUsed = true
+                       }
+               }
+               if slotCtxDepth == 0 {
+                       if slotUsed {
+                               for _, slotCtxNode := range slotCtx {
+                                       targetSlot.Parent.InsertBefore(slotCtxNode, targetSlot)
+                               }
+                               slotCtx = make([]*html.Node, 0)
+                               slotUsed = false
+                       }
+                       if nonslotUsed {
+                               for _, nonslotCtxNode := range nonslotCtx {
+                                       root.AppendChild(nonslotCtxNode)
+                               }
+                               nonslotCtx = make([]*html.Node, 0)
+                               nonslotUsed = false
                        }
-                       usedSlot[slotName] = true
-               } else {
-                       root.AppendChild(n)
                }
                n = next
        }