diff options
Diffstat (limited to 'gomponents.go')
-rw-r--r-- | gomponents.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/gomponents.go b/gomponents.go new file mode 100644 index 0000000..bd7e09c --- /dev/null +++ b/gomponents.go @@ -0,0 +1,100 @@ +package gomponents + +import ( + "fmt" + "html/template" + "strings" +) + +// Node is a DOM node that can Render itself to a string representation. +type Node interface { + Render() string +} + +// NodeFunc is render function that is also a Node. +type NodeFunc func() string + +func (n NodeFunc) Render() string { + return n() +} + +// El creates an element DOM Node with a name and child Nodes. +// Use this if no convenience creator exists. +func El(name string, children ...Node) NodeFunc { + return func() string { + var b, attrString, childrenString strings.Builder + + b.WriteString("<") + b.WriteString(name) + + if len(children) == 0 { + b.WriteString("/>") + return b.String() + } + + for _, c := range children { + s := c.Render() + if _, ok := c.(attr); ok { + attrString.WriteString(s) + continue + } + childrenString.WriteString(c.Render()) + } + + b.WriteString(attrString.String()) + + if childrenString.Len() == 0 { + b.WriteString("/>") + return b.String() + } + + b.WriteString(">") + b.WriteString(childrenString.String()) + b.WriteString("</") + b.WriteString(name) + b.WriteString(">") + return b.String() + } +} + +// Attr creates an attr DOM Node. +// If one parameter is passed, it's a name-only attribute (like "required"). +// If two parameters are passed, it's a name-value attribute (like `class="header"`). +// More parameter counts make Attr panic. +// Use this if no convenience creator exists. +func Attr(name string, value ...string) Node { + switch len(value) { + case 0: + return attr{name: name} + case 1: + return attr{name: name, value: &value[0]} + default: + panic("attribute must be just name or name and value pair") + } +} + +type attr struct { + name string + value *string +} + +func (a attr) Render() string { + if a.value == nil { + return fmt.Sprintf(" %v", a.name) + } + return fmt.Sprintf(` %v="%v"`, a.name, *a.value) +} + +// Text creates a text DOM Node that Renders the escaped string t. +func Text(t string) NodeFunc { + return func() string { + return template.HTMLEscaper(t) + } +} + +// Raw creates a raw Node that just Renders the unescaped string t. +func Raw(t string) NodeFunc { + return func() string { + return t + } +} |