component

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: May 2, 2022 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package component features a framework, inspired by React and Redux, that allows you to extend the basic ui package with custom Components on top of plain ui Elements.

Index

Constants

This section is empty.

Variables

View Source
var Element = Define(func(props Properties) Instance {
	element := UseState(func() *ui.Element {
		return uiCtx.CreateElement()
	}).Get()

	Defer(func() {
		element.Destroy()
	})

	data := GetData[ElementData](props)

	element.SetEssence(data.Essence)
	if data.Enabled.Specified {
		element.SetEnabled(data.Enabled.Value)
	}
	if data.Visible.Specified {
		element.SetVisible(data.Visible.Value)
	}
	if data.Focusable.Specified {
		element.SetFocusable(data.Focusable.Value)
	}
	if data.IdealSize.Specified {
		element.SetIdealSize(data.IdealSize.Value)
	}
	element.SetLayout(data.Layout)
	element.SetPadding(data.Padding)
	element.SetLayoutConfig(props.LayoutData())

	return Instance{
		element:  element,
		children: props.Children(),
	}
})

Element represents the most basic component, which is translated to a UI Element. All higher-order components eventually boil down to an Element.

View Source
var StoreProvider = Define(func(props Properties) Instance {
	data := GetData[StoreProviderData](props)

	stores := UseState(func() []*Store {
		result := make([]*Store, len(data.Entries))
		for i, entry := range data.Entries {
			result[i] = CreateStore(entry.Reducer, entry.InitialValue)
		}
		return result
	}).Get()

	Defer(func() {
		for _, store := range stores {
			store.Destroy()
		}
	})

	return New(Element, func() {
		WithData(ElementData{
			Layout: ui.NewFillLayout(),
		})
		WithChildren(props.children)
	})
})

StoreProvider is a convenience component that manages the lifecycle of a set of Stores.

Using StoreProvider can be used as an optimization, since the lifecycle of the Stores is determined by the lifecycle of the given StoreProvider. If certain Store should be available only in the context of a given component hierarchy (e.g. a wizard dialog) it might make sense to wrap that hierarchy with such a StoreProvider.

Should you go down this route, however, make sure that only nested components try to access Stores that are managed by this StoreProvider.

Functions

func After

func After(duration time.Duration, fn func())

After will schedule a closure function to be run after the specified amount of time. The closure is guaranteed to run on the UI thread and the framework ensures that the closure will not be called if the component had been destroyed in the meantime.

Normally, you would use this function within a Once block or as a result of a callback. Not doing so would cause the closure function to be scheduled on every rendering of the component. As the framework is free to render a component at any time it deems necessary, it is unlikely that a user would like to have a function scheduled in an undeterministic way.

func CreateImage added in v0.3.0

func CreateImage(img image.Image) *ui.Image

CreateImage delegates to the UI window context to create the specified image.

func Defer

func Defer(fn func())

Defer can be used to perform a cleanup action. The framework will issue one final render of a component before it gets destroyed. During that final render all closure functions specified via the Defer function will be invoked in the respective order.

Similar to Once, Defer can be used multiple times within a component's render function.

func Dispatch

func Dispatch(action interface{})

Dispatch is the mechanism through which Stores get modified. An action is provided and all Reducers attempt to process the action. Should a reducer change it's Store's value then all connected components are reconciled.

func GetCallbackData added in v0.5.0

func GetCallbackData[T any](props Properties) T

GetCallbackData returns the callback data stored in Properties as the specified type.

func GetContext added in v0.5.0

func GetContext[T any]() T

GetContext retrieves the appropriate context based on the generic type param and returns it.

func GetData added in v0.5.0

func GetData[T any](props Properties) T

GetData returns the data stored in Properties as the specified type.

func GetFont

func GetFont(family, style string) *ui.Font

GetFont retrieves the font with the specified family and style.

Keep in mind that the necessary fonts should have been loaded via OpenFontCollection beforehand, otherwise this method will panic if it is unable to find the requested font.

func GetLayoutData added in v0.5.0

func GetLayoutData[T any](props Properties) T

GetLayoutData returns the layout data stored in Properties as the specified type.

func GetOptionalCallbackData added in v0.5.0

func GetOptionalCallbackData[T any](props Properties, defaultValue T) T

GetOptionalCallbackData returns the callback data stored in Properties as the specified type, unless there is no callback data, in which case the defaultValue is returned.

func GetOptionalData added in v0.5.0

func GetOptionalData[T any](props Properties, defaultValue T) T

GetOptionalData returns the data stored in Properties as the specified type, unless there is no data, in which case the defaultValue is returned.

