diff --git a/responsive.go b/responsive.go index 046d092..fc40939 100644 --- a/responsive.go +++ b/responsive.go @@ -1,6 +1,8 @@ package html import ( + "maps" + "slices" "strconv" "strings" ) @@ -10,6 +12,7 @@ import ( // Each variant is rendered inside a container with data-variant for CSS targeting. type Responsive struct { variants []responsiveVariant + attrs map[string]string } type responsiveVariant struct { @@ -20,7 +23,19 @@ type responsiveVariant struct { // responsive.go: NewResponsive creates a new multi-variant responsive compositor. // Example: r := NewResponsive(). func NewResponsive() *Responsive { - return &Responsive{} + return &Responsive{ + attrs: make(map[string]string), + } +} + +func (r *Responsive) setAttr(key, value string) { + if r == nil { + return + } + if r.attrs == nil { + r.attrs = make(map[string]string) + } + r.attrs[key] = value } // escapeCSSString escapes a string for safe use inside a double-quoted CSS @@ -85,7 +100,19 @@ func (r *Responsive) Render(ctx *Context) string { var b strings.Builder for _, v := range r.variants { - b.WriteString(`
`) b.WriteString(Render(v.layout, ctx)) diff --git a/responsive_test.go b/responsive_test.go index 351ed3b..ee0a3e6 100644 --- a/responsive_test.go +++ b/responsive_test.go @@ -115,6 +115,28 @@ func TestResponsive_NilLayoutVariant(t *testing.T) { } } +func TestResponsive_Attributes(t *testing.T) { + ctx := NewContext() + r := Attr(NewResponsive(). + Variant("desktop", NewLayout("C").C(Raw("main"))). + Variant("mobile", NewLayout("C").C(Raw("main"))), + "aria-label", "Responsive content", + ) + r = Attr(r, "class", "responsive-shell") + + got := r.Render(ctx) + + if count := strings.Count(got, `aria-label="Responsive content"`); count != 2 { + t.Fatalf("responsive attrs should apply to each wrapper, got %d in:\n%s", count, got) + } + if count := strings.Count(got, `class="responsive-shell"`); count != 2 { + t.Fatalf("responsive class should apply to each wrapper, got %d in:\n%s", count, got) + } + if !strings.Contains(got, `aria-label="Responsive content" class="responsive-shell" data-variant="desktop"`) { + t.Fatalf("responsive wrapper attrs should be sorted and preserved, got:\n%s", got) + } +} + func TestVariantSelector(t *testing.T) { tests := []struct { name string