-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy patheval_slot.go
More file actions
136 lines (116 loc) · 4.12 KB
/
Copy patheval_slot.go
File metadata and controls
136 lines (116 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package vuego
import (
"strings"
"golang.org/x/net/html"
"github.com/titpetric/vuego/internal/helpers"
)
// SlotContent holds the processed content for a slot along with any scoped props.
type SlotContent struct {
// Nodes contains the rendered content for this slot.
Nodes []*html.Node
// Props contains any scoped props passed to the slot.
Props map[string]any
// TemplateNode holds the original template node for processing scoped slots.
TemplateNode *html.Node
}
// SlotScope holds all slot contents indexed by name for a component instance.
type SlotScope struct {
// Slots maps slot names to their content.
// Empty string key is the default slot.
Slots map[string]*SlotContent
}
// NewSlotScope creates a new SlotScope for a component.
func NewSlotScope() *SlotScope {
return &SlotScope{
Slots: make(map[string]*SlotContent),
}
}
// GetSlot retrieves slot content by name.
// Returns nil if the slot doesn't exist.
func (ss *SlotScope) GetSlot(name string) *SlotContent {
return ss.Slots[name]
}
// SetSlot sets the content for a named slot.
func (ss *SlotScope) SetSlot(name string, content *SlotContent) {
ss.Slots[name] = content
}
// evalSlot processes a <slot> element and inserts the appropriate content.
// If slot content was provided by the component user, use that.
// Otherwise, render the fallback content (children of the slot element).
func (v *Vue) evalSlot(ctx VueContext, node *html.Node, slotScope *SlotScope) ([]*html.Node, error) {
slotName := helpers.GetAttr(node, "name")
if slotName == "" {
slotName = "default"
}
// Get slot props that the slot binds
slotProps := make(map[string]any)
for _, attr := range node.Attr {
if attr.Key == "" || attr.Key[0] != ':' {
continue
}
// Extract the binding name (without the colon)
propName := attr.Key[1:]
// Evaluate the binding value
val, err := v.exprEval.Eval(attr.Val, ctx.ExprEnv())
if err == nil && val != nil {
slotProps[propName] = val
}
}
// Try to get provided slot content (from explicit include or inherited from layout)
if slotScope != nil {
if slotContent := slotScope.GetSlot(slotName); slotContent != nil {
// Found explicit slot content - evaluate it with the scoped props
result := []*html.Node{}
// If the slot content is a template with v-slot, evaluate it with the props
if slotContent.TemplateNode != nil {
// Extract scoped variable name from the template's v-slot attribute
scopedVarName := ""
for _, attr := range slotContent.TemplateNode.Attr {
if attr.Key == "v-slot" {
scopedVarName = attr.Val
} else if strings.HasPrefix(attr.Key, "v-slot:") || (len(attr.Key) > 0 && attr.Key[0] == '#') {
// For named slots, extract the scoped var from the attribute value
scopedVarName = attr.Val
}
}
// Push the scoped props onto the stack
ctx.stack.Push(nil)
defer ctx.stack.Pop()
// If there's a scoped variable name, use it; otherwise use the props directly
if scopedVarName != "" {
ctx.stack.Set(scopedVarName, slotProps)
} else {
// Set the slot props directly in the context
for k, v := range slotProps {
ctx.stack.Set(k, v)
}
}
// Evaluate the template content (children of the template)
children, err := v.evaluateChildren(ctx, slotContent.TemplateNode, 0)
if err != nil {
return nil, err
}
result = append(result, children...)
} else {
// Use the provided content as-is
result = append(result, slotContent.Nodes...)
}
return result, nil
}
}
// Check for inherited slots from layout (passed via __slotScope__ in context data)
if inheritedSlotScopeData, ok := ctx.stack.EnvMap()["__slotScope__"]; ok {
if inheritedSlotScope, ok := inheritedSlotScopeData.(*SlotScope); ok {
if slotContent := inheritedSlotScope.GetSlot(slotName); slotContent != nil {
// Use the inherited slot content directly (already parsed as DOM nodes)
return slotContent.Nodes, nil
}
}
}
// No explicit slot content - use fallback (children of the slot element)
if node.FirstChild != nil {
// Evaluate the fallback content
return v.evaluateChildren(ctx, node, 0)
}
return []*html.Node{}, nil
}