Documentation
¶
Overview ¶
Package style is the stylesheet engine for visual components.
It is excluded from WebAssembly by `//go:build !wasm` so it can never reach the client binary.
Index ¶
- type Aspect
- type ColumnWidth
- type Edge
- type Elevation
- type IconSize
- type Motion
- type Option
- func Anchor() Option
- func Animate(m Motion) Option
- func As(s Surface) Option
- func Backdrop(s Scope) Option
- func Capitalize() Option
- func Center(max ...Size) Option
- func CenterContent() Option
- func ChipBox() Option
- func ControlBox() Option
- func Cover() Option
- func Docked(scope Scope, edge Edge, side Side, gap Space) Option
- func Drawer(side Side, size Size) Option
- func EdgeToEdge() Option
- func Fill() Option
- func FillCentered() Option
- func FloatingChrome(edge Edge, size IconSize, gap Space) Option
- func Flyout(side Side) Option
- func FontSize(ts TextSize) Option
- func FontWeight(w Weight) Option
- func Glyph(s Surface) Option
- func Grid(min ColumnWidth, gap Space) Option
- func Grow() Option
- func Hide() Option
- func HideOverflow() Option
- func IconBox(s IconSize) Option
- func Interactive(s Surface) Option
- func KeepSize() Option
- func MasterDetail(detail Size) Option
- func MediaBox(a Aspect) Option
- func OnEdge(edge Edge, side Side, block Space, inline Space) Option
- func Pad(s Space) Option
- func PadEdge(e Edge, s Space) Option
- func PadInline(s Space) Option
- func PushEnd() Option
- func Raise(e Elevation) Option
- func RevealedBy(st widget.State) Option
- func Round(rad Radius) Option
- func Row(gap Space) Option
- func Scroll() Option
- func ScrollRow(gap Space) Option
- func Sidebar(side Side, width RailWidth, gap Space) Option
- func SlideDeck(m Motion) Option
- func Split(ratio SplitRatio, gap Space) Option
- func Stack(gap Space) Option
- func StartContent() Option
- func Veil() Option
- func Width(s Size) Option
- type Radius
- type RailWidth
- type Scope
- type Sheet
- func (s *Sheet) Cue(c widget.Cue, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) CueWithin(c widget.Cue, container, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) CueWithinHover(c widget.Cue, container, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) On(d css.Device, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) OnlyOn(d css.Device, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) Part(p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) Parts() []widget.Part
- func (s *Sheet) Root(opts ...Option) *Sheet
- func (s *Sheet) StateAttrs() []fmt.KeyValue
- func (s *Sheet) Stylesheet() *css.Stylesheet
- func (s *Sheet) Validate() []error
- func (s *Sheet) When(st widget.State, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) WhenWithin(st widget.State, container, p widget.Part, opts ...Option) *Sheet
- func (s *Sheet) Within(container, p widget.Part, opts ...Option) *Sheet
- type Side
- type Size
- type Space
- type SplitRatio
- type Surface
- type TextSize
- type Weight
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ColumnWidth ¶ added in v0.4.0
type ColumnWidth uint8
ColumnWidth represents minimum column width for grids.
const ( ColumnNarrow ColumnWidth = iota ColumnMedium ColumnWide )
type IconSize ¶ added in v0.4.4
type IconSize uint8
IconSize is the square size scale for icon-sized parts. The steps are relative to the inherited font size, so an icon tracks the text it sits with.
type Motion ¶ added in v0.3.1
type Motion uint8
Motion is the transition scale. Duration is owned by CSS; here we only select the level.
type Option ¶ added in v0.4.0
type Option func(*rule)
Option is a visual option that configures a rule.
func Anchor ¶ added in v0.5.0
func Anchor() Option
Anchor makes the element a positioning reference: it emits position: relative, which is what lets a Flyout descendant hang from it. It is the trigger's container — a menu, a combobox.
Anchor() only wins if nothing positioned sits between it and the Flyout: CSS resolves the Flyout's inset against the nearest POSITIONED ancestor, so a Docked/OnEdge/Backdrop part in between becomes the containing block instead and the Anchor is dead code. Validate() rejects that composition — see Within() for the legal way to declare nesting.
func As ¶ added in v0.4.0
As sets the surface decision (background, text, border, and radius default).
func Backdrop ¶ added in v0.3.0
Backdrop removes the element from the normal flow and stretches it over its Scope.
Example ¶
package main
import (
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
_ = style.For(btn).
Part("overlay", style.Backdrop(style.Viewport), style.Veil())
}
Output:
func Capitalize ¶ added in v0.5.11
func Capitalize() Option
Capitalize uppercases the first letter of every word the element renders. It is for text that arrives from a data source in whatever case the source happens to store it — a model's field names becoming a form's labels — so the presentation layer decides the casing instead of every caller having to pre-format the string it passes in.
func Center ¶
Center defines a centered column with an optional maximum size (defaults to Readable).
func CenterContent ¶ added in v0.5.0
func CenterContent() Option
CenterContent centers whatever the element contains, on both axes. A button holding nothing but an icon needs it: the icon is a replaced element with display: block, so the text-align a button carries by default does not move it and it sits against the leading edge.
func ChipBox ¶ added in v0.5.0
func ChipBox() Option
ChipBox gives the element the shared chip width, the box a legend or a badge occupies. Fixing it is what makes a column of chips line up instead of each one hugging its own text; the text itself is truncated by the component that renders it.
func ControlBox ¶ added in v0.5.0
func ControlBox() Option
ControlBox gives the element the shared control height, the rhythm every interactive row in the app is measured against — a list row, a form field. Pinning both to one token is what keeps them from drifting apart.
func Cover ¶
func Cover() Option
Cover locks the frame to the viewport height and stacks its children vertically. It is the outermost frame of an application shell: use KeepSize() on the children that must not shrink (a header) and Fill() on the one that takes the remaining height. Do not nest one Cover inside another.
The height is definite, not a floor, so a Fill() descendant resolves against it and a HideOverflow() or Scroll() descendant actually clips. A shell whose content can exceed the viewport must therefore give that descendant Scroll(); otherwise the overflow is unreachable.
func Docked ¶ added in v0.5.0
Docked pins the element inside a corner, above the content and out of the flow, at the widget kind's stacking layer. Use it for a control that must not cost the content a band of its own: a floating action button, a row's overflow menu.
Parent pins it to the corner of the nearest positioned ancestor — the Anchor only when nothing positioned sits between the two. Viewport pins it to the screen, so it stays put while the content behind it scrolls or swipes — and it disappears with the widget, because a fixed descendant of a display:none ancestor is not rendered either.
Docked also makes the element a containing block: a Flyout inside it hangs from THIS box, not from whatever Anchor sits above. Validate() reports the theft; the fix is either a docked trigger that spans the anchor, or the Flyout moving out of the docked part.
func Drawer ¶ added in v0.4.3
Drawer anchors the element to one inline edge of the viewport, full height, at the widget kind's stacking layer. It is the slide-in panel of a mobile navigation; pair it with RevealedBy(widget.Open) to control visibility and with a sibling Backdrop(Viewport)+Veil() for the dimmed page behind it.
Drawer sets the element's width. Do NOT also pass Width() — Validate rejects it.
func EdgeToEdge ¶ added in v0.4.0
func EdgeToEdge() Option
EdgeToEdge has no border radius or margin: flush against parent container.
func FillCentered ¶ added in v0.4.0
func FillCentered() Option
FillCentered fills the container with a centered child.
func FloatingChrome ¶ added in v0.5.12
FloatingChrome declares that this element occupies a strip along its edge, and every Scroll() region DESCENDANT of it must reserve that strip — the contract between a floating action button and the scroll container behind it. It emits, on its own box:
--floating-bottom: calc(<size> + 2 * <gap>);
(and the --floating-top counterpart for EdgeTop). The custom property is inherited, so the reservation crosses widget and repository boundaries: the host says "I occupy this band of my edge" and a Scroll() descendant — whatever widget it belongs to — pads itself by var(--floating-bottom, 0px) without either knowing the other's class name. No FloatingChrome means no declaration, and every scroller reserves nothing (the 0px default).
size is IconSize, not Size: floating chrome pinned to a screen edge is by construction a small icon-only control (a FAB, a hamburger) — the same IconBox(...) an author already gave its glyph. Size's members are percentages/keywords meant for a panel's share of a Split or a Flyout's width; a percentage inside padding-block-end resolves against the SCROLL REGION'S OWN inline size, not a fixed footprint, and max-content is not a <length> at all — neither compiles into a calc() that means what this needs. gap is doubled because the same value both pads the control on the edge closest to its icon and sets its own inset off the container edge.
This is the seam the badge-over-FAB overlap needed: the FAB's box is invisible to the badge's scrollHeight, so no padding computed from the badge's own box could reserve the space where the FAB really paints.
func Flyout ¶ added in v0.5.0
Flyout lifts the element out of the flow and hangs it under its containing block, flush with the given inline edge, at the widget kind's stacking layer. Use it for a dropdown: left in the flow, an expanding menu pushes everything below it down and the list jumps under the pointer that opened it.
The containing block is the nearest positioned ancestor. An Anchor() on the chain is what makes it hang where intended — but any positioned part between the two becomes the containing block instead, and nothing in the emitted CSS distinguishes the two. Validate() walks the declared part tree and rejects the interposition; declare the nesting with Within().
func Glyph ¶ added in v0.5.0
Glyph colours what the element draws — its text and, through currentColor, its icons — with a surface's base colour, and leaves the background alone. It is the "tinted, not filled" treatment: a nav item that is merely available shows a coloured icon, the selected one gets the filled surface via As().
func Grid ¶
func Grid(min ColumnWidth, gap Space) Option
Grid defines auto-fit + minmax without a fixed number of columns.
func Grow ¶ added in v0.5.0
func Grow() Option
Grow takes the free space along the inline axis and nothing else. It is the Row counterpart of Fill(): Fill() also claims `height: 100%`, which inside a Row resolves against the row and stretches the part into a full-height block. Use Grow() for the item in a Row that should push its siblings to the trailing edge.
func Hide ¶ added in v0.5.0
func Hide() Option
Hide removes the element. Its use is inside On(): a part that exists on wide screens and not on a phone keeps its base styling and is switched off for the one device, which OnlyOn cannot express — OnlyOn hides by default and reveals per device, the opposite direction.
func HideOverflow ¶ added in v0.4.0
func HideOverflow() Option
HideOverflow clips descendants (overflow: hidden).
func IconBox ¶ added in v0.4.4
IconBox sizes a part as a square that never shrinks — the shape an icon needs. A bare <svg> with no width or height falls back to the replaced-element default of 300x150 and blows the layout apart, so every part that renders one must declare its box here.
func Interactive ¶ added in v0.4.0
Interactive applies s and derives its hover, focus, and press treatments.
Example ¶
package main
import (
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
_ = style.For(btn).
Root(style.Interactive(style.Primary))
}
Output:
func KeepSize ¶ added in v0.4.0
func KeepSize() Option
KeepSize does NOT reflow: maintains its size under any width.
func MasterDetail ¶ added in v0.5.0
MasterDetail turns a two-panel container into a horizontal scroll-snap strip for a narrow screen: the master list rests where the browser's default scroll position already is, and the detail sits beside it at `detail` of the strip's width, so a sliver of the list stays visible and the panel it came from is obvious. Swiping is a native scroll; snapping to the detail is a plain ScrollIntoView from the row handler.
The FIRST TWO element children are the panels, in the same DOM order a desktop Split uses: detail first, master second. Anything after them — a modal mount point, a portal anchor — is left alone, which is why this addresses them by position and not with :first-child/:last-child. The strip is laid out RTL so the master — the second child, given order 1 — lands at the start edge, which RTL puts on the right, exactly where scroll position 0 already rests. That is what removes the need for a scroll nudge at mount time, which this framework's component contract has no hook for. Each panel resets to LTR so only the outer strip's flow is mirrored, never the content.
func OnEdge ¶ added in v0.5.0
OnEdge centres the element ON one of its Anchor's edge lines — half outside the box, half inside — the way a fieldset legend rides the border it labels.
block is the distance from the Anchor's border to the line being ridden: pass the Anchor's padding to ride the box that padding encloses, or SpaceNone to ride the Anchor's own border. inline is how far the chip is indented along that line. The straddle is exact because the chip's height is the shared --chip-height token, applied as half a chip-height of negative margin.
func PadEdge ¶ added in v0.5.0
PadEdge pads one block edge only. Pad() is all four sides, which is the right default; this exists for the case where a fixed overlay covers the top of a panel and the content underneath has to start below it without gaining the same inset left and right.
func PadInline ¶ added in v0.5.1
PadInline pads the inline axis (start and end) and nothing else. A chip whose height is contracted against another element — the fieldset legend matches the list badge — cannot take vertical padding, but its text still needs air at the sides; flush text against a filled chip edge reads as a bug, not as density.
func PushEnd ¶ added in v0.5.0
func PushEnd() Option
PushEnd sends the part to the trailing edge of its line. It is the companion of Grow(): Grow() absorbs the free space so the items after it are pushed out, PushEnd() moves the free space in front of a single item — the only way to keep something right-aligned once flex-wrap has dropped it onto a line of its own.
func RevealedBy ¶ added in v0.4.0
RevealedBy binds hiding/showing the element to a widget State.
Example ¶
package main
import (
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
_ = style.For(btn).
Part("menu", style.RevealedBy(widget.Open))
}
Output:
func Scroll ¶ added in v0.4.0
func Scroll() Option
Scroll overflows internally instead of growing. Implies Fill().
func Sidebar ¶ added in v0.4.3
Sidebar places a fixed-width rail beside a fluid content area. The rail keeps its width; the content takes everything else. Below the point where the content can no longer hold its minimum width the two reflow into a single column, with no media query involved.
The container MUST have exactly two element children. Which one is the rail is decided by side, not by DOM order: SideEnd makes the LAST child the rail.
func SlideDeck ¶ added in v0.5.3
SlideDeck apila a sus hijos en capas que ocupan el contenedor entero y muestra solo aquel que lleva el estado widget.Current; los demás quedan aparcados en el borde inline-start y entran deslizándose de izquierda a derecha cuando les toca.
Es la forma de cambiar de panel en un shell SIN crear un scroller: un contenedor de scroll-snap horizontal aquí encadena con el scroll-snap horizontal que un módulo pueda tener adentro, y el gesto de deslizar dentro del contenido termina cambiando de sección sola.
Todos los hijos siguen montados en el DOM. Ese es el trato: el estado decide cuál está en pantalla, nadie desmonta nada. El contenedor es el bloque contenedor de sus hijos, así que un Docked(Parent) dentro de un panel se resuelve contra SU panel — no hace falta Anchor() en el hijo, y ponerlo lo ROMPE: el position: relative de @layer widgets gana sobre el position: absolute que este flujo emite en @layer primitives.
m gobierna la duración del deslizamiento. MotionNone conmuta sin animación.
func Split ¶
func Split(ratio SplitRatio, gap Space) Option
Split defines two panels that stack below their own width.
Example ¶
package main
import (
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
_ = style.For(btn).
Root(style.Split(style.SplitTwoThirds, style.Space3))
}
Output:
func Stack ¶
Stack defines a vertical rhythm with children at full width.
Example ¶
package main
import (
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
_ = style.For(btn).
Root(style.Stack(style.Space4))
}
Output:
func StartContent ¶ added in v0.5.0
func StartContent() Option
StartContent packs what the element contains against its leading edge. It is the counterpart of CenterContent, for the case where the same part is centred in one state and aligned in another — an icon alone in a narrow rail, icon and label once the rail expands.
type RailWidth ¶ added in v0.4.3
type RailWidth uint8
RailWidth is the closed scale for a Sidebar's fixed column.
type Sheet ¶
type Sheet struct {
// contains filtered or unexported fields
}
Sheet represents a scoped stylesheet for a widget.
func For ¶ added in v0.4.0
For opens the styling block for a widget.
Example ¶
package main
import (
"fmt"
"github.com/tinywasm/widget"
"github.com/tinywasm/widget/style"
)
type myButton struct{}
func (b *myButton) WidgetName() widget.Name { return widget.Name("btn") }
func (b *myButton) WidgetKind() widget.Kind { return widget.Region }
func main() {
btn := &myButton{}
sheet := style.For(btn).
Root(style.As(style.Primary))
fmt.Println(sheet.Parts())
}
Output: []
func (*Sheet) Cue ¶
Cue defines the style for a part (or Root if p is "") when the browser has a cue.
func (*Sheet) CueWithin ¶ added in v0.5.0
CueWithin styles a part while an ANCESTOR part carries a browser cue — `.n__container:hover .n__part`. Reach for Cue() first; this is only for the case where the trigger and the thing that reacts are different elements, such as a rail that shows its labels while the pointer is over it.
func (*Sheet) CueWithinHover ¶ added in v0.5.8
CueWithinHover is CueWithin gated on the fine-pointer capability: the same descendant selector, emitted inside `@media (hover: hover)`. A touch tap fires `:hover` and synthetic mouse events, so a hover reveal that is not scoped this way misfires on a phone — the exact reason this variant exists.
func (*Sheet) On ¶ added in v0.4.3
On defines the style for a part (or Root if p is "") only on the given viewport class. It is the single sanctioned way to vary a widget by device: the query strings live in tinywasm/css and are exhaustively tested there.
Reach for a flow primitive first — Split, Grid and Sidebar already reflow on their own. Use On only when the ARRANGEMENT itself differs, e.g. a nav rail that becomes a drawer.
func (*Sheet) OnlyOn ¶ added in v0.4.3
OnlyOn declares a part that exists on one viewport class and nowhere else: it is display:none by default and takes the given options only on d.
Use it for chrome that is genuinely device-specific — a hamburger button, a drawer's backdrop. If the element merely CHANGES between devices rather than disappearing, declare it with Part() and refine it with On().
func (*Sheet) StateAttrs ¶ added in v0.4.3
func (*Sheet) Stylesheet ¶
func (s *Sheet) Stylesheet() *css.Stylesheet
func (*Sheet) When ¶
When defines the style for a part (or Root if p is "") when the widget has a specific state.
func (*Sheet) WhenWithin ¶ added in v0.5.11
WhenWithin styles a part while an ANCESTOR part carries a written state — `.n__container[data-x="true"] .n__part`. It is the State counterpart of CueWithin, and like CueWithin it is the exception, not the habit: reach for When() first.
It exists because dom writes a state onto the element that OWNS it, which is not always the element that should change. A form field's read-only gate is written on the field, but what must stop looking editable is the control inside it — When(Locked, PartInput) would emit `.n__input[data-locked="true"]` and match nothing, since the attribute is on the wrapper. Pass "" as container to hang the rule off the widget root.
func (*Sheet) Within ¶ added in v0.6.0
Within declares that part renders INSIDE container, and applies the options to part exactly as Part() would; what it adds is the containment relation, which the sheet needs to reason about positioning — who is whose containing block. It reads like the DOM: Within("menu", "options", Flyout(...)) is "options, inside menu".
Part() remains the normal declaration. Within() is only needed where containment changes the result: a Flyout that hangs from an Anchor while a positioned part sits between them. When it matters, the sheet rejects the composition until the nesting is declared — see Validate().
type Side ¶ added in v0.4.3
type Side uint8
Side names which edge a Sidebar's rail or a Drawer's panel is anchored to. Logical, not physical: it follows writing direction.
type SplitRatio ¶ added in v0.4.0
type SplitRatio uint8
SplitRatio is the flex-grow ratio for Split partitions.
const ( SplitHalf SplitRatio = iota SplitTwoThirds SplitThreeQuarters )
type Surface ¶
type Surface uint8
Surface is a complete visual decision: background, text, and border resolved together.