Skip to content
webtypPublic

About

Input widgets library for tinywasm forms

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Input Types

This package contains all input implementations for webtyp/form. Each input implements model.Kind (Type, Validate, Clone) plus metadata getters. Inputs are render-free: they carry no dom/html imports. Rendering is done by the form package via RenderInput(input.Input). All inputs use only webtyp/fmt — no errors or strconv from the standard library.

Available Inputs

Type HTML type Validation rules
Address text Letters, Numbers, . , - # /, Min: 5, Max: 200
Checkbox checkbox true, false, on, 1, 0 or empty
Date date YYYY-MM-DD format, leap year + month/day range check
Datalist text Value must match one of the registered Options.Key
Decimal number Digits, ., -, Min: 1, Max: 20 chars — storage FieldFloat (see note)
Email email Letters, Numbers, @ . _ -, Min: 5, Max: 100
Filepath text Letters, digits, .\/- _, no whitespace, Min: 1
Gender radio m/f pre-wired options
Hour time HH:MM format, digits + :, validates 24h range
IP text IPv4 or IPv6 format; 0.0.0.0 rejected
MAC text 12 hex digits, plain or :/- separated; see CanonicalMAC, IsLocallyAdministeredMAC
Number number Digits only (0-9), Min: 1, Max: 20 chars
Password password Any char, Min: 5, Max: 50
Phone tel Digits, + ( ) -, Min: 7, Max: 15
Radio radio Value must match one of the registered Options.Key
Rut text Chilean RUT XXXXXXX-D, verifies check digit
Search search Letters, Numbers, Spaces, Min: 0, Max: 100 — optional
Select select Value must match one of the registered Options.Key
Text text Letters, Numbers, . , ( ), Min: 2, Max: 100
Textarea textarea Wide char set incl. \n, Min: 5, Max: 2000

Number vs Decimal: both render the same <input type="number">. The difference is Storage() — Number() reports model.FieldInt (int64), Decimal() reports model.FieldFloat (float64). Use Decimal for any field with fractional precision (price, measurements, percentages, ...); using Number there silently truncates the value to a whole number.

No Standard Library

Rule: All input files must import only webtyp.com/fmt. No errors, strconv, or strings.

Use the webtyp/fmt equivalents:

// Instead of strconv.Atoi:
val, err := fmt.Convert("42").Int()

// Instead of errors.New:
return fmt.Err("Field", "Invalid")

// Instead of strings.ToLower:
lower := fmt.Convert(s).ToLower().String()

// Instead of strings.Contains:
found := fmt.Contains(haystack, needle)

Prototype Pattern

Constructors take zero arguments and return stateless prototypes. The form layer calls Clone(parentID, name) to create positioned instances that preserve all configuration.

// Schema definition (ormc generates this).
// input.* kinds get a form input + validation; model.* base kinds
// (e.g. model.Text()) validate only and are never rendered.
var schema = []model.Field{
    {Name: "email", Type: input.Email(), NotNull: true},
}

// form.New calls Clone internally, for fields whose Type implements input.Input:
// field.Type.(input.Input).Clone(formID, fieldName) → positioned input with id, name, HTML attributes

Creating a Custom Input (embedding Base)

All inputs share the same pattern: embed Base, configure Permitted rules, implement the Input interface. Custom inputs can live in your own package — Base, InitBase and all setters are exported.

package myapp

import (
    "webtyp.com/fmt"
    "webtyp.com/input"
)

// myInput is a custom input that only allows lowercase hex characters.
type myInput struct {
    input.Base
}

// MyInput creates a prototype — no arguments.
func MyInput() input.Input {
    m := &myInput{}
    m.Letters = true
    m.Numbers = true
    m.Minimum = 1
    m.Maximum = 40
    m.InitBase("", "", "text")
    m.SetPlaceholder("example:", "3f4a1b")
    m.SetTitle("Lowercase hex only")
    return m
}

func (m *myInput) Validate(value string) error {
    // Custom rule: no uppercase letters
    for _, c := range value {
        if c >= 'A' && c <= 'F' {
            return fmt.Err("Character", "Invalid")
        }
    }
    return m.Permitted.Validate(m.FieldName(), value)
}

// Clone creates a positioned copy preserving all configuration.
func (m *myInput) Clone(parentID, name string) input.Input {
    c := *m
    c.InitBase(parentID, name, "text")
    return &c
}

The custom input renders with the generic markup for its htmlName ("text" above). Storage defaults by htmlName (number → int, checkbox → bool, else text); override Storage() on your struct if your kind needs a different mapping.

Custom markup

Custom inputs can provide their own HTML markup by implementing form.Renderer (see docs/API.md). This allows for complex widgets (color pickers, composite fields) while the form still manages the field container, ID, and validation state.

Base Available Methods

Method Purpose
InitBase(parentID, name, htmlName) Required — sets ID, name, and HTML type
SetPlaceholder(string) HTML placeholder text
SetTitle(string) HTML title (tooltip)
SetOptions(...fmt.KeyValue) Options for select/radio/datalist
AddAttribute(key, value string) Custom extra HTML attributes
SetRequired(bool) HTML required attribute
SetSkipValidation(bool) Skip validation entirely

Composition Pattern (wrapping another input)

Reuse existing inputs to create semantic wrappers:

func Gender() Input {
    g := &gender{}
    g.InitBase("", "", "radio")
    g.SetOptions(
        fmt.KeyValue{Key: "m", Value: "Male"},
        fmt.KeyValue{Key: "f", Value: "Female"},
    )
    return g
}

About

Input widgets library for tinywasm forms

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages