registry/widget.go

Functions Structs

Functions

func AllInfo

AllInfo returns a copy of all registered widget information.

 

The returned slice is sorted by widget name.

func (r *WidgetRegistry) AllInfo() []WidgetInfo {
	r.mu.RLock()
	defer r.mu.RUnlock()

	infos := make([]WidgetInfo, 0, len(r.info))
	for _, info := range r.info {
		infos = append(infos, info)
	}

	// Sort by name for consistent ordering
	sort.Slice(infos, func(i, j int) bool {
		return infos[i].Name < infos[j].Name
	})

	return infos
}

func AllWidgetInfo

AllWidgetInfo returns information about all registered widgets.

 

The returned slice is sorted by widget name.

func AllWidgetInfo() []WidgetInfo {
	return globalWidgetRegistry.AllInfo()
}

func Clear

Clear removes all registered widgets.

 

This is primarily useful for testing to reset the registry state.

func (r *WidgetRegistry) Clear() {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.widgets = make(map[string]WidgetFactory)
	r.info = make(map[string]WidgetInfo)
}

func ClearGlobalRegistry

ClearGlobalRegistry removes all widgets from the global registry.

 

WARNING: This is primarily intended for testing. Use with caution

in production code as it will break any code relying on registered widgets.

func ClearGlobalRegistry() {
	globalWidgetRegistry.Clear()
}

func Count

Count returns the number of registered widgets.

func (r *WidgetRegistry) Count() int {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return len(r.widgets)
}

func Create

Create creates a widget by name using its registered factory.

 

The config parameter is passed to the widget's factory function.

Pass nil for widgets that don't require configuration.

 

Returns ErrWidgetNotFound if no widget is registered with the given name.

func (r *WidgetRegistry) Create(name string, config map[string]any) (Widget, error) {
	r.mu.RLock()
	factory, exists := r.widgets[name]
	r.mu.RUnlock()

	if !exists {
		return nil, fmt.Errorf("%w: %s", ErrWidgetNotFound, name)
	}

	return factory(config)
}

func CreateWidget

CreateWidget creates a widget by name from the global registry.

 

This is the primary function for creating widgets dynamically.

The config parameter is passed to the widget's factory function.

 

Example:

 

widget, err := registry.CreateWidget("button", map[string]any{

"label": "Click Me",

"onClick": func() { fmt.Println("Clicked!") },

})

func CreateWidget(name string, config map[string]any) (Widget, error) {
	return globalWidgetRegistry.Create(name, config)
}

func GetWidgetInfo

GetWidgetInfo returns information about a registered widget.

 

Returns false as the second value if the widget is not registered.

func GetWidgetInfo(name string) (WidgetInfo, bool) {
	return globalWidgetRegistry.Info(name)
}

func GlobalRegistry

GlobalRegistry returns the global widget registry instance.

 

This is useful for advanced use cases where direct access to the

registry is needed, such as iterating over all widgets or

implementing custom registration logic.

func GlobalRegistry() *WidgetRegistry {
	return globalWidgetRegistry
}

func Has

Has returns true if a widget with the given name is registered.

func (r *WidgetRegistry) Has(name string) bool {
	r.mu.RLock()
	defer r.mu.RUnlock()
	_, exists := r.widgets[name]
	return exists
}

func HasWidget

HasWidget returns true if a widget is registered in the global registry.

func HasWidget(name string) bool {
	return globalWidgetRegistry.Has(name)
}

func Info

Info returns the WidgetInfo for a registered widget.

 

Returns false as the second value if the widget is not registered.

func (r *WidgetRegistry) Info(name string) (WidgetInfo, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	info, exists := r.info[name]
	return info, exists
}

func IsValid

IsValid returns true if the category is one of the predefined categories.

func (c Category) IsValid() bool {
	switch c {
	case CategoryInput, CategoryDisplay, CategoryContainer, CategoryCustom:
		return true
	default:
		return false
	}
}

func List

List returns the names of all registered widgets in sorted order.

