component

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package component defines the component model for GoFastr's core-ui framework.

A Component describes its visual appearance via the Render method, returning render.HTML. Components that handle user events implement the InteractiveComponent interface by adding an Actions method.

The package provides:

  • Component and InteractiveComponent interfaces
  • ComponentBase for embedding common fields (ID, Class)
  • ComponentContext for event data and state access
  • ActionRegistry and On() for declarative event handling
  • Lifecycle hooks (Mount, Update, Unmount)
  • ComponentList for rendering multiple components

Basic usage:

type Greeting struct {
    component.ComponentBase
    Name string
}

func (g *Greeting) Render() render.HTML {
    return render.Tag("p", nil, render.Text("Hello, "+g.Name))
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ComponentList

func ComponentList(components ...Component) render.HTML

ComponentList renders multiple components joined together.

func IsInteractive

func IsInteractive(c Component) bool

IsInteractive returns true if the component implements InteractiveComponent.

func RenderComponent

func RenderComponent(c Component) render.HTML

RenderComponent calls the Render method of any Component and returns its HTML. This is a convenience function for composing components.

func SafeRender

func SafeRender(c Component) (html render.HTML, err error)

SafeRender calls Render() with panic recovery. If the component panics, it returns a fallback error UI. Components implementing ErrorBoundary get a custom fallback; others get a generic red-bordered box.

func SafeRenderCtx

func SafeRenderCtx(ctx context.Context, c Component) (html render.HTML, err error)

SafeRenderCtx is the context-aware variant of SafeRender. If c implements ContextComponent its RenderCtx(ctx) is called; otherwise Render() is called. Panic recovery and ErrorBoundary handling are identical to SafeRender.

Types

type ActionDef

type ActionDef struct {
	Event    string                  // "click", "submit", "input", "change", "keydown", etc.
	Handler  func(*ComponentContext) // the server-side handler (runs in Go)
	Server   bool                    // if true, this action must run on the server
	Debounce int                     // debounce in milliseconds (0 = no debounce)

	// ClientJS is the JavaScript handler body. This is what gets compiled
	// into the actions.js bundle. It receives a `params` object with:
	//   params.value  — input value (for input/change events)
	//   params.*      — any data-param-* attributes from the trigger element
	//
	// Available runtime helpers via `G` (window.__gofastr):
	//   G.getState(key, default)   G.setState(key, value)
	//   G.updateText(sel, text)    G.updateHTML(sel, html)
	//   G.toast(msg)               G.navigate(path)
	//   G.addClass(sel, cls)       G.removeClass(sel, cls)
	//
	// Example: "G.setState('count', G.getState('count', 0) + 1); G.updateText('[data-count]', G.getState('count', 0));"
	ClientJS string
}

ActionDef defines a single event handler within a component.

func On

func On(event string, handler func(*ComponentContext), opts ...ActionOption) ActionDef

On registers an event handler into the current registry. This is the primary API for .ui.go files.

Usage: On("click", func(ctx *ComponentContext) { ... }, WithClientJS("G.setState('x', 1)"))

type ActionOption

type ActionOption func(*ActionDef)

ActionOption is a functional option for ActionDef.

func WithClientJS

func WithClientJS(js string) ActionOption

WithClientJS sets the client-side JavaScript handler body. This JS runs in the browser when the action is triggered.

type ActionRegistry

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

ActionRegistry holds all registered actions for a component.

func ExtractActions

func ExtractActions(c Component) *ActionRegistry

func NewActionRegistry

func NewActionRegistry() *ActionRegistry

NewActionRegistry creates a new action registry.

func (*ActionRegistry) All

func (r *ActionRegistry) All() []ActionDef

All returns all registered actions.

func (*ActionRegistry) Get

func (r *ActionRegistry) Get(eventName string) (ActionDef, bool)

Get retrieves the action for an event name.

func (*ActionRegistry) HasActions

func (r *ActionRegistry) HasActions() bool

HasActions returns true if any actions are registered.

func (*ActionRegistry) Register

func (r *ActionRegistry) Register(action ActionDef)

Register adds an action handler for an event.

type Component

type Component interface {
	Render() render.HTML
}

Component is the base interface for all UI components. A component describes its appearance via Render.

type ComponentBase

type ComponentBase struct {
	ID    string
	Class string
}

ComponentBase provides common fields for all components. Embed this in your component structs for convenience.

type ComponentContext

type ComponentContext struct {
	// Event data
	EventName string
	TargetID  string
	Params    map[string]string

	// State access
	StateGetter func(key string) any
	StateSetter func(key string, value any)
}

ComponentContext holds the execution context for a component action. It provides access to event data and component state.

func NewComponentContext

func NewComponentContext(eventName, targetID string, params map[string]string) *ComponentContext

NewComponentContext creates a new context with the given event data.

func (*ComponentContext) GetState

func (ctx *ComponentContext) GetState(key string) any

GetState retrieves state by key.

func (*ComponentContext) Param

func (ctx *ComponentContext) Param(name string) string

Param returns a named parameter from the event context.

func (*ComponentContext) ParamInt

func (ctx *ComponentContext) ParamInt(name string) (int, error)

ParamInt returns a named integer parameter from the event context.

func (*ComponentContext) SetState

func (ctx *ComponentContext) SetState(key string, value any)

SetState updates state by key.

type ContextComponent

type ContextComponent interface {
	RenderCtx(ctx context.Context) render.HTML
}

ContextComponent is the optional ctx-aware render interface. Implementations receive the request context and can branch on auth state, locale, or any other request-scoped value that isn't loaded into struct fields by Load(ctx).

The framework prefers RenderCtx over Render when both exist. ContextComponent intentionally does NOT embed Component — a type that only wants the ctx-aware shape can satisfy Component via the ContextOnly{} embed below, avoiding the `func (c) Render() HTML { return c.RenderCtx(context.Background()) }` boilerplate.

type ContextOnly

type ContextOnly struct{}

ContextOnly is a zero-byte embed helper for components that only want to implement RenderCtx. Embedding it provides a Render() satisfying the Component interface; that Render is never called when the type also implements RenderCtx (the framework dispatch prefers RenderCtx and skips Render in that case).

type Home struct {
    component.ContextOnly
    // ... your fields
}
func (h *Home) RenderCtx(ctx context.Context) render.HTML { ... }

No need to write a Render() stub on Home — ContextOnly provides one.

func (ContextOnly) Render

func (ContextOnly) Render() render.HTML

Render satisfies the Component interface. In practice it is never called: SafeRenderCtx and Screen.RenderCtx detect RenderCtx via a structural type check and route to it directly.

type ErrorBoundary

type ErrorBoundary interface {
	RenderError(err error) render.HTML
}

ErrorBoundary is implemented by components that provide a custom error fallback.

type InteractiveComponent

type InteractiveComponent interface {
	Component
	Actions()
}

InteractiveComponent extends Component with event handling. Components that implement this interface can respond to user events.

type Lifecycle

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

Lifecycle manages mount, update, and unmount hooks.

func NewLifecycle

func NewLifecycle() *Lifecycle

NewLifecycle creates a new lifecycle manager.

func (*Lifecycle) HasMountHooks

func (l *Lifecycle) HasMountHooks() bool

HasMountHooks returns true if any mount hooks are registered.

func (*Lifecycle) OnMount

func (l *Lifecycle) OnMount(fn LifecycleHook)

OnMount registers a hook to run when the component first renders.

func (*Lifecycle) OnUnmount

func (l *Lifecycle) OnUnmount(fn LifecycleHook)

OnUnmount registers a hook to run when the component is removed.

func (*Lifecycle) OnUpdate

func (l *Lifecycle) OnUpdate(fn LifecycleHook)

OnUpdate registers a hook to run when the component re-renders.

func (*Lifecycle) TriggerMount

func (l *Lifecycle) TriggerMount()

TriggerMount runs all mount hooks.

func (*Lifecycle) TriggerUnmount

func (l *Lifecycle) TriggerUnmount()

TriggerUnmount runs all unmount hooks.

func (*Lifecycle) TriggerUpdate

func (l *Lifecycle) TriggerUpdate()

TriggerUpdate runs all update hooks.

type LifecycleHook

type LifecycleHook func()

LifecycleHook is a function that runs at a specific point in a component's life.

type ServerCall

type ServerCall struct {
	Action string
	Params map[string]string
}

ServerCall represents a call that should be executed on the server.

func Server

func Server(action string, params ...string) *ServerCall

Server marks an action as requiring server-side execution. When the compiler sees this, it generates JS that POSTs to the server instead of running locally. The server handler runs in a goroutine.

type Widget

type Widget struct {
	ID        string          // unique widget ID (used for data-widget attribute)
	Component Component       // the component that renders this widget
	Actions   *ActionRegistry // extracted actions from the component
}

Widget is a self-contained interactive unit that serves as a hydration boundary. Widgets are hydrated incrementally on first user interaction. Components inside a Widget are compiled to JS for client-side execution.

func NewWidget

func NewWidget(id string, comp Component) *Widget

NewWidget creates a new widget wrapping a component. It automatically extracts actions if the component implements InteractiveComponent.

func (*Widget) IsInteractive

func (w *Widget) IsInteractive() bool

IsInteractive returns true if the widget's component has actions.

func (*Widget) Render

func (w *Widget) Render() render.HTML

Render renders the widget's component wrapped in a data-widget attribute. Output: <div data-widget="{id}" data-hydrate="lazy">{component.Render()}</div>

Jump to

Keyboard shortcuts

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