func GetOptionalLayoutData added in v0.5.0

func GetOptionalLayoutData[T any](props Properties, defaultValue T) T

GetOptionalLayoutData returns the layout data stored in Properties as the specified type, unless there is no layout data, in which case the defaultValue is returned.

func Initialize

func Initialize(window *ui.Window, instance Instance)

Initialize wires the framework to the specified ui Window. The specified instance will be the root component used.

func InjectContext

func InjectContext(target any)

InjectContext retrieves the appropriate context and assigns it to target.

The specified target must be a pointer to the type that was used in RegisterContext.

func InjectStore

func InjectStore(target interface{})

InjectStore is a helper function that allows one to discover and access and arbitrary Store's value.

The function uses the type of the referenced value by the target pointer to determine which Store should be used.

func IsEqualData added in v0.3.0

func IsEqualData(old, new interface{}) bool

IsEqualData compares if the two data objects are equal

func Once

func Once(fn func())

Once can be used to perform an initialization action in a component's render function. During subsequent renders for the same component instance, the specified closure function will not be called.

You can use Once multiple times within a component's render function and all closure functions will be called in the respective order.

func OpenFontCollection

func OpenFontCollection(uri string)

OpenFontCollection delegates to the UI window context to open the specified font collection.

func OpenImage

func OpenImage(uri string) *ui.Image

OpenImage delegates to the UI window context to open the specified image.

func RegisterContext

func RegisterContext(value any)

RegisterContext registers a data structure that will be accessible from all components.

If used, this method should be called during bootstrapping and should not be called from within components.

The context is stored according to its type and there can only be one call per struct type. Once a context is set it is persisted for the whole lifecycle of the framework.

Contexts should be used only for global configurations that will not change, like graphics handles or i18n functions.

func Schedule

func Schedule(fn func())

Schedule will schedule a closure function to run as soon as possible on the UI thread.

Normally this would be used when a certain processing is being performed on a separate go routine and the result needs to be passed back to the UI thread.

The framework ensures that the closure will not be called if the component had been destroyed in the meantime.

func UseLifecycle added in v0.3.0

func UseLifecycle[T Lifecycle](constructor func(handle LifecycleHandle) T) T

UseLifecycle attaches a Lifecycle to the given Component instance in which this hook is used.

func Window

func Window() *ui.Window

Window returns the underlying ui Window object.

func WithCallbackData

func WithCallbackData(callbackData interface{})

WithCallbackData specifies the callback data to be passed to the component during instantiation.

Callback data is a mechanism for one component to listen for events on instanced components.

As callback data is expected to be a struct of function fields, they are not comparable in Go and as such cannot follow the lifecycle of data or layout data.

func WithChild

func WithChild(key string, instance Instance)

WithChild adds a child to the given component. The child is appended to all previously registered children via the same method.

The key property is important. If in a subsequent render a component's child changes key or component type, the old one will be destroyed and a new one will be created. As such, to maintain a more optimized rendering and to prevent state loss, children should have a key assigned to them.

func WithChildren

func WithChildren(children []Instance)

WithChildren sets the children for the given component. Keep in mind that any former children assigned via WithChild are replaced.

func WithContext

func WithContext(context interface{})

WithContext can be used during the instantiation of an Application in order to configure a context object.

This is a helper function in place of RegisterContext. While currently not enforced, you should use this function during the instantiation of your root component. Using it at a later point during the lifecycle of your application could indicate an improper usage of contexts. You may consider using reducers and global state instead.

func WithData

func WithData(data interface{})

WithData specifies the data to be passed to the component during instantiation.

Your data should be comparable in order to enable optimizations done by the framework. If you'd like to pass functions, in case of callbacks, they can be passed through callback data.

func WithLayoutData

func WithLayoutData(layoutData interface{})

WithLayoutData specifies the layout data to be passed to the component during instantiation.

LayoutData is kept separate by the framework as it is expected to have a different lifecycle (changes might be rare) and as such can be optimized.

Your layout data should be comparable in order to enable optimizations done by the framework.

Types

type BaseController added in v0.3.0

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

func (*BaseController) Alter added in v0.3.0

func (c *BaseController) Alter(fn func() error) error

func (*BaseController) NotifyChanged added in v0.3.0

func (c *BaseController) NotifyChanged()

func (*BaseController) Subscribe added in v0.3.0

type BaseLifecycle added in v0.3.0

type BaseLifecycle struct{}

BaseLifecycle is an implementation of Lifecycle that does nothing.

func NewBaseLifecycle added in v0.3.0

