From a60fa62a6f9a3c8ba79cf6267bc8741595c28abd Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 21:05:16 +0000 Subject: [PATCH] docs: add detailed godoc comments to public APIs Added extensive documentation to `pkg/api`, `compose`, `state`, and `runtime` packages to improve developer experience and support godoc generation. Detailed changes: - `pkg/api`: Documented `Composer`, `Composable`, `Modifier`, `Identifier`, and other core types. Added usage examples. - `compose`: Documented `NewComposer`, `Sequence` (deprecated), and `Id`. - `state`: Documented `SupportState`, `MutableValue`, `PersistentState`, and `Memo` types. - `runtime`: Documented `Runtime` interface and `Run` method. --- compose/composer.go | 14 +++++++ pkg/api/types.go | 78 +++++++++++++++++++++++++++++++++++---- runtime/runtime.go | 5 +++ state/memo.go | 4 ++ state/mutable_value.go | 5 +++ state/persistent_state.go | 7 ++++ state/types.go | 17 ++++++++- 7 files changed, 120 insertions(+), 10 deletions(-) diff --git a/compose/composer.go b/compose/composer.go index c53a72f3..3dce2565 100644 --- a/compose/composer.go +++ b/compose/composer.go @@ -10,12 +10,26 @@ import ( type Composable = api.Composable type Composer = api.Composer +// NewComposer creates a new Composer instance initialized with the given persistent state store. +// The returned Composer is the entry point for building and managing the composition tree. +// +// Parameters: +// - store: A PersistentState implementation that manages the state across recompositions. +// +// Returns: +// - A new Composer instance. func NewComposer(store state.PersistentState) Composer { return zipper.NewComposer(store) } +// Sequence is a convenience function for combining multiple Composables into a single one. +// It delegates to the internal sequence implementation. +// +// Deprecated: Use c.Sequence(...) method on the Composer interface instead for better fluency. var Sequence = sequence.Sequence +// Id returns a Composable that does nothing and returns the Composer as is. +// It is useful as a placeholder or identity operation in functional composition patterns. func Id() Composable { return func(c Composer) Composer { return c diff --git a/pkg/api/types.go b/pkg/api/types.go index 36dc3968..65acb0f9 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -8,27 +8,57 @@ import ( "github.com/zodimo/go-compose/state" ) -// compose-identifier.api.Identifier +// Identifier is a unique identifier for a composable node in the composition tree. +// It is used to track nodes across recompositions. type Identifier = idApi.Identifier -// type Composition = func(Composable) Composable +// Composable is the fundamental building block of the UI. +// It is a function that takes a Composer and returns a Composer, representing a transformation +// or emission of UI elements into the composition tree. +// +// Unlike Jetpack Compose where @Composable is an annotation, here it is an explicit function signature. +// +// Example: +// +// func MyComponent(c api.Composer) api.Composer { +// return c.Sequence( +// m3Text.Text("Hello"), +// m3Button.Filled(func() { ... }, "Click Me"), +// ) +// } type Composable func(Composer) Composer +// MutableValue is a value holder that can be observed for changes. +// When the value changes, it triggers a recomposition of the scopes that read it. +// This is an alias to state.MutableValue. type MutableValue = state.MutableValue +// NodePath represents the path to a node in the composition tree. type NodePath = node.NodePath -// Public API of the composer +// Composer is the interface that orchestrates the composition process. +// It manages the tree of composables, handles state, and builds the final layout tree. +// +// Users interact with the Composer primarily to: +// - Define the structure of the UI using methods like Sequence, If, When. +// - Manage state using Remember and State (via state.SupportState). +// - Apply modifiers to components. +// - Control flow using Key and Range. type Composer interface { - // -- + // GetID returns the unique identifier of the current composable node. GetID() Identifier + + // GetPath returns the path of the current node in the composition tree. GetPath() NodePath modifier.ModifierAwareComposer - // -- id management + // GenerateID generates a new unique identifier for a child node. GenerateID() Identifier + // EmitSlot emits a value into a named slot of the current node. + // This is used for advanced component composition where data needs to be passed + // to the underlying layout node. EmitSlot(k string, v any) Composer TreeBuilderComposer @@ -36,33 +66,65 @@ type Composer interface { state.SupportState + // WithComposable executes the given Composable with this Composer. + // It is equivalent to calling composable(c). WithComposable(composable Composable) Composer + // If conditionally executes one of two Composables based on the boolean condition. + // If condition is true, ifTrue is executed; otherwise, ifFalse is executed. If(condition bool, ifTrue Composable, ifFalse Composable) Composable + + // When conditionally executes a Composable if the boolean condition is true. + // If condition is false, it behaves like an empty composable. When(condition bool, ifTrue Composable) Composable + + // Else conditionally executes a Composable if the boolean condition is false. + // It acts as the inverse of When. Else(condition bool, ifFalse Composable) Composable + // Sequence executes a list of Composables in order. + // This is the primary way to group multiple components together. Sequence(contents ...Composable) Composable - // Control Flow + // Key identifies a block of execution with a specific key. + // This is useful for maintaining state when the order of items in a list changes. Key(key any, content Composable) Composable + + // Range loops count times and executes the function fn for each index. + // It is used for rendering lists or repeating elements. Range(count int, fn func(int) Composable) Composable } -// Public Modifier interface +// Modifier is an interface for objects that can modify the behavior or appearance of a UI element. +// Modifiers are chained together to apply multiple effects. type Modifier interface { - // Then chains this modifier with another + // Then chains this modifier with another modifier. + // It returns a new Modifier that represents the combination of the two. Then(other Modifier) Modifier } +// LayoutNode represents a node in the layout tree produced by the composition. +// It contains the information needed by the runtime to measure, layout, and draw the UI. type LayoutNode = layoutnode.LayoutNode +// TreeBuilderComposer provides methods for building the composition tree structure. +// These methods are typically used internally by framework components but are exposed +// for advanced custom component creation. type TreeBuilderComposer interface { + // StartBlock starts a new group or node in the composition tree with the given key. StartBlock(key string) Composer + + // EndBlock ends the current group or node. EndBlock() Composer + + // Build finalizes the composition and returns the root of the generated layout tree. Build() LayoutNode } +// GioLayoutNodeAwareComposer allows setting the widget constructor for the current layout node. +// This bridges the composition world with the underlying Gio widgets. type GioLayoutNodeAwareComposer interface { + // SetWidgetConstructor sets the function responsible for creating the Gio widget + // associated with the current layout node. SetWidgetConstructor(constructor layoutnode.LayoutNodeWidgetConstructor) } diff --git a/runtime/runtime.go b/runtime/runtime.go index 6d9cceeb..3abaffc0 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -2,6 +2,11 @@ package runtime import "gioui.org/op" +// Runtime is the interface responsible for executing the layout tree. +// It bridges the gap between the abstract LayoutNode tree produced by composition +// and the actual drawing operations. type Runtime interface { + // Run executes the layout logic for the given LayoutNode within the provided LayoutContext. + // It returns an op.CallOp that contains the drawing operations for the node and its children. Run(LayoutContext, LayoutNode) op.CallOp } diff --git a/state/memo.go b/state/memo.go index 53beac54..238951fb 100644 --- a/state/memo.go +++ b/state/memo.go @@ -4,10 +4,14 @@ import ( "github.com/zodimo/go-compose/internal/immap" ) +// Memo is an alias for an immutable map holding values of any type. +// It is used for memoization and efficient state storage. type Memo = immap.ImmutableMap[any] +// MemoTyped is an alias for an immutable map holding values of a specific type T. type MemoTyped[T any] = immap.ImmutableMap[T] +// EmptyMemo returns an empty typed immutable map. func EmptyMemo[T any]() MemoTyped[T] { return immap.EmptyImmutableMap[T]() } diff --git a/state/mutable_value.go b/state/mutable_value.go index 754e31f9..214d5f16 100644 --- a/state/mutable_value.go +++ b/state/mutable_value.go @@ -1,6 +1,11 @@ package state +// MutableValue is a wrapper around a value that can be read and written. +// Changes to the value are propagated to the composition system to trigger updates. type MutableValue interface { + // Get retrieves the current value. Get() any + + // Set updates the value and notifies listeners (e.g., the composition system) of the change. Set(value any) } diff --git a/state/persistent_state.go b/state/persistent_state.go index 138e42d0..7ce79ee3 100644 --- a/state/persistent_state.go +++ b/state/persistent_state.go @@ -1,6 +1,13 @@ package state +// PersistentState is the interface for the underlying store that holds state values. +// It manages the lifecycle of MutableValues and allows the runtime to react to state changes. type PersistentState interface { + // GetState retrieves or creates a MutableValue for the given key. + // If the state for the key does not exist, it is initialized using the initial function. GetState(key string, initial func() any) MutableValue + + // SetOnStateChange registers a callback that is invoked whenever any state managed by this store changes. + // This is typically used by the runtime to trigger a new frame or recomposition. SetOnStateChange(callback func()) } diff --git a/state/types.go b/state/types.go index 66c4331d..3cba0950 100644 --- a/state/types.go +++ b/state/types.go @@ -1,6 +1,19 @@ package state +// SupportState defines the interface for state management within a composition. +// It allows composables to remember values and manage state that persists across recompositions. type SupportState interface { - Remember(key string, calc func() any) any // transient state - State(key string, initial func() any) MutableValue // persistent state + // Remember stores a value computed by calc. + // The value is calculated only once (or when the key changes, if applicable in future implementations) + // and returned on subsequent recompositions. + // This corresponds to transient state that is attached to the current position in the composition. + Remember(key string, calc func() any) any + + // State returns a MutableValue that persists across recompositions. + // When the value inside the MutableValue changes, it triggers a recomposition. + // + // Parameters: + // - key: A unique string to identify this state. + // - initial: A function that provides the initial value if the state does not exist. + State(key string, initial func() any) MutableValue }