widget

package module
v0.6.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 1 Imported by: 0

README

tinywasm/widget

Visual component contracts, states, layout, and styling for the tinywasm suite.

Usage

package main

import (
	"github.com/tinywasm/fmt"
	"github.com/tinywasm/widget"
	"github.com/tinywasm/widget/style"
)

type MasterDetail struct{}

func (m *MasterDetail) WidgetName() widget.Name { return widget.Name("masterdetail") }
func (m *MasterDetail) WidgetKind() widget.Kind { return widget.Grid }

func (m *MasterDetail) Style() *style.Sheet {
	return style.For(m).
		Root(style.Grid(style.ColumnNarrow, style.Space2), style.As(style.Page), style.Scroll()).
		Part("master", style.Stack(style.Space1), style.As(style.Panel), style.Pad(style.Space3)).
		Part("detail", style.Stack(style.Space2), style.As(style.Panel), style.Pad(style.Space3)).
		Part("item",   style.Row(style.Space1),   style.Interactive(style.Subtle)).
		When(widget.Selected, "item", style.As(style.Highlight))
}

func main() {
	m := &MasterDetail{}
	fmt.Println(m.Style().Stylesheet().String())
}

Documentation

  • AGENTS.md — constraints for anyone (human or agent) changing this library: the WASM boundary, zero escape, never invent a value, and the SSR contract every style builder must satisfy.
  • GUIDE.md — task-oriented decision guide and standard scales.
  • docs/ARCHITECTURE.md — package boundaries (WASM / non-WASM), anatomy and state contracts, and CSS emission guarantees.
  • docs/SPECS.md — exact public surface, scale-to-token mappings, emission tables, and validation conditions.
  • docs/DESIGN.md — the reasoning behind each decision and the alternatives rejected.
  • docs/TRADEOFFS.md — what the architecture buys, what it costs, and the limitations it accepts.
  • docs/MIGRATION.md — moving a consumer to the closed API; includes the v0.5.0 mapping for the one typed state writer (dom.BindState).
  • docs/diagrams/BOUNDARIES.md — how css, widget and ssr divide the problem, and the WASM boundary.

Documentation

Overview

Package widget defines visual component contracts, states, and layout.

It travels inside the WASM binary, so it carries zero style logic and zero emission.

Index

Constants

View Source
const (
	PartLabel      = Part("label")
	PartInput      = Part("input")
	PartError      = Part("error")
	PartRadioGroup = Part("radio-group")
	PartSubmit     = Part("submit")
)

Parts of the field. The names are generic by design: Part is local to its widget and only becomes a class through a Name, so "label" here produces "tw-field__label" and never collides with the "label" of another widget.

View Source
const NameField = Name("tw-field")

NameField is the shared anatomy of the form field.

It is emitted by github.com/tinywasm/form (which builds the markup) and styled by github.com/tinywasm/components/fieldset (which is the global skin of the forms). It lives here because it crosses the boundary between these two libraries, and neither can own it without the other depending on it.

Variables

This section is empty.

Functions

This section is empty.

Types

type Class

type Class string

Class is a CSS class name. It has NO public constructor: the only way to obtain one is to derive it from a Name. This ensures markup and stylesheet agree by construction.

func (Class) AsAttr

func (c Class) AsAttr() fmt.KeyValue

func (Class) String

func (c Class) String() string

type Cue

type Cue uint8

Cue is a state that the BROWSER possesses. It is only styled; it cannot be written from Go — which is why it is a separate type and has no Attr().

const (
	Hover Cue = iota
	Focus
	Press
	Target
)

type Dismissible

type Dismissible interface{ Dismiss() }

type Expandable

type Expandable interface{ Expand(open bool) }

type Filterable added in v0.5.1

type Filterable interface{ OnFilterChange(func(term string)) }

Filterable is implemented by a control that narrows a host's collection: a search bar, a date picker, a category select. The host registers one sink and the control calls it whenever the term changes.

The term is a plain string because that is what the consuming end takes (view.Presenter.Filter(term string)). A calendar formats its range into a term; a select emits the chosen id. Widening this to a structured query is a change to that contract, not to this one.

The host registers the sink once, at wiring time, and never reads it back — which is why this is a setter and not a field: a control is free to fan the sink out to several inputs, or to debounce it, without the host knowing.