func NewBaseLifecycle() *BaseLifecycle

NewBaseLifecycle returns a new BaseLifecycle.

func (*BaseLifecycle) OnCreate added in v0.3.0

func (l *BaseLifecycle) OnCreate(props Properties)

func (*BaseLifecycle) OnDestroy added in v0.3.0

func (l *BaseLifecycle) OnDestroy()

func (*BaseLifecycle) OnUpdate added in v0.3.0

func (l *BaseLifecycle) OnUpdate(props Properties)

type CallbackMapFunc

type CallbackMapFunc func(props Properties) interface{}

CallbackMapFunc controls how a connected component's data is calculated.

type Component

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

Component represents a definition for a component.

func Connect

func Connect(delegate Component, mapping ConnectMapping) Component

Connect is the mechanism through which a Component gets wired to the global Stores. A connected component will get invalidated when one of the Stores gets changed.

The Connect method is used to wrap an existing Component and the mapping configuration can be used to adjust the delegate component's data and callback data based on the Store state.

func Controlled added in v0.3.0

func Controlled(delegate Component) Component

func Define

func Define(fn ComponentFunc) Component

Define can be used to describe a new component. The provided component function (or render function) will be called by the framework to initialize, reconcicle, or destroy a component instance.

func ShallowCached

func ShallowCached(delegate Component) Component

ShallowCached can be used to wrap a component and optimize reconciliation by avoiding the rerendering of the component if the data and layout data are equal to their previous values when shallowly (==) compared.

type ComponentFunc

type ComponentFunc func(props Properties) Instance

ComponentFunc holds the logic and layouting of the component.

type ConnectMapping

type ConnectMapping struct {

	// Data, if specified, controls the data to be passed to the
	// delegate component. If nil, then the original data is passed through.
	Data DataMapFunc

	// Callback, if specified, controls the callback data to be passed to the
	// delegate component. If nil, then the original callback data is passed
	// through.
	Callback CallbackMapFunc
}

ConnectMapping is a configuration mechanism to wire a connected component to its delegate.

type Controller added in v0.3.0

type Controller interface {
	Subscribe(callback ControllerCallback) ControllerSubscription
	Alter(func() error) error
	NotifyChanged()
}

func NewBaseController added in v0.3.0

func NewBaseController() Controller

type ControllerCallback added in v0.3.0

type ControllerCallback func(controller Controller)

type ControllerSubscription added in v0.3.0

type ControllerSubscription interface {
	Unsubscribe()
}

type DataMapFunc

type DataMapFunc func(props Properties) interface{}

DataMapFunc controls how a connected component's data is calculated.

type ElementData

type ElementData struct {
	Essence   ui.Essence
	Enabled   optional.V[bool]
	Visible   optional.V[bool]
	Focusable optional.V[bool]
	IdealSize optional.V[ui.Size]
	Padding   ui.Spacing
	Layout    ui.Layout
}

ElementData is the struct that should be used when configuring an Element component's data.

type Instance

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

Instance represents the instantiation of a given Component.

func New

func New(component Component, setupFn func()) Instance

New instantiates the specified component. The setup function is used to apply configurations to the component in a user-friendly manner.

Note: creating an instance with New does not necessarily mean that a component will be freshly instantiated. If this occurs during rendering the framework will reuse former instances when possible.

func (Instance) Key added in v0.3.0

func (i Instance) Key() string

Key returns the child key that is registered for this Instance in case the Instance was created as part of a WithChild directive.

type Lifecycle added in v0.3.0

type Lifecycle interface {

	// OnCreate is called when the Component instance is first created.
	OnCreate(props Properties)

	// OnUpdate is called when an existing Component instance has its properties
	// changed.
	OnUpdate(props Properties)

	// OnDestroy is called when the Component is about to be detached and removed.
	OnDestroy()
}

Lifecycle is a mechanism through which a Component may get more detailed lifecycle events.

type LifecycleHandle added in v0.3.0

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

LifecycleHandle is a hook through which a Lifecycle can invalidate a Component, as though the Component's data were changed.

func (LifecycleHandle) NotifyChanged added in v0.3.0

func (h LifecycleHandle) NotifyChanged()

NotifyChanged invalidates the Component instance.

type Overlay added in v0.3.0

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

func OpenOverlay added in v0.3.0

func OpenOverlay(instance Instance) Overlay

func (*Overlay) Close added in v0.3.0

func (o *Overlay) Close()

type Properties

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

Properties is a holder for all data necessary to render a component.

func (Properties) CallbackData

func (p Properties) CallbackData() interface{}

