Skip to main content

core

Package core provides the widget and element framework interfaces and lifecycle.

This package defines the foundational types for building reactive user interfaces: Widget, Element, State, and BuildContext. It follows a declarative UI model where widgets describe what the UI should look like, and the framework efficiently updates the actual UI to match.

Core Types

Widget is an immutable description of part of the UI. Widgets are lightweight configuration objects that can be created frequently without performance concerns.

Element is the instantiation of a Widget at a particular location in the tree. Elements manage the lifecycle and identity of widgets.

Stateful Widgets

For widgets that need mutable state, embed StateBase in your state struct:

type myState struct {
core.StateBase
count int
}

func (s *myState) InitState() {
// Initialize state here
}

func (s *myState) Build(ctx core.BuildContext) core.Widget {
return widgets.Text{Content: fmt.Sprintf("Count: %d", s.count)}
}

State Management

ManagedState provides automatic rebuild triggering:

s.count = core.NewManagedState(&s.StateBase, 0)
s.count.Set(s.count.Get() + 1) // Automatically triggers rebuild

Observable provides thread-safe reactive values:

counter := core.NewObservable(0)
core.UseObservable(&s.StateBase, counter) // Subscribe to changes

Hooks

UseController, UseListenable, and UseObservable help manage resources and subscriptions with automatic cleanup on disposal.

Package core provides the core widget and element framework.

Variables

DebugMode controls whether debug information is displayed in error widgets. When true, error widgets show detailed error messages and stack traces. When false, error widgets show minimal information.

var DebugMode = true

func GlobalOffsetOf

func GlobalOffsetOf(element Element) rendering.Offset

GlobalOffsetOf returns the accumulated offset for an element in the render tree.

func SetDebugMode

func SetDebugMode(debug bool)

SetDebugMode enables or disables debug mode for the framework.

func SetErrorWidgetBuilder

func SetErrorWidgetBuilder(builder ErrorWidgetBuilder)

SetErrorWidgetBuilder configures the global error widget builder. Pass nil to restore the default builder.

func UseController

func UseController[C Disposable](base *StateBase, create func() C) C

UseController creates a controller and registers it for automatic disposal. The controller will be disposed when the state is disposed.

Example:

func (s *myState) InitState() {
s.animation = core.UseController(&s.StateBase, func() *animation.AnimationController {
return animation.NewAnimationController(300 * time.Millisecond)
})
}

func UseListenable

func UseListenable(base *StateBase, listenable Listenable)

UseListenable subscribes to a listenable and triggers rebuilds. The subscription is automatically cleaned up when the state is disposed.

Example:

func (s *myState) InitState() {
s.controller = core.UseController(&s.StateBase, func() *MyController {
return NewMyController()
})
core.UseListenable(&s.StateBase, s.controller)
}

func UseObservable

func UseObservable[T any](base *StateBase, obs *Observable[T])

UseObservable subscribes to an observable and triggers rebuilds when it changes. Call this once in InitState(), not in Build(). The subscription is automatically cleaned up when the state is disposed.

Example:

func (s *myState) InitState() {
s.counter = core.NewObservable(0)
core.UseObservable(&s.StateBase, s.counter)
}

func (s *myState) Build(ctx core.BuildContext) core.Widget {
// Use .Value() in Build to read the current value
return widgets.TextOf(fmt.Sprintf("Count: %d", s.counter.Value()), ...)
}

type BuildContext

BuildContext provides access to the element tree during build.

type BuildContext interface {
Widget() Widget
FindAncestor(predicate func(Element) bool) Element
// DependOnInherited finds and depends on an ancestor InheritedWidget of the given type.
// The aspect parameter enables granular dependency tracking: when non-nil, only changes
// affecting that aspect will trigger rebuilds. Pass nil to depend on all changes.
DependOnInherited(inheritedType reflect.Type, aspect any) any
// DependOnInheritedWithAspects is like DependOnInherited but registers multiple aspects
// in a single tree walk. More efficient when depending on multiple aspects.
DependOnInheritedWithAspects(inheritedType reflect.Type, aspects ...any) any
}