func (r *WidgetRegistry) List() []string {
	r.mu.RLock()
	defer r.mu.RUnlock()

	names := make([]string, 0, len(r.widgets))
	for name := range r.widgets {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

func ListByCategory

ListByCategory returns the names of widgets in the specified category.

 

The returned list is sorted alphabetically.

func (r *WidgetRegistry) ListByCategory(category Category) []string {
	r.mu.RLock()
	defer r.mu.RUnlock()

	var names []string
	for name, info := range r.info {
		if info.Category == category {
			names = append(names, name)
		}
	}
	sort.Strings(names)
	return names
}

func ListWidgets

ListWidgets returns all registered widget names from the global registry.

 

The returned list is sorted alphabetically.

func ListWidgets() []string {
	return globalWidgetRegistry.List()
}

func ListWidgetsByCategory

ListWidgetsByCategory returns widgets in a specific category from the global registry.

 

The returned list is sorted alphabetically.

func ListWidgetsByCategory(category Category) []string {
	return globalWidgetRegistry.ListByCategory(category)
}

func MustRegister

MustRegister is like Register but panics if registration fails.

 

This is intended for use in init() functions where registration

failure indicates a programming error.

func (r *WidgetRegistry) MustRegister(name string, factory WidgetFactory, info ...WidgetInfo) {
	if err := r.Register(name, factory, info...); err != nil {
		panic(fmt.Sprintf("registry: failed to register widget %q: %v", name, err))
	}
}

func MustRegisterWidget

MustRegisterWidget is like RegisterWidget but panics on failure.

 

Use this in init() functions where registration failure indicates

a programming error that should be caught during development.

func MustRegisterWidget(name string, factory WidgetFactory, info ...WidgetInfo) {
	globalWidgetRegistry.MustRegister(name, factory, info...)
}

func NewWidgetRegistry

NewWidgetRegistry creates a new empty WidgetRegistry.

 

Use this to create an isolated registry for testing or when you need

multiple independent registries.

func NewWidgetRegistry() *WidgetRegistry {
	return &WidgetRegistry{
		widgets:	make(map[string]WidgetFactory),
		info:		make(map[string]WidgetInfo),
	}
}

func Register

Register adds a widget factory to the registry.

 

The name must be unique within the registry. If info is provided,

it stores metadata about the widget for discovery purposes.

 

Returns ErrEmptyName if name is empty, ErrNilFactory if factory is nil,

or ErrWidgetExists if a widget with the same name is already registered.

func (r *WidgetRegistry) Register(name string, factory WidgetFactory, info ...WidgetInfo) error {
	if name == "" {
		return ErrEmptyName
	}
	if factory == nil {
		return ErrNilFactory
	}

	r.mu.Lock()
	defer r.mu.Unlock()

	if _, exists := r.widgets[name]; exists {
		return fmt.Errorf("%w: %s", ErrWidgetExists, name)
	}

	r.widgets[name] = factory

	// Store info if provided
	if len(info) > 0 {
		widgetInfo := info[0]
		// Ensure the name in info matches the registration name
		if widgetInfo.Name == "" {
			widgetInfo.Name = name
		}
		r.info[name] = widgetInfo
	} else {
		// Create minimal info
		r.info[name] = WidgetInfo{Name: name}
	}

	return nil
}

func RegisterWidget

RegisterWidget adds a widget factory to the global registry.

 

This is the primary function for registering widgets. Call this from

your package's init() function to enable automatic registration on import.

 

Example:

 

func init() {

registry.RegisterWidget("my-widget", NewMyWidget, registry.WidgetInfo{

Name: "my-widget",

Description: "A custom widget",

Category: registry.CategoryCustom,

Version: "1.0.0",

})

}

func RegisterWidget(name string, factory WidgetFactory, info ...WidgetInfo) error {
	return globalWidgetRegistry.Register(name, factory, info...)
}

func String

String returns the string representation of the category.

func (c Category) String() string {
	return string(c)
}

func Unregister

Unregister removes a widget from the registry.

 

Returns ErrWidgetNotFound if the widget is not registered.

func (r *WidgetRegistry) Unregister(name string) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	if _, exists := r.widgets[name]; !exists {
		return fmt.Errorf("%w: %s", ErrWidgetNotFound, name)
	}

	delete(r.widgets, name)
	delete(r.info, name)
	return nil
}

func UnregisterWidget

UnregisterWidget removes a widget from the global registry.

 

Returns an error if the widget is not registered.

func UnregisterWidget(name string) error {
	return globalWidgetRegistry.Unregister(name)
}

func Validate

Validate checks if the WidgetInfo has all required fields.

func (i WidgetInfo) Validate() error {
	if i.Name == "" {
		return errors.New("widget info: name is required")
	}
	return nil
}

func WidgetCount

WidgetCount returns the number of registered widgets in the global registry.

func WidgetCount() int {
	return globalWidgetRegistry.Count()
}

Structs

type WidgetInfo struct

WidgetInfo describes a registered widget.

 

This metadata is used for widget discovery, documentation, and tooling.

type WidgetInfo struct {
	// Name is the unique identifier used for registration.
	Name	string

	// Description provides a human-readable description of the widget.
	Description	string

	// Category organizes widgets for filtering and discovery.
	Category	Category

	// Version is the semantic version of the widget (e.g., "1.0.0").
	Version	string
}

type WidgetRegistry struct

WidgetRegistry manages widget registration and creation.

 

The registry maintains a thread-safe collection of widget factories

and metadata, allowing dynamic widget creation by name.

 

Use the package-level functions (RegisterWidget, CreateWidget, etc.)

for the global registry, or create a custom registry for testing

or isolated use cases.

type WidgetRegistry struct {
	mu	sync.RWMutex
	widgets	map[string]WidgetFactory
	info	map[string]WidgetInfo
}