From a76262652b227c95ce140f3698c46f59b79354ac Mon Sep 17 00:00:00 2001 From: Markus Wüstenberg Date: Thu, 10 Dec 2020 13:00:23 +0100 Subject: Move elements and attributes into html package (#52) This makes it easier to use dot-imports. Also updated the readme and examples with new usage, and move the `Classes` helper into the `components` package.--- components/attributes.go | 37 +++++++++++++++++++++++++++++++++++++ components/attributes_test.go | 32 ++++++++++++++++++++++++++++++++ components/documents.go | 29 ++++++++++++++--------------- components/documents_test.go | 13 ++++++------- 4 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 components/attributes.go create mode 100644 components/attributes_test.go (limited to 'components') diff --git a/components/attributes.go b/components/attributes.go new file mode 100644 index 0000000..dc7ef9b --- /dev/null +++ b/components/attributes.go @@ -0,0 +1,37 @@ +package components + +import ( + "io" + "sort" + "strings" + + g "github.com/maragudk/gomponents" + "github.com/maragudk/gomponents/html" +) + +// Classes is a map of strings to booleans, which Renders to an attribute with name "class". +// The attribute value is a sorted, space-separated string of all the map keys, +// for which the corresponding map value is true. +type Classes map[string]bool + +func (c Classes) Render(w io.Writer) error { + var included []string + for c, include := range c { + if include { + included = append(included, c) + } + } + sort.Strings(included) + return html.Class(strings.Join(included, " ")).Render(w) +} + +func (c Classes) Type() g.NodeType { + return g.AttributeType +} + +// String satisfies fmt.Stringer. +func (c Classes) String() string { + var b strings.Builder + _ = c.Render(&b) + return b.String() +} diff --git a/components/attributes_test.go b/components/attributes_test.go new file mode 100644 index 0000000..bf3e93b --- /dev/null +++ b/components/attributes_test.go @@ -0,0 +1,32 @@ +package components_test + +import ( + "testing" + + g "github.com/maragudk/gomponents" + "github.com/maragudk/gomponents/assert" + c "github.com/maragudk/gomponents/components" +) + +func TestClasses(t *testing.T) { + t.Run("given a map, returns sorted keys from the map with value true", func(t *testing.T) { + assert.Equal(t, ` class="boheme-hat hat partyhat"`, c.Classes{ + "boheme-hat": true, + "hat": true, + "partyhat": true, + "turtlehat": false, + }) + }) + + t.Run("renders as attribute in an element", func(t *testing.T) { + e := g.El("div", c.Classes{"hat": true}) + assert.Equal(t, `
`, e) + }) + + t.Run("also works with fmt", func(t *testing.T) { + a := c.Classes{"hat": true} + if a.String() != ` class="hat"` { + t.FailNow() + } + }) +} diff --git a/components/documents.go b/components/documents.go index 5e96466..e2d3a22 100644 --- a/components/documents.go +++ b/components/documents.go @@ -1,15 +1,14 @@ -// Package components provides high-level components that are composed of low-level elements and attributes. +// Package components provides high-level components and helpers that are composed of low-level elements and attributes. package components import ( g "github.com/maragudk/gomponents" - "github.com/maragudk/gomponents/attr" - "github.com/maragudk/gomponents/el" + . "github.com/maragudk/gomponents/html" ) -// DocumentProps for HTML5. +// HTML5Props for HTML5. // Title is set no matter what, Description and Language elements only if the strings are non-empty. -type DocumentProps struct { +type HTML5Props struct { Title string Description string Language string @@ -18,24 +17,24 @@ type DocumentProps struct { } // HTML5 document template. -func HTML5(p DocumentProps) g.NodeFunc { +func HTML5(p HTML5Props) g.NodeFunc { var lang, description g.Node if p.Language != "" { - lang = attr.Lang(p.Language) + lang = Lang(p.Language) } if p.Description != "" { - description = el.Meta(attr.Name("description"), attr.Content(p.Description)) + description = Meta(Name("description"), Content(p.Description)) } - return el.Document( - el.HTML(lang, - el.Head( - el.Meta(attr.Charset("utf-8")), - el.Meta(attr.Name("viewport"), attr.Content("width=device-width, initial-scale=1")), - el.Title(p.Title), + return Document( + HTML(lang, + Head( + Meta(Charset("utf-8")), + Meta(Name("viewport"), Content("width=device-width, initial-scale=1")), + TitleEl(p.Title), description, g.Group(p.Head), ), - el.Body(g.Group(p.Body)), + Body(g.Group(p.Body)), ), ) } diff --git a/components/documents_test.go b/components/documents_test.go index 863ac96..07f8697 100644 --- a/components/documents_test.go +++ b/components/documents_test.go @@ -5,26 +5,25 @@ import ( g "github.com/maragudk/gomponents" "github.com/maragudk/gomponents/assert" - "github.com/maragudk/gomponents/attr" - c "github.com/maragudk/gomponents/components" - "github.com/maragudk/gomponents/el" + . "github.com/maragudk/gomponents/components" + . "github.com/maragudk/gomponents/html" ) func TestHTML5(t *testing.T) { t.Run("returns an html5 document template", func(t *testing.T) { - e := c.HTML5(c.DocumentProps{ + e := HTML5(HTML5Props{ Title: "Hat", Description: "Love hats.", Language: "en", - Head: []g.Node{el.Link(attr.Rel("stylesheet"), attr.Href("/hat.css"))}, - Body: []g.Node{el.Div()}, + Head: []g.Node{Link(Rel("stylesheet"), Href("/hat.css"))}, + Body: []g.Node{Div()}, }) assert.Equal(t, `