type BuildOwner

BuildOwner tracks dirty elements that need rebuilding.

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

func NewBuildOwner

func NewBuildOwner() *BuildOwner

NewBuildOwner creates a new BuildOwner.

func (*BuildOwner) FlushBuild

func (b *BuildOwner) FlushBuild()

FlushBuild rebuilds all dirty elements in depth order.

func (*BuildOwner) NeedsWork

func (b *BuildOwner) NeedsWork() bool

NeedsWork returns true if there are dirty elements or pending layout/paint.

func (*BuildOwner) Pipeline

func (b *BuildOwner) Pipeline() *layout.PipelineOwner

Pipeline returns the PipelineOwner for render object scheduling.

func (*BuildOwner) ScheduleBuild

func (b *BuildOwner) ScheduleBuild(element Element)

ScheduleBuild marks an element as needing rebuild.

type ControllerBase

ControllerBase provides common functionality for controllers. Embed this struct in your controllers to get listener management for free.

Example:

type MyController struct {
core.ControllerBase
value int
}

func (c *MyController) SetValue(v int) {
c.value = v
c.NotifyListeners()
}
type ControllerBase struct {
// contains filtered or unexported fields
}

func (*ControllerBase) AddListener

func (c *ControllerBase) AddListener(fn func()) func()

AddListener adds a callback that fires when NotifyListeners() is called. Returns an unsubscribe function.

func (*ControllerBase) Dispose

func (c *ControllerBase) Dispose()

Dispose clears all listeners and marks the controller as disposed. Override this method if you need custom cleanup, but always call c.ControllerBase.Dispose() in your override.

func (*ControllerBase) IsDisposed

func (c *ControllerBase) IsDisposed() bool

IsDisposed returns true if this controller has been disposed.

func (*ControllerBase) ListenerCount

func (c *ControllerBase) ListenerCount() int

ListenerCount returns the number of registered listeners.

func (*ControllerBase) NotifyListeners

func (c *ControllerBase) NotifyListeners()

NotifyListeners calls all registered listeners. Safe to call after disposal (becomes a no-op).

type Disposable

Disposable is an interface for types that need cleanup.

type Disposable interface {
Dispose()
}

type Element

Element is the instantiation of a Widget at a particular location in the tree.

type Element interface {
Widget() Widget
Mount(parent Element, slot any)
Update(newWidget Widget)
Unmount()
MarkNeedsBuild()
RebuildIfNeeded()
VisitChildren(visitor func(Element) bool)
Depth() int
Slot() any
UpdateSlot(newSlot any)
}

func MountRoot

func MountRoot(root Widget, owner *BuildOwner) Element

MountRoot inflates and mounts the root widget with the provided build owner.

type ErrorBoundaryCapture

ErrorBoundaryCapture is implemented by error boundary elements to capture build errors from descendant widgets.

type ErrorBoundaryCapture interface {
// CaptureError captures a build error from a descendant widget.
// Returns true if the error was captured and handled.
CaptureError(err *errors.BuildError) bool
}

type ErrorWidgetBuilder

ErrorWidgetBuilder creates a fallback widget when a widget build fails. The builder receives the build error and should return a widget to display in place of the failed widget.

type ErrorWidgetBuilder func(err *errors.BuildError) Widget

func GetErrorWidgetBuilder

func GetErrorWidgetBuilder() ErrorWidgetBuilder

GetErrorWidgetBuilder returns the current error widget builder.

type IndexedSlot

IndexedSlot represents a child's position in a multi-child parent.

type IndexedSlot struct {
Index int
PreviousSibling Element
}

type InheritedElement

InheritedElement hosts an InheritedWidget and tracks dependents.

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

func NewInheritedElement

func NewInheritedElement(widget InheritedWidget, owner *BuildOwner) *InheritedElement

NewInheritedElement creates an InheritedElement for the given widget.

func (*InheritedElement) AddDependent

func (e *InheritedElement) AddDependent(dependent Element, aspect any)

AddDependent registers an element as depending on this inherited widget. If aspect is non-nil, it's added to the dependent's aspect set for granular tracking. If aspect is nil, a sentinel is added indicating the widget depends on all changes.

