diff --git a/framework-ui/ui/button.go b/framework-ui/ui/button.go index 76efd60..1cad240 100644 --- a/framework-ui/ui/button.go +++ b/framework-ui/ui/button.go @@ -47,10 +47,10 @@ func Button(props ButtonProps) h.Ren { button := h.Button( h.If(props.Id != "", h.Id(props.Id)), h.If(props.Children != nil, h.Children(props.Children...)), - h.If(props.Trigger != "", h.Trigger(props.Trigger)), + h.If(props.Trigger != "", h.HxTrigger(props.Trigger)), h.Class("flex gap-1 items-center border p-4 rounded cursor-hover", props.Class), h.If(props.Get != "", h.Get(props.Get)), - h.If(props.Target != "", h.Target(props.Target)), + h.If(props.Target != "", h.HxTarget(props.Target)), h.IfElse(props.Type != "", h.Type(props.Type), h.Type("button")), lifecycle, text, diff --git a/framework/h/app.go b/framework/h/app.go index 4131a29..effd666 100644 --- a/framework/h/app.go +++ b/framework/h/app.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/labstack/echo/v4" "github.com/maddalax/htmgo/framework/htmgo/service" + "github.com/maddalax/htmgo/framework/hx" "github.com/maddalax/htmgo/framework/util/process" "log/slog" "time" @@ -11,7 +12,14 @@ import ( type RequestContext struct { echo.Context - locator *service.Locator + locator *service.Locator + isBoosted bool + currentBrowserUrl string + hxPromptResponse string + isHxRequest bool + hxTargetId string + hxTriggerName string + hxTriggerId string } func (c *RequestContext) ServiceLocator() *service.Locator { @@ -47,6 +55,16 @@ func Start(opts AppOpts) { instance.start() } +func populateHxFields(cc *RequestContext) { + cc.isBoosted = cc.Request().Header.Get(hx.BoostedHeader) == "true" + cc.currentBrowserUrl = cc.Request().Header.Get(hx.CurrentUrlHeader) + cc.hxPromptResponse = cc.Request().Header.Get(hx.PromptResponseHeader) + cc.isHxRequest = cc.Request().Header.Get(hx.RequestHeader) == "true" + cc.hxTargetId = cc.Request().Header.Get(hx.TargetIdHeader) + cc.hxTriggerName = cc.Request().Header.Get(hx.TriggerNameHeader) + cc.hxTriggerId = cc.Request().Header.Get(hx.TriggerIdHeader) +} + func (a App) start() { if a.Opts.Register != nil { @@ -56,9 +74,10 @@ func (a App) start() { a.Echo.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { cc := &RequestContext{ - c, - a.Opts.ServiceLocator, + Context: c, + locator: a.Opts.ServiceLocator, } + populateHxFields(cc) return next(cc) } }) diff --git a/framework/h/attribute.go b/framework/h/attribute.go index 358ce98..9ea9341 100644 --- a/framework/h/attribute.go +++ b/framework/h/attribute.go @@ -1,6 +1,10 @@ package h -import "fmt" +import ( + "fmt" + "github.com/maddalax/htmgo/framework/hx" + "strings" +) type AttributeMap map[string]any @@ -21,3 +25,143 @@ func (m *AttributeMap) ToMap() map[string]string { } return result } + +func Attribute(key string, value string) *AttributeMap { + return Attributes(&AttributeMap{key: value}) +} + +func AttributeList(children ...*AttributeMap) *AttributeMap { + m := make(AttributeMap) + for _, child := range children { + for k, v := range *child { + m[k] = v + } + } + return &m +} + +func Attributes(attrs *AttributeMap) *AttributeMap { + return attrs +} + +func AttributePairs(pairs ...string) *AttributeMap { + if len(pairs)%2 != 0 { + return &AttributeMap{} + } + m := make(AttributeMap) + for i := 0; i < len(pairs); i++ { + m[pairs[i]] = pairs[i+1] + i++ + } + return &m +} + +func Checked() Ren { + return Attribute("checked", "true") +} + +func Id(value string) Ren { + if strings.HasPrefix(value, "#") { + value = value[1:] + } + return Attribute("id", value) +} + +func Disabled() Ren { + return Attribute("disabled", "") +} + +func HxTarget(target string) Ren { + return Attribute(hx.TargetAttr, target) +} + +func Name(name string) Ren { + return Attribute("name", name) +} + +func HxConfirm(message string) Ren { + return Attribute(hx.ConfirmAttr, message) +} + +// HxInclude https://htmx.org/attributes/hx-include/ +func HxInclude(selector string) Ren { + return Attribute(hx.IncludeAttr, selector) +} + +func HxIndicator(tag string) *AttributeMap { + return Attribute(hx.IndicatorAttr, tag) +} + +func TriggerChildren() Ren { + return HxExtension("trigger-children") +} + +func TriggerString(triggers ...string) *AttributeMap { + trigger := hx.NewStringTrigger(strings.Join(triggers, ", ")) + return Attribute(hx.TriggerAttr, trigger.ToString()) +} + +func HxTrigger(opts ...hx.TriggerEvent) *AttributeMap { + return Attribute(hx.TriggerAttr, hx.NewTrigger(opts...).ToString()) +} + +func HxTriggerClick(opts ...hx.Modifier) *AttributeMap { + return HxTrigger(hx.OnClick(opts...)) +} + +func HxExtension(value string) Ren { + return Attribute(hx.ExtAttr, value) +} + +func Href(path string) Ren { + return Attribute("href", path) +} + +func Type(name string) Ren { + return Attribute("type", name) +} + +func Placeholder(placeholder string) Ren { + return Attribute("placeholder", placeholder) +} + +func Hidden() Ren { + return Attribute("style", "display:none") +} + +func Class(value ...string) Ren { + return Attribute("class", MergeClasses(value...)) +} + +func ClassX(value string, m ClassMap) Ren { + builder := strings.Builder{} + builder.WriteString(value) + builder.WriteString(" ") + for k, v := range m { + if v { + builder.WriteString(k) + builder.WriteString(" ") + } + } + return Class(builder.String()) +} + +func MergeClasses(classes ...string) string { + if len(classes) == 1 { + return classes[0] + } + builder := strings.Builder{} + for _, s := range classes { + builder.WriteString(s) + builder.WriteString(" ") + } + return builder.String() +} + +func Boost() Ren { + return Attribute(hx.BoostAttr, "true") +} + +func IfQueryParam(key string, node *Element) Ren { + return Fragment(Attribute("hx-if-qp:"+key, "true"), node) +} diff --git a/framework/h/base.go b/framework/h/base.go index 7074428..7e30742 100644 --- a/framework/h/base.go +++ b/framework/h/base.go @@ -51,6 +51,18 @@ func NewPartial(root *Element) *Partial { } } +func SwapManyPartial(ctx *RequestContext, swaps ...*Element) *Partial { + return NewPartial( + SwapMany(ctx, swaps...), + ) +} + +func SwapManyXPartial(ctx *RequestContext, swaps ...SwapArg) *Partial { + return NewPartial( + SwapManyX(ctx, swaps...), + ) +} + func GetPartialPath(partial func(ctx *RequestContext) *Partial) string { return runtime.FuncForPC(reflect.ValueOf(partial).Pointer()).Name() } diff --git a/framework/h/conditionals.go b/framework/h/conditionals.go index 9455fa6..70b04df 100644 --- a/framework/h/conditionals.go +++ b/framework/h/conditionals.go @@ -8,6 +8,13 @@ func If(condition bool, node Ren) Ren { } } +func Ternary[T any](value bool, a T, b T) T { + if value { + return a + } + return b +} + func IfElse(condition bool, node Ren, node2 Ren) Ren { if condition { return node @@ -30,3 +37,10 @@ func IfHtmxRequest(ctx *RequestContext, node Ren) Ren { } return Empty() } + +func ClassIf(condition bool, value string) Ren { + if condition { + return Class(value) + } + return Empty() +} diff --git a/framework/h/header.go b/framework/h/header.go new file mode 100644 index 0000000..b66bbe7 --- /dev/null +++ b/framework/h/header.go @@ -0,0 +1,41 @@ +package h + +import ( + "github.com/maddalax/htmgo/framework/hx" + "net/url" +) + +func ReplaceUrlHeader(url string) *Headers { + return NewHeaders(hx.ReplaceUrlHeader, url) +} + +func CombineHeaders(headers ...*Headers) *Headers { + m := make(Headers) + for _, h := range headers { + for k, v := range *h { + m[k] = v + } + } + return &m +} + +func CurrentPath(ctx *RequestContext) string { + current := ctx.Request().Header.Get(hx.CurrentUrlHeader) + parsed, err := url.Parse(current) + if err != nil { + return "" + } + return parsed.Path +} + +func NewHeaders(headers ...string) *Headers { + if len(headers)%2 != 0 { + return &Headers{} + } + m := make(Headers) + for i := 0; i < len(headers); i++ { + m[headers[i]] = headers[i+1] + i++ + } + return &m +} diff --git a/framework/h/qs.go b/framework/h/qs.go new file mode 100644 index 0000000..548157f --- /dev/null +++ b/framework/h/qs.go @@ -0,0 +1,89 @@ +package h + +import ( + "github.com/maddalax/htmgo/framework/hx" + "net/url" + "strings" +) + +type Qs struct { + m map[string]string +} + +func NewQs(pairs ...string) *Qs { + q := &Qs{ + m: make(map[string]string), + } + if len(pairs)%2 != 0 { + return q + } + for i := 0; i < len(pairs); i++ { + q.m[pairs[i]] = pairs[i+1] + i++ + } + return q +} + +func (q *Qs) Add(key string, value string) *Qs { + q.m[key] = value + return q +} + +func (q *Qs) Remove(key string) *Qs { + delete(q.m, key) + return q +} + +func (q *Qs) ToString() string { + builder := strings.Builder{} + index := 0 + for k, v := range q.m { + builder.WriteString(k) + builder.WriteString("=") + builder.WriteString(v) + if index < len(q.m)-1 { + builder.WriteString("&") + } + index++ + } + return builder.String() +} + +func PushQsHeader(ctx *RequestContext, qs *Qs) *Headers { + parsed, err := url.Parse(ctx.currentBrowserUrl) + if err != nil { + return NewHeaders() + } + return NewHeaders(hx.ReplaceUrlHeader, SetQueryParams(parsed.Path, qs)) +} + +func GetQueryParam(ctx *RequestContext, key string) string { + value := ctx.QueryParam(key) + if value == "" { + current := ctx.currentBrowserUrl + if current != "" { + u, err := url.Parse(current) + if err == nil { + return u.Query().Get(key) + } + } + } + return value +} + +func SetQueryParams(href string, qs *Qs) string { + u, err := url.Parse(href) + if err != nil { + return href + } + q := u.Query() + for key, value := range qs.m { + if value == "" { + q.Del(key) + } else { + q.Set(key, value) + } + } + u.RawQuery = q.Encode() + return u.String() +} diff --git a/framework/h/render.go b/framework/h/render.go index 1ce50c4..6319e64 100644 --- a/framework/h/render.go +++ b/framework/h/render.go @@ -6,6 +6,10 @@ import ( "time" ) +type Ren interface { + Render(builder *strings.Builder) +} + func Render(node Ren) string { start := time.Now() builder := &strings.Builder{} diff --git a/framework/h/swap.go b/framework/h/swap.go new file mode 100644 index 0000000..b43a2af --- /dev/null +++ b/framework/h/swap.go @@ -0,0 +1,83 @@ +package h + +import ( + "fmt" + "github.com/maddalax/htmgo/framework/hx" +) + +type SwapArg struct { + Content *Element + Option SwapOption +} + +type SwapOption struct { + Selector string + SwapType hx.SwapType + Modifier string +} + +func NewSwap(content *Element, opts ...SwapOption) SwapArg { + option := SwapOption{} + if len(opts) > 0 { + option = opts[0] + } + return SwapArg{ + Content: content, + Option: option, + } +} + +func OobSwap(ctx *RequestContext, content *Element, option ...SwapOption) *Element { + return OobSwapWithSelector(ctx, "", content, option...) +} + +func OobSwapWithSelector(ctx *RequestContext, selector string, content *Element, option ...SwapOption) *Element { + if ctx == nil || !ctx.isHxRequest { + return Empty() + } + return content.AppendChild(outOfBandSwap(selector, option...)) +} + +func outOfBandSwap(selector string, option ...SwapOption) Ren { + swapType := hx.SwapTypeTrue + + if len(option) > 0 { + o := option[0] + + if o.SwapType != "" { + swapType = o.SwapType + } + + modifier := o.Modifier + if modifier != "" { + swapType = fmt.Sprintf("%s %s", swapType, modifier) + } + } + + return Attribute(hx.SwapOobAttr, + Ternary(selector == "", swapType, selector)) +} + +func SwapMany(ctx *RequestContext, elements ...*Element) *Element { + if !ctx.isHxRequest { + return Empty() + } + for _, element := range elements { + element.AppendChild(outOfBandSwap("")) + } + return Template(Map(elements, func(arg *Element) Ren { + return arg + })...) +} + +func SwapManyX(ctx *RequestContext, args ...SwapArg) *Element { + if !ctx.isHxRequest { + return Empty() + } + for _, arg := range args { + arg.Content.AppendChild(outOfBandSwap("", arg.Option)) + } + return Template(Map(args, func(arg SwapArg) Ren { + return arg.Content + })...) +} diff --git a/framework/h/tag.go b/framework/h/tag.go index ec47f70..cfaf78b 100644 --- a/framework/h/tag.go +++ b/framework/h/tag.go @@ -1,50 +1,10 @@ package h import ( - "encoding/json" "fmt" - "github.com/maddalax/htmgo/framework/hx" - "net/url" - "strings" ) -type Qs struct { - m map[string]string -} - -func NewQs(pairs ...string) *Qs { - q := &Qs{ - m: make(map[string]string), - } - if len(pairs)%2 != 0 { - return q - } - for i := 0; i < len(pairs); i++ { - q.m[pairs[i]] = pairs[i+1] - i++ - } - return q -} - -func (q *Qs) Add(key string, value string) *Qs { - q.m[key] = value - return q -} - -func (q *Qs) ToString() string { - builder := strings.Builder{} - index := 0 - for k, v := range q.m { - builder.WriteString(k) - builder.WriteString("=") - builder.WriteString(v) - if index < len(q.m)-1 { - builder.WriteString("&") - } - index++ - } - return builder.String() -} +type ClassMap map[string]bool type PartialFunc = func(ctx *RequestContext) *Partial @@ -59,113 +19,7 @@ func (node *Element) AppendChild(child Ren) *Element { return node } -func Data(data map[string]any) Ren { - serialized, err := json.Marshal(data) - if err != nil { - return Empty() - } - return Attribute("x-data", string(serialized)) -} - -func ClassIf(condition bool, value string) Ren { - if condition { - return Class(value) - } - return Empty() -} - -func Class(value ...string) Ren { - return Attribute("class", MergeClasses(value...)) -} - -func ClassX(value string, m ClassMap) Ren { - builder := strings.Builder{} - builder.WriteString(value) - builder.WriteString(" ") - for k, v := range m { - if v { - builder.WriteString(k) - builder.WriteString(" ") - } - } - return Class(builder.String()) -} - -func MergeClasses(classes ...string) string { - if len(classes) == 1 { - return classes[0] - } - builder := strings.Builder{} - for _, s := range classes { - builder.WriteString(s) - builder.WriteString(" ") - } - return builder.String() -} - -func Id(value string) Ren { - if strings.HasPrefix(value, "#") { - value = value[1:] - } - return Attribute("id", value) -} - -type ClassMap map[string]bool - -func Attributes(attrs *AttributeMap) *AttributeMap { - return attrs -} - -func AttributePairs(pairs ...string) *AttributeMap { - if len(pairs)%2 != 0 { - return &AttributeMap{} - } - m := make(AttributeMap) - for i := 0; i < len(pairs); i++ { - m[pairs[i]] = pairs[i+1] - i++ - } - return &m -} - -func Checked() Ren { - return Attribute("checked", "true") -} - -func Boost() Ren { - return Attribute(hx.BoostAttr, "true") -} - -func Attribute(key string, value string) *AttributeMap { - return Attributes(&AttributeMap{key: value}) -} - -func TriggerChildren() Ren { - return HxExtension("trigger-children") -} - -func HxExtension(value string) Ren { - return Attribute(hx.ExtAttr, value) -} - -func Disabled() Ren { - return Attribute("disabled", "") -} - -func TriggerString(triggers ...string) *AttributeMap { - trigger := hx.NewStringTrigger(strings.Join(triggers, ", ")) - return Attribute(hx.TriggerAttr, trigger.ToString()) -} - -func Trigger(opts ...hx.TriggerEvent) *AttributeMap { - return Attribute(hx.TriggerAttr, hx.NewTrigger(opts...).ToString()) -} - -func TriggerClick(opts ...hx.Modifier) *AttributeMap { - return Trigger(hx.OnClick(opts...)) -} - -func TextF(format string, args ...interface{}) Ren { +func TextF(format string, args ...interface{}) *TextContent { return Text(fmt.Sprintf(format, args...)) } @@ -177,39 +31,6 @@ func Pf(format string, args ...interface{}) Ren { return P(Text(fmt.Sprintf(format, args...))) } -func Target(target string) Ren { - return Attribute(hx.TargetAttr, target) -} - -func Name(name string) Ren { - return Attribute("name", name) -} - -func Confirm(message string) Ren { - return Attribute(hx.ConfirmAttr, message) -} - -func Href(path string) Ren { - return Attribute("href", path) -} - -func Type(name string) Ren { - return Attribute("type", name) -} - -func Placeholder(placeholder string) Ren { - return Attribute("placeholder", placeholder) -} - -func OutOfBandSwap(selector string) Ren { - return Attribute(hx.SwapOobAttr, - Ternary(selector == "", "true", selector)) -} - -func Click(value string) Ren { - return Attribute("onclick", value) -} - func Tag(tag string, children ...Ren) *Element { return &Element{ tag: tag, @@ -292,52 +113,6 @@ func Article(children ...Ren) *Element { return Tag("article", children...) } -func ReplaceUrlHeader(url string) *Headers { - return NewHeaders(hx.ReplaceUrlHeader, url) -} - -func CombineHeaders(headers ...*Headers) *Headers { - m := make(Headers) - for _, h := range headers { - for k, v := range *h { - m[k] = v - } - } - return &m -} - -func CurrentPath(ctx *RequestContext) string { - current := ctx.Request().Header.Get(hx.CurrentUrlHeader) - parsed, err := url.Parse(current) - if err != nil { - return "" - } - return parsed.Path -} - -func PushQsHeader(ctx *RequestContext, key string, value string) *Headers { - current := ctx.Request().Header.Get(hx.CurrentUrlHeader) - parsed, err := url.Parse(current) - if err != nil { - return NewHeaders() - } - return NewHeaders(hx.ReplaceUrlHeader, SetQueryParams(parsed.Path, map[string]string{ - key: value, - })) -} - -func NewHeaders(headers ...string) *Headers { - if len(headers)%2 != 0 { - return &Headers{} - } - m := make(Headers) - for i := 0; i < len(headers); i++ { - m[headers[i]] = headers[i+1] - i++ - } - return &m -} - func Checkbox(children ...Ren) Ren { return Input("checkbox", children...) } @@ -368,14 +143,8 @@ func Fragment(children ...Ren) *ChildList { return Children(children...) } -func AttributeList(children ...*AttributeMap) *AttributeMap { - m := make(AttributeMap) - for _, child := range children { - for k, v := range *child { - m[k] = v - } - } - return &m +func Template(children ...Ren) *Element { + return Tag("template", children...) } func AppendChildren(node *Element, children ...Ren) Ren { @@ -388,10 +157,6 @@ func Button(children ...Ren) *Element { return Tag("button", children...) } -func Indicator(tag string) *AttributeMap { - return Attribute(hx.IndicatorAttr, tag) -} - func P(children ...Ren) *Element { return Tag("p", children...) } @@ -446,14 +211,6 @@ func Empty() *Element { } } -func IfQueryParam(key string, node *Element) Ren { - return Fragment(Attribute("hx-if-qp:"+key, "true"), node) -} - -func Hidden() Ren { - return Attribute("style", "display:none") -} - func Children(children ...Ren) *ChildList { return NewChildList(children...) } @@ -461,42 +218,3 @@ func Children(children ...Ren) *ChildList { func Label(text string) *Element { return Tag("label", Text(text)) } - -func GetTriggerName(ctx *RequestContext) string { - return ctx.Request().Header.Get("HX-Trigger-Name") -} - -type SwapArg struct { - Selector string - Content *Element -} - -func NewSwap(selector string, content *Element) SwapArg { - return SwapArg{ - Selector: selector, - Content: content, - } -} - -func OobSwap(ctx *RequestContext, content *Element) *Element { - return OobSwapWithSelector(ctx, "", content) -} - -func OobSwapWithSelector(ctx *RequestContext, selector string, content *Element) *Element { - if ctx == nil || ctx.Get("HX-Request") == "" { - return Empty() - } - return content.AppendChild(OutOfBandSwap(selector)) -} - -func SwapMany(ctx *RequestContext, args ...SwapArg) Ren { - if ctx.Get("HX-Request") == "" { - return Empty() - } - for _, arg := range args { - arg.Content.AppendChild(OutOfBandSwap(arg.Selector)) - } - return Fragment(Map(args, func(arg SwapArg) Ren { - return arg.Content - })...) -} diff --git a/framework/h/util.go b/framework/h/util.go index 16b962f..3533737 100644 --- a/framework/h/util.go +++ b/framework/h/util.go @@ -2,22 +2,8 @@ package h import ( "encoding/json" - "github.com/labstack/echo/v4" - "net/url" - "strings" ) -type Ren interface { - Render(builder *strings.Builder) -} - -func Ternary[T any](value bool, a T, b T) T { - if value { - return a - } - return b -} - func JsonSerialize(data any) string { serialized, err := json.Marshal(data) if err != nil { @@ -25,34 +11,3 @@ func JsonSerialize(data any) string { } return string(serialized) } - -func GetQueryParam(ctx echo.Context, key string) string { - value := ctx.QueryParam(key) - if value == "" { - current := ctx.Request().Header.Get("Hx-Current-Url") - if current != "" { - u, err := url.Parse(current) - if err == nil { - return u.Query().Get(key) - } - } - } - return value -} - -func SetQueryParams(href string, qs map[string]string) string { - u, err := url.Parse(href) - if err != nil { - return href - } - q := u.Query() - for key, value := range qs { - if value == "" { - q.Del(key) - } else { - q.Set(key, value) - } - } - u.RawQuery = q.Encode() - return u.String() -} diff --git a/framework/h/xhr.go b/framework/h/xhr.go index a31fa24..1350b9f 100644 --- a/framework/h/xhr.go +++ b/framework/h/xhr.go @@ -14,7 +14,7 @@ func GetPartialWithQs(partial PartialFunc, qs *Qs, trigger string) *AttributeMap return Get(GetPartialPathWithQs(partial, qs), trigger) } -func GetWithQs(path string, qs map[string]string, trigger string) *AttributeMap { +func GetWithQs(path string, qs *Qs, trigger string) *AttributeMap { return Get(SetQueryParams(path, qs), trigger) } diff --git a/framework/hx/htmx.go b/framework/hx/htmx.go index 5d3adee..6b2ce92 100644 --- a/framework/hx/htmx.go +++ b/framework/hx/htmx.go @@ -3,6 +3,7 @@ package hx type Attribute = string type Header = string type Event = string +type SwapType = string // https://htmx.org/reference/#events const ( @@ -42,6 +43,12 @@ const ( ) const ( + BoostedHeader Header = "HX-Boosted" + PromptResponseHeader Header = "HX-Prompt" + RequestHeader Header = "HX-Request" + TargetIdHeader Header = "HX-Target" + TriggerNameHeader Header = "HX-Trigger-Name" + TriggerIdHeader Header = "HX-Trigger" LocationHeader Header = "HX-Location" PushUrlHeader Header = "HX-Push-Url" RedirectHeader Header = "HX-Redirect" @@ -136,3 +143,16 @@ const ( DropEvent Event = "ondrop" DragEndEvent Event = "ondragend" ) + +const ( + SwapTypeTrue SwapType = "true" + SwapTypeInnerHtml SwapType = "innerHTML" + SwapTypeOuterHtml SwapType = "outerHTML" + SwapTypeTextContent SwapType = "textContent" + SwapTypeBeforeBegin SwapType = "beforebegin" + SwapTypeAfterBegin SwapType = "afterbegin" + SwapTypeBeforeEnd SwapType = "beforeend" + SwapTypeAfterEnd SwapType = "afterend" + SwapTypeDelete SwapType = "delete" + SwapTypeNone SwapType = "none" +) diff --git a/htmgo-site/partials/navbar.go b/htmgo-site/partials/navbar.go index 63f0973..7224729 100644 --- a/htmgo-site/partials/navbar.go +++ b/htmgo-site/partials/navbar.go @@ -10,8 +10,9 @@ type NavItem struct { } func ToggleNavbar(ctx *h.RequestContext) *h.Partial { - return h.NewPartial( - h.OobSwap(ctx, MobileNav(h.GetQueryParam(ctx, "expanded") == "true")), + return h.SwapManyPartial( + ctx, + MobileNav(h.GetQueryParam(ctx, "expanded") == "true"), ) } diff --git a/sandbox/partials/patient/create.go b/sandbox/partials/patient/create.go index e56cf5d..08dddf8 100644 --- a/sandbox/partials/patient/create.go +++ b/sandbox/partials/patient/create.go @@ -29,7 +29,7 @@ func Create(ctx echo.Context) *h.Partial { } headers := h.CombineHeaders(h.PushQsHeader(ctx, "adding", ""), &map[string]string{ - "HX-Trigger": "patient-added", + "HX-HxTrigger": "patient-added", }) return h.NewPartialWithHeaders( diff --git a/todo-list/partials/task/task.go b/todo-list/partials/task/task.go index 6ff2052..5692d7e 100644 --- a/todo-list/partials/task/task.go +++ b/todo-list/partials/task/task.go @@ -55,7 +55,7 @@ func Input(list []*ent.Task) *h.Element { h.Class("pl-12 text-xl p-4 w-full outline-none focus:outline-2 focus:outline-rose-400"), h.Placeholder("What needs to be done?"), h.Post(h.GetPartialPath(Create)), - h.Trigger("keyup[keyCode==13]"), + h.HxTrigger("keyup[keyCode==13]"), ), CompleteAllIcon(list), ) @@ -162,7 +162,7 @@ func Task(task *ent.Task, editing bool) *h.Element { ), ), h.P( - h.Trigger("dblclick"), + h.HxTrigger("dblclick"), h.GetPartialWithQs(EditNameForm, "id="+task.ID.String()), h.ClassX("text-xl break-all text-wrap truncate", map[string]bool{ "line-through text-slate-400": task.CompletedAt != nil, @@ -174,7 +174,7 @@ func Task(task *ent.Task, editing bool) *h.Element { func CompleteIcon(task *ent.Task) *h.Element { return h.Div( - h.Trigger("click"), + h.HxTrigger("click"), h.Post(h.GetPartialPathWithQs(ToggleCompleted, "id="+task.ID.String())), h.Class("flex items-center justify-center cursor-pointer"), h.Div(