Repository: maragudk/gomponents
Pull request #236 (2024-10-26 03:46:59)

Add popover attributes
This PR adds popover attributes as detailed here: https://developer.mozilla.org/en-US/docs/Web/API/Popover_API/Using


markuswustenberg: Hi @knpwrs, thanks for this.

This is the second attribute in a short time that allows zero or one argument(s) (`popover` is the same as `popover="auto"`). I'm wondering whether we should start adding a third form of attribute in the `html` package, with varargs values, similar to how `gomponents.Attr` itself works. And then panic if there's more than one value. Thoughts?
markuswustenberg: @knpwrs I think in-place is fine. But it needs to go into a new test which:
1. Tests that it works like a boolean attribute
2. Tests that it works as a key-value attribute
3. Tests that it panics with more than one value given

Might as well start a new table-driven test, I think more attributes like these will show up.

Are you up for that? Otherwise let me know. 😊
knpwrs: How does that look?
markuswustenberg: Looks great! Should we add the `popovertargetaction` now we're at it? :D
knpwrs: Done!


Patch:
diff --git a/html/attributes.go b/html/attributes.go
index be8393e..e4cd796 100644
--- a/html/attributes.go
+++ b/html/attributes.go
@@ -213,6 +213,18 @@ func Placeholder(v string) g.Node {
 	return g.Attr("placeholder", v)
 }
 
+func Popover(value ...string) g.Node {
+	return g.Attr("popover", value...)
+}
+
+func PopoverTarget(v string) g.Node {
+	return g.Attr("popovertarget", v)
+}
+
+func PopoverTargetAction(v string) g.Node {
+	return g.Attr("popovertargetaction", v)
+}
+
 func Poster(v string) g.Node {
 	return g.Attr("poster", v)
 }


Test patch:
diff --git a/html/attributes_test.go b/html/attributes_test.go
index 67b98f4..cfb64b5 100644
--- a/html/attributes_test.go
+++ b/html/attributes_test.go
@@ -78,6 +78,8 @@ func TestSimpleAttributes(t *testing.T) {
 		{Name: "name", Func: Name},
 		{Name: "pattern", Func: Pattern},
 		{Name: "placeholder", Func: Placeholder},
+		{Name: "popovertarget", Func: PopoverTarget},
+		{Name: "popovertargetaction", Func: PopoverTargetAction},
 		{Name: "poster", Func: Poster},
 		{Name: "preload", Func: Preload},
 		{Name: "rel", Func: Rel},
@@ -107,6 +109,37 @@ func TestSimpleAttributes(t *testing.T) {
 	}
 }
 
+func TestVariadicAttributes(t *testing.T) {
+	tests := []struct {
+		Name string
+		Func func(...string) g.Node
+	}{
+		{Name: "popover", Func: Popover},
+	}
+
+	for _, test := range tests {
+		t.Run(test.Name + "(no args)", func(t *testing.T) {
+			n := g.El("div", test.Func())
+			assert.Equal(t, fmt.Sprintf(`<div %v></div>`, test.Name), n)
+		})
+
+		t.Run(test.Name +"(one arg)", func(t *testing.T) {
+			n := g.El("div", test.Func("hat"))
+			assert.Equal(t, fmt.Sprintf(`<div %v="hat"></div>`, test.Name), n)
+		})
+
+		t.Run(test.Name + "(two args panics)", func(t *testing.T) {
+			defer func() {
+				if r := recover(); r == nil {
+					t.Errorf("expected a panic")
+				}
+			}()
+			n := g.El("div", test.Func("hat", "party"))
+			assert.Equal(t, "unreachable", n)
+		})
+	}
+}
+
 func TestAria(t *testing.T) {
 	t.Run("returns an attribute which name is prefixed with aria-", func(t *testing.T) {
 		n := Aria("selected", "true")