Note: Aspect sets only grow during an element's lifetime. If a widget changes which aspects it depends on across rebuilds, old aspects remain registered. This may cause extra rebuilds but is safe (over-notification, not under-notification).

func (*InheritedElement) DependOnInherited

func (e *InheritedElement) DependOnInherited(inheritedType reflect.Type, aspect any) any

func (*InheritedElement) DependOnInheritedWithAspects

func (e *InheritedElement) DependOnInheritedWithAspects(inheritedType reflect.Type, aspects ...any) any

func (*InheritedElement) FindAncestor

func (e *InheritedElement) FindAncestor(predicate func(Element) bool) Element

func (*InheritedElement) Mount

func (e *InheritedElement) Mount(parent Element, slot any)

func (*InheritedElement) MountWithSelf

func (e *InheritedElement) MountWithSelf(parent Element, slot any, self Element)

MountWithSelf allows a wrapper element to specify itself as the parent for children.

func (*InheritedElement) RebuildIfNeeded

func (e *InheritedElement) RebuildIfNeeded()

func (*InheritedElement) RebuildIfNeededWithSelf

func (e *InheritedElement) RebuildIfNeededWithSelf(self Element)

RebuildIfNeededWithSelf allows a wrapper element to specify itself as the parent.

func (*InheritedElement) RemoveDependent

func (e *InheritedElement) RemoveDependent(dependent Element)

RemoveDependent unregisters an element as depending on this inherited widget.

func (*InheritedElement) RenderObject

func (e *InheritedElement) RenderObject() layout.RenderObject

RenderObject returns the render object from the child element.

func (*InheritedElement) Unmount

func (e *InheritedElement) Unmount()

func (*InheritedElement) Update

func (e *InheritedElement) Update(newWidget Widget)

func (*InheritedElement) VisitChildren

func (e *InheritedElement) VisitChildren(visitor func(Element) bool)

type InheritedWidget

InheritedWidget provides data to descendants without explicit passing. Widgets can depend on an InheritedWidget via BuildContext.DependOnInherited.

type InheritedWidget interface {
Widget
// Child returns the child widget.
Child() Widget
// UpdateShouldNotify returns true if dependents should rebuild
// when this widget is updated.
UpdateShouldNotify(oldWidget InheritedWidget) bool
// UpdateShouldNotifyDependent returns true if a specific dependent should rebuild
// based on the aspects it registered. This enables granular rebuild optimization
// where dependents only rebuild when their specific aspects change.
UpdateShouldNotifyDependent(oldWidget InheritedWidget, aspects map[any]struct{}) bool
}

type Listenable

Listenable is an interface for types that can be listened to. AddListener should return an unsubscribe function.

type Listenable interface {
AddListener(listener func()) func()
}

type ManagedState

ManagedState holds a value and triggers rebuilds when it changes. Unlike Observable, it is tied to a specific StateBase.

ManagedState is NOT thread-safe. It must only be accessed from the UI thread. To update from a background goroutine, use drift.Dispatch:

go func() {
result := doExpensiveWork()
drift.Dispatch(func() {
s.data.Set(result) // Safe - runs on UI thread
})
}()

Example:

type myState struct {
core.StateBase
count *core.ManagedState[int]
}

func (s *myState) InitState() {
s.count = core.NewManagedState(&s.StateBase, 0)
}

func (s *myState) Build(ctx core.BuildContext) core.Widget {
return widgets.GestureDetector{
OnTap: func() { s.count.Set(s.count.Get() + 1) },
Child: widgets.TextOf(fmt.Sprintf("Count: %d", s.count.Get()), ...),
}
}
type ManagedState[T any] struct {
// contains filtered or unexported fields
}

Example:

This example shows how to use ManagedState for automatic rebuilds. ManagedState wraps a value and triggers rebuilds when it changes.

package main

import (
"fmt"

"github.com/go-drift/drift/pkg/core"
)