type Kind

type Kind uint8

Kind is the type of widget according to WAI-ARIA Authoring Practices. It determines the role, valid states, and expected keyboard interactions. Closed by design: if a widget does not fit any pattern, it is almost always two widgets.

const (
	Region Kind = iota
	Listbox
	Menu
	Dialog
	Disclosure
	Tabs
	Toolbar
	Grid
	Combobox
	Form
	Alert
)

func (Kind) Allows added in v0.4.0

func (k Kind) Allows(s State) bool

Allows returns whether the given state is meaningful for the Kind.

func (Kind) Layer added in v0.4.0

func (k Kind) Layer() Layer

Layer returns the stacking level of the Kind.

func (Kind) Role added in v0.4.0

func (k Kind) Role() fmt.KeyValue

Role returns the ARIA role of the Kind as a KeyValue attribute.

func (Kind) String added in v0.4.0

func (k Kind) String() string

type Layer added in v0.4.0

type Layer uint8

Layer is the stacking level of a pattern. It is an enum, not a css.Token: this package travels inside the WASM binary and must not import css. widget/style maps it to the --z-* catalog.

const (
	LayerBase Layer = iota
	LayerDropdown
	LayerSticky
	LayerModal
	LayerToast
	LayerTooltip
)

type Name

type Name string

Name identifies a widget. It is the prefix of EVERY class it emits, so two widgets cannot collide even if they choose the same part name.

func (Name) Class

func (n Name) Class(p Part) Class

Class derives the class of an anatomical part: e.g. "targetlist__row".

func (Name) Root

func (n Name) Root() Class

Root is the outer class of the widget.

type Part

type Part string

Part is a named slot of a widget's anatomy (Open UI vocabulary). It is local to the widget: e.g. "row", "menu", "header". It never carries a prefix.

type Selectable

type Selectable interface{ Select(id string) }

Capabilities — each hook asserts only the capability it needs.

type State

type State uint8

State is a state that the widget POSSESSES: written by Go, read by the stylesheet.

Open is the expanded/visible state a SHEET selects on. Do not use BindState with it on a <details> element: the browser writes the native `open` attribute onto the element itself, and usermenu/targetlist mirror that into a signal precisely because the element owns the attribute. A data-open state written alongside is a separate thing that happens to share a name.

const (
	Selected State = iota
	Disabled
	Locked // read-only, but fully legible
	Invalid
	Busy
	Open    // deployed / expanded
	Current // active navigation item
)

func (State) Attr

func (s State) Attr() StateAttr

Attr returns the attribute that the DOM writes and upon which the stylesheet selects. Markup and CSS match by construction, not by convention.

func (State) Key added in v0.5.0

func (s State) Key() string

Key and Value let a State itself be passed to dom's BindState/BindStateFunc/ SetState: the projection is derived inside dom, so the value written is always the one the sheet selects on.

func (State) String added in v0.4.0

func (s State) String() string

func (State) Value added in v0.5.0

func (s State) Value() string

type StateAttr added in v0.5.0

type StateAttr struct {
	// contains filtered or unexported fields
}

StateAttr is the DOM projection of a State: the attribute the markup writes and the stylesheet selects on, as one value.

It is a distinct type on purpose. It used to be an fmt.KeyValue, which is a bare string pair — and a string pair fits every attribute method dom exposes, including the ones that write the wrong value. A state written with BindAttrBool lands as `data-x=""`, the sheet selects `data-x="true"`, and nothing reports the mismatch. The type is what makes that call not compile.

func (StateAttr) Key added in v0.5.0

func (a StateAttr) Key() string

Key and Value are for the two libraries that have to reach the strings: tinywasm/dom, which writes the attribute, and widget/style, which emits the selector. Reading them to hand-wire a state is the mistake this type exists to prevent — use dom's BindState/SetState instead.

func (StateAttr) Value added in v0.5.0

func (a StateAttr) Value() string

type Widget

type Widget interface {
	WidgetName() Name
	WidgetKind() Kind
}

Widget is the identity. It is the only mandatory interface.

Directories

Path Synopsis
Package style is the stylesheet engine for visual components.
Package style is the stylesheet engine for visual components.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL