diff --git a/htmgo-site/pages/examples/examples.go b/htmgo-site/pages/examples/examples.go index 2e7aabc..f979578 100644 --- a/htmgo-site/pages/examples/examples.go +++ b/htmgo-site/pages/examples/examples.go @@ -97,6 +97,15 @@ var JsHideChildrenOnClick = Snippet{ partial: snippets.JsHideChildrenOnClick, } +var InputComponentSnippet = Snippet{ + category: "Components", + name: "Input", + description: "An example of how you could build a re-usable input component", + sidebarName: "Text Input", + path: "/examples/input-component", + partial: snippets.InputComponent, +} + var examples = []Snippet{ FormWithLoadingStateSnippet, FormWithBlurValidationSnippet, @@ -110,4 +119,6 @@ var examples = []Snippet{ HackerNewsSnippet, TodoListSnippet, HtmgoSiteSnippet, + + InputComponentSnippet, } diff --git a/htmgo-site/pages/examples/input-component.go b/htmgo-site/pages/examples/input-component.go new file mode 100644 index 0000000..0fc879b --- /dev/null +++ b/htmgo-site/pages/examples/input-component.go @@ -0,0 +1,8 @@ +package examples + +import "github.com/maddalax/htmgo/framework/h" + +func InputComponentExample(ctx *h.RequestContext) *h.Page { + SetSnippet(ctx, &InputComponentSnippet) + return Index(ctx) +} diff --git a/htmgo-site/partials/snippets/input-component.go b/htmgo-site/partials/snippets/input-component.go new file mode 100644 index 0000000..1bd780e --- /dev/null +++ b/htmgo-site/partials/snippets/input-component.go @@ -0,0 +1,128 @@ +package snippets + +import ( + "github.com/maddalax/htmgo/framework/h" + "github.com/maddalax/htmgo/framework/hx" +) + +// InputComponent wrapper to make the code snippet work, main code is the Input function +func InputComponent(ctx *h.RequestContext) *h.Partial { + + return h.NewPartial( + h.Div( + h.Class("max-w-sm mx-auto flex flex-col gap-4"), + Input( + InputProps{ + Id: "my-input", + Name: "my-input", + Label: "Input with label", + Type: "text", + Placeholder: "Type something", + Required: true, + }, + h.Attribute("autocomplete", "off"), + h.MaxLength(50), + ), + Input( + InputProps{ + Id: "my-input", + Name: "my-input", + Label: "Input with default value", + Type: "text", + DefaultValue: "Default value", + }, + ), + Input( + InputProps{ + Id: "my-input", + Name: "my-input", + Label: "Input with helper text", + Type: "text", + Placeholder: "Full name", + HelperText: "This should be your full legal name", + }, + ), + ), + ) +} + +type InputProps struct { + Id string + Label string + Name string + Type string + DefaultValue string + Placeholder string + Required bool + ValidationPath string + HelperText string +} + +func Input(props InputProps, children ...h.Ren) *h.Element { + validation := h.If( + props.ValidationPath != "", + h.Children( + h.Post(props.ValidationPath, hx.BlurEvent), + h.Attribute("hx-swap", "innerHTML transition:true"), + h.Attribute("hx-target", "next div"), + ), + ) + + if props.Type == "" { + props.Type = "text" + } + + input := h.Input( + props.Type, + h.Class("border p-2 rounded"), + h.If( + props.Id != "", + h.Id(props.Id), + ), + h.If( + props.Name != "", + h.Name(props.Name), + ), + h.If( + children != nil, + h.Children(children...), + ), + h.If( + props.Required, + h.Required(), + ), + h.If( + props.Placeholder != "", + h.Placeholder(props.Placeholder), + ), + h.If( + props.DefaultValue != "", + h.Attribute("value", props.DefaultValue), + ), + validation, + ) + + wrapped := h.Div( + h.Class("flex flex-col gap-1"), + h.If( + props.Label != "", + h.Label( + h.Text(props.Label), + ), + ), + input, + h.If( + props.HelperText != "", + h.Div( + h.Class("text-slate-600 text-sm"), + h.Text(props.HelperText), + ), + ), + h.Div( + h.Id(props.Id+"-error"), + h.Class("text-red-500"), + ), + ) + + return wrapped +}