func main() {
// In a stateful widget's InitState:
//
// func (s *myState) InitState() {
// s.count = core.NewManagedState(&s.StateBase, 0)
// }
//
// In Build:
//
// func (s *myState) Build(ctx core.BuildContext) core.Widget {
// return widgets.GestureDetector{
// OnTap: func() {
// // Set automatically triggers a rebuild
// s.count.Set(s.count.Get() + 1)
// },
// ChildWidget: widgets.Text{
// Content: fmt.Sprintf("Count: %d", s.count.Get()),
// },
// }
// }

// Direct usage for demonstration:
base := &core.StateBase{}
count := core.NewManagedState(base, 0)

// Get the current value
fmt.Printf("Initial: %d\n", count.Get())

// Update using transform function
count.Update(func(v int) int { return v + 10 })
fmt.Printf("After update: %d\n", count.Value())

}

Output

Initial: 0
After update: 10

func NewManagedState

func NewManagedState[T any](base *StateBase, initial T) *ManagedState[T]

NewManagedState creates a new managed state value. Changes to this value will automatically trigger a rebuild.

func (*ManagedState[T]) Get

func (m *ManagedState[T]) Get() T

Get returns the current value.

func (*ManagedState[T]) Set

func (m *ManagedState[T]) Set(value T)

Set updates the value and triggers a rebuild.

func (*ManagedState[T]) Update

func (m *ManagedState[T]) Update(transform func(T) T)

Update applies a transformation to the current value and triggers a rebuild.

func (*ManagedState[T]) Value

func (m *ManagedState[T]) Value() T

Value returns the current value. Alias for Get().

type Notifier

Notifier triggers callbacks when Notify() is called. Unlike Observable, it doesn't hold a value. It is safe for concurrent use.

Notifier implements the Listenable interface, so it can be used with UseListenable.

Example:

refresh := core.NewNotifier()
unsub := refresh.AddListener(func() {
fmt.Println("Refresh triggered!")
})
refresh.Notify() // prints: Refresh triggered!
unsub() // stop listening
type Notifier struct {
// contains filtered or unexported fields
}

Example:

This example shows the Notifier type for event broadcasting. Unlike Observable, Notifier doesn't hold a value.

package main

import (
"fmt"

"github.com/go-drift/drift/pkg/core"
)

func main() {
refresh := core.NewNotifier()

// Add a listener
unsub := refresh.AddListener(func() {
fmt.Println("Refresh triggered!")
})

// Trigger the notification
refresh.Notify()

// Clean up
unsub()

}

Output

Refresh triggered!

func NewNotifier

func NewNotifier() *Notifier

NewNotifier creates a new notifier.

func (*Notifier) AddListener

func (n *Notifier) AddListener(fn func()) func()

AddListener adds a callback that fires when Notify() is called. Returns an unsubscribe function.

func (*Notifier) ListenerCount

func (n *Notifier) ListenerCount() int

ListenerCount returns the number of registered listeners.

func (*Notifier) Notify

func (n *Notifier) Notify()

Notify triggers all registered listeners.

type Observable

Observable holds a value and notifies listeners when it changes. It is safe for concurrent use.

Example:

count := core.NewObservable(0)
unsub := count.AddListener(func(value int) {
fmt.Println("Count changed to:", value)
})
count.Set(5) // prints: Count changed to: 5
unsub() // stop listening
type Observable[T any] struct {
// contains filtered or unexported fields
}

Example:

This example shows how to create an Observable for reactive state. Observable is thread-safe and can be shared across goroutines.

package main

import (
"fmt"

"github.com/go-drift/drift/pkg/core"
)

func main() {
// Create an observable with an initial value
counter := core.NewObservable(0)

// Add a listener that fires when the value changes
unsub := counter.AddListener(func(value int) {
fmt.Printf("Counter changed to: %d\n", value)
})

// Update the value - this triggers all listeners
counter.Set(5)

// Read the current value
current := counter.Value()
fmt.Printf("Current value: %d\n", current)

// Clean up when done
unsub()

}

Output

Counter changed to: 5
Current value: 5

func NewObservable

func NewObservable[T any](initial T) *Observable[T]

NewObservable creates a new observable with the given initial value.

func NewObservableWithEquality

func NewObservableWithEquality[T any](initial T, equalityFunc func(a, b T) bool) *Observable[T]

NewObservableWithEquality creates a new observable with a custom equality function. The equality function is used to determine if the value has changed.

Example:

This example shows how to use Observable with a custom equality function. This is useful when you want to avoid unnecessary updates.

package main

import (
"fmt"

"github.com/go-drift/drift/pkg/core"
)

func main() {
type User struct {
ID int
Name string
}

// Only notify listeners when the user ID changes
user := core.NewObservableWithEquality(User{ID: 1, Name: "Alice"}, func(a, b User) bool {
return a.ID == b.ID
})

user.AddListener(func(u User) {
fmt.Printf("User changed: %s\n", u.Name)
})

// This won't trigger listeners because ID is the same
user.Set(User{ID: 1, Name: "Alice Updated"})

// This will trigger listeners because ID changed
user.Set(User{ID: 2, Name: "Bob"})

}

Output

User changed: Bob

func (*Observable[T]) AddListener

func (o *Observable[T]) AddListener(fn func(T)) func()

AddListener adds a callback that fires whenever the value changes. Returns an unsubscribe function.

func (*Observable[T]) ListenerCount

func (o *Observable[T]) ListenerCount() int

ListenerCount returns the number of registered listeners.

func (*Observable[T]) Set

func (o *Observable[T]) Set(value T)

Set updates the value and notifies all listeners if the value changed. If a custom equality function was provided, it is used to determine if the value changed.

func (*Observable[T]) Update

func (o *Observable[T]) Update(transform func(T) T)

Update applies a transformation to the current value. This is useful for complex updates that depend on the current value.

func (*Observable[T]) Value

func (o *Observable[T]) Value() T

Value returns the current value.

type RenderObjectElement

RenderObjectElement hosts a RenderObject and optional children.

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

func NewRenderObjectElement

func NewRenderObjectElement(widget RenderObjectWidget, owner *BuildOwner) *RenderObjectElement

func (*RenderObjectElement) DependOnInherited

func (e *RenderObjectElement) DependOnInherited(inheritedType reflect.Type, aspect any) any

func (*RenderObjectElement) DependOnInheritedWithAspects

func (e *RenderObjectElement) DependOnInheritedWithAspects(inheritedType reflect.Type, aspects ...any) any

func (*RenderObjectElement) FindAncestor

func (e *RenderObjectElement) FindAncestor(predicate func(Element) bool) Element

func (*RenderObjectElement) Mount

func (e *RenderObjectElement) Mount(parent Element, slot any)

func (*RenderObjectElement) RebuildIfNeeded

func (e *RenderObjectElement) RebuildIfNeeded()

func (*RenderObjectElement) RenderObject

func (e *RenderObjectElement) RenderObject() layout.RenderObject

RenderObject exposes the backing render object for the element.

func (*RenderObjectElement) Unmount

func (e *RenderObjectElement) Unmount()

func (*RenderObjectElement) Update

func (e *RenderObjectElement) Update(newWidget Widget)

func (*RenderObjectElement) UpdateSlot

func (e *RenderObjectElement) UpdateSlot(newSlot any)

UpdateSlot updates the slot and notifies the render parent of the move.

func (*RenderObjectElement) VisitChildren

func (e *RenderObjectElement) VisitChildren(visitor func(Element) bool)

type RenderObjectWidget

RenderObjectWidget creates a render object directly.

type RenderObjectWidget interface {
Widget
CreateRenderObject(ctx BuildContext) layout.RenderObject
UpdateRenderObject(ctx BuildContext, renderObject layout.RenderObject)
}

type ScrollOffsetProvider

ScrollOffsetProvider reports a paint-time scroll offset for descendants.

type ScrollOffsetProvider interface {
ScrollOffset() rendering.Offset
}

type State

State holds mutable state for a StatefulWidget.

type State interface {
InitState()
Build(ctx BuildContext) Widget
SetState(fn func())
Dispose()
DidChangeDependencies()
DidUpdateWidget(oldWidget StatefulWidget)
}

type StateBase

StateBase provides common functionality for stateful widget states. Embed this struct in your state to eliminate boilerplate.

Example:

type myState struct {
core.StateBase
count int
}

func (s *myState) InitState() {
// No need to implement SetElement, SetState, Dispose, etc.
}
type StateBase struct {
// contains filtered or unexported fields
}

Example:

This example shows the StateBase type for stateful widgets. Embed StateBase in your state struct to get automatic lifecycle management.

package main

import (
"github.com/go-drift/drift/pkg/core"
)

func main() {
// In a real stateful widget, you would define:
//
// type counterState struct {
// core.StateBase
// count int
// }
//
// func (s *counterState) InitState() {
// s.count = 0
// }
//
// func (s *counterState) Build(ctx core.BuildContext) core.Widget {
// return widgets.GestureDetector{
// OnTap: func() {
// s.SetState(func() {
// s.count++
// })
// },
// ChildWidget: widgets.Text{
// Content: fmt.Sprintf("Count: %d", s.count),
// },
// }
// }

// StateBase provides SetState, OnDispose, and IsDisposed methods
state := &core.StateBase{}
_ = state
}

func (*StateBase) Build

func (s *StateBase) Build(ctx BuildContext) Widget

Build is a no-op default implementation that returns nil. Override this method to build your widget tree.

func (*StateBase) DidChangeDependencies

func (s *StateBase) DidChangeDependencies()

DidChangeDependencies is a no-op default implementation. Override this method to respond to inherited widget changes.

func (*StateBase) DidUpdateWidget

func (s *StateBase) DidUpdateWidget(oldWidget StatefulWidget)

DidUpdateWidget is a no-op default implementation. Override this method to respond to widget configuration changes.

func (*StateBase) Dispose

func (s *StateBase) Dispose()

Dispose cleans up resources. Override this method if you need custom cleanup, but always call s.RunDisposers() or s.StateBase.Dispose() in your override.

func (*StateBase) Element

func (s *StateBase) Element() *StatefulElement

Element returns the element associated with this state. Returns nil if the state has been disposed or not yet mounted.

func (*StateBase) InitState

func (s *StateBase) InitState()

InitState is a no-op default implementation. Override this method to initialize your state.

func (*StateBase) IsDisposed

func (s *StateBase) IsDisposed() bool

IsDisposed returns true if this state has been disposed.

func (*StateBase) OnDispose

func (s *StateBase) OnDispose(cleanup func()) func()

OnDispose registers a cleanup function to be called when the state is disposed. Returns an unregister function that can be called to remove the disposer. The cleanup function will only be called once.

func (*StateBase) RunDisposers

func (s *StateBase) RunDisposers()

RunDisposers executes all registered disposers in reverse order. This is called automatically by Dispose().

func (*StateBase) SetElement

func (s *StateBase) SetElement(element *StatefulElement)

SetElement stores the element reference for triggering rebuilds. This method is called automatically by the framework.

func (*StateBase) SetState

func (s *StateBase) SetState(fn func())

SetState executes the given function and schedules a rebuild. Safe to call even after disposal (becomes a no-op).

SetState is NOT thread-safe. It must only be called from the UI thread. To update state from a background goroutine, use drift.Dispatch.

type StatefulBuilder

StatefulBuilder provides a declarative way to create stateful widgets with full lifecycle support.

Example:

core.StatefulBuilder[int]{
Init: func() int { return 0 },
Build: func(count int, ctx core.BuildContext, setState func(func(int) int)) core.Widget {
return widgets.GestureDetector{
OnTap: func() { setState(func(c int) int { return c + 1 }) },
Child: widgets.TextOf(fmt.Sprintf("Count: %d", count), ...),
}
},
Dispose: func(count int) {
// cleanup resources
},
}.Widget()
type StatefulBuilder[S any] struct {
// Init creates the initial state value. Required.
Init func() S

// Build creates the widget tree. Required.
// The setState function updates the state and triggers a rebuild.
Build func(state S, ctx BuildContext, setState func(func(S) S)) Widget

// Dispose is called when the widget is removed from the tree. Optional.
Dispose func(state S)

// DidChangeDependencies is called when inherited widgets change. Optional.
DidChangeDependencies func(state S, ctx BuildContext)

// DidUpdateWidget is called when the widget configuration changes. Optional.
DidUpdateWidget func(state S, oldWidget StatefulWidget)

// WidgetKey is an optional key for the widget.
WidgetKey any
}

func (StatefulBuilder[S]) Widget

func (b StatefulBuilder[S]) Widget() Widget

Widget returns a Widget that can be used in the widget tree.

type StatefulElement

StatefulElement hosts a StatefulWidget and its State.

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

func NewStatefulElement

func NewStatefulElement(widget StatefulWidget, owner *BuildOwner) *StatefulElement

func (*StatefulElement) DependOnInherited

func (e *StatefulElement) DependOnInherited(inheritedType reflect.Type, aspect any) any

func (*StatefulElement) DependOnInheritedWithAspects

func (e *StatefulElement) DependOnInheritedWithAspects(inheritedType reflect.Type, aspects ...any) any

func (*StatefulElement) FindAncestor

func (e *StatefulElement) FindAncestor(predicate func(Element) bool) Element

func (*StatefulElement) Mount

func (e *StatefulElement) Mount(parent Element, slot any)

func (*StatefulElement) RebuildIfNeeded

func (e *StatefulElement) RebuildIfNeeded()

func (*StatefulElement) RenderObject

func (e *StatefulElement) RenderObject() layout.RenderObject

RenderObject returns the render object from the first render-object child.

func (*StatefulElement) Unmount

func (e *StatefulElement) Unmount()

func (*StatefulElement) Update

func (e *StatefulElement) Update(newWidget Widget)

func (*StatefulElement) VisitChildren

func (e *StatefulElement) VisitChildren(visitor func(Element) bool)

type StatefulWidget

StatefulWidget has mutable state that can change over time.

type StatefulWidget interface {
Widget
CreateState() State
}

type StatelessElement

StatelessElement hosts a StatelessWidget.

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

func NewStatelessElement

func NewStatelessElement(widget StatelessWidget, owner *BuildOwner) *StatelessElement

func (*StatelessElement) DependOnInherited

func (e *StatelessElement) DependOnInherited(inheritedType reflect.Type, aspect any) any

func (*StatelessElement) DependOnInheritedWithAspects

func (e *StatelessElement) DependOnInheritedWithAspects(inheritedType reflect.Type, aspects ...any) any

func (*StatelessElement) FindAncestor

func (e *StatelessElement) FindAncestor(predicate func(Element) bool) Element

func (*StatelessElement) Mount

func (e *StatelessElement) Mount(parent Element, slot any)

func (*StatelessElement) RebuildIfNeeded

func (e *StatelessElement) RebuildIfNeeded()

func (*StatelessElement) RenderObject

func (e *StatelessElement) RenderObject() layout.RenderObject

RenderObject returns the render object from the first render-object child.

func (*StatelessElement) Unmount

func (e *StatelessElement) Unmount()

func (*StatelessElement) Update

func (e *StatelessElement) Update(newWidget Widget)

func (*StatelessElement) VisitChildren

func (e *StatelessElement) VisitChildren(visitor func(Element) bool)

type StatelessWidget

StatelessWidget builds UI without mutable state.

type StatelessWidget interface {
Widget
Build(ctx BuildContext) Widget
}

type Widget

Widget is an immutable description of part of the UI.

type Widget interface {
CreateElement() Element
Key() any
}

func DefaultErrorWidgetBuilder

func DefaultErrorWidgetBuilder(err *errors.BuildError) Widget

DefaultErrorWidgetBuilder returns a placeholder widget when build fails. The actual error widget implementation is in pkg/widgets to avoid circular dependencies. This default returns nil, which signals the framework to use the widgets.ErrorWidget if available.

func Stateful

func Stateful[S any](init func() S, build func(state S, setState func(func(S) S)) Widget) Widget

Stateful creates a stateful widget using generics. For more control over lifecycle callbacks, use StatefulBuilder instead.

Generated by gomarkdoc