CallbackData returns the callback data that can be used by the component to notify its instantiator regarding key events.

func (Properties) Children

func (p Properties) Children() []Instance

Children returns all the child instances that this component should host.

func (Properties) Data

func (p Properties) Data() interface{}

Data returns the configuration data needed to render the component.

func (Properties) InjectCallbackData

func (p Properties) InjectCallbackData(target interface{})

InjectCallbackData is a helper function that injects the CallbackData into the specified target, which should be a pointer to the correct type.

func (Properties) InjectData

func (p Properties) InjectData(target interface{})

InjectData is a helper function that injects the Data into the specified target, which should be a pointer to the correct type.

func (Properties) InjectLayoutData

func (p Properties) InjectLayoutData(target interface{})

InjectLayoutData is a helper function that injects the LayoutData into the specified target, which should be a pointer to the correct type.

func (Properties) InjectOptionalCallbackData

func (p Properties) InjectOptionalCallbackData(target, defaultValue interface{})

InjectOptionalCallbackData is a helper function that injects the CallbackData into the specified target, which should be a pointer to the correct type or if there is no callback data, it injects the default one.

func (Properties) InjectOptionalData

func (p Properties) InjectOptionalData(target, defaultValue interface{})

InjectOptionalData is a helper function that injects the Data into the specified target, which should be a pointer to the correct type of if there is no data, it injects the default one.

func (Properties) InjectOptionalLayoutData

func (p Properties) InjectOptionalLayoutData(target, defaultValue interface{})

InjectOptionalLayoutData is a helper function that injects the LayoutData into the specified target, which should be a pointer to the correct type or if there is no layout data, it injects the default one.

func (Properties) LayoutData

func (p Properties) LayoutData() interface{}

LayoutData returns the layout data needed to layout the component.

type Reducer

type Reducer func(store *Store, action interface{}) interface{}

Reducer is a mechanism through which a Store's value is changed. It is sent actions and is required to return the changed value according to the specified action. If the Reducer returns the old state of the Store, then it is considered that the action is not applicable for this Reducer.

type State

type State[T any] struct {
	// contains filtered or unexported fields
}

State represents a persistent state of a component. Every render operation for a component would return the same sequence of states.

func UseState

func UseState[T any](fn func() T) *State[T]

UseState registers a new State object to the given component.

During component initialization, the closure function will be called to retrieve an initial value to be assigned to the State.

The order in which this function is called inside a component's render function is important. As such, every component render should issue exactly the same UseState calls and in the exacly the same order.

func (*State[T]) Get

func (s *State[T]) Get() T

Ge returns the current value stored in this State.

func (*State[T]) Set

func (s *State[T]) Set(value T)

Set changes the value stored in this State. Using this function will force the component to be scheduled for reconciliation.

type Store

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

Store represents a state that can cross component boundaries, which allows multiple components to share the same source of truth.

func CreateStore

func CreateStore(reducer Reducer, initialValue interface{}) *Store

CreateStore creates a new Store instance.

The specified reducer will be responsible for handling dispatched actions and adjusting the store's state.

The initialValue should be of the same type that the reducer will operate on and can be used to initialize the Store.

Note that similarly to Contexts, there can only be one Store instance per value type. Unlike Contexts, however, Stores are intended to have their value change throughout the lifecycle of the application.

func (*Store) Destroy

func (s *Store) Destroy()

Destroy releases this Store and the value that it manages. A destroyed store will no longer be discoverable.

func (*Store) Get

func (s *Store) Get() interface{}

Get returns the value stored in the Store.

func (*Store) Inject

func (s *Store) Inject(target interface{})

Inject is a helper function that allows one to inject the Store's value directly into a variable referenced via the target pointer.

type StoreProviderData

type StoreProviderData struct {

	// Entries contains the definition of all Stores that should be managed
	// by the given StoreProvider.
	Entries []StoreProviderEntry
}

StoreProviderData is the data necessary to instantiate a StoreProvider.

Note that the StoreProvider caches the Stores it creates and a reconciliation with a different data will be ignored.

type StoreProviderEntry

type StoreProviderEntry struct {

	// Reducer specifies the Reducer that will be passed to CreateStore.
	Reducer Reducer

	// InitialValue specifies the initialValue that will be passed to CreateStore.
	InitialValue interface{}
}

StoreProviderEntry represents a single Store instance.

func NewStoreProviderEntry

func NewStoreProviderEntry(reducer Reducer, initialValue interface{}) StoreProviderEntry

NewStoreProviderEntry is a helper function to quickly create a StoreProviderEntry value.

Jump to

Keyboard shortcuts

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