Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ func (Counter) Body(s *g.Scope) g.View {
}

func main() {
g.Run("Counter", g.Define(func(s *g.Scope) g.View {
return Counter{}
}))
g.Run("Counter", g.Component(Counter{}))
}
```

Expand Down
8 changes: 8 additions & 0 deletions component.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ type Viewable interface {
Body(s *Scope) View
}

// Component wraps a Viewable as a View so it can be passed to APIs that take
// a typed View (Run, RunWithConfig, TestRender). Layout constructors accept
// a Viewable directly via their variadic any arguments; this helper is for
// the top-level entry points that cannot.
func Component(v Viewable) View {
return wrapViewable(v)
}

// wrapViewable turns a Viewable into a View by creating a componentNode whose renderFn invokes Body with the current scope.
func wrapViewable(v Viewable) View {
return &componentNode{
Expand Down
16 changes: 16 additions & 0 deletions docs-site/content/docs/concepts/viewables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ to `VStack`, `List`, or any other constructor.
prop if a child view is expensive to construct and you want to defer it
(see `NavLink` for an example).

## Passing a Viewable to typed `View` slots

Layout constructors accept a Viewable directly because their children are
variadic `any`. Top-level entry points like `Run`, `RunWithConfig`, and
`TestRender` take a typed `View`, so a Viewable needs a one-call wrapper:

```go
func main() {
gova.Run("Counter", gova.Component(Counter{}))
}
```

`Component(v Viewable) View` is a thin adapter. It preserves the Viewable's
Body semantics and its reactive scope; all it does is give the compiler a
`View` where it asks for one.

## When to reach for `Define`

`Define` is fine for:
Expand Down
2 changes: 1 addition & 1 deletion docs-site/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (Counter) Body(s *Scope) View {
}

func main() {
Run("Counter", Counter{})
Run("Counter", Component(Counter{}))
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs-site/content/docs/testing/testrender.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tree you can query and interact with.

```go
func TestCounterIncrements(t *testing.T) {
tree := gova.TestRender(Counter{})
tree := gova.TestRender(gova.Component(Counter{}))

if got := tree.FindText(0).Value; got != "count: 0" {
t.Fatalf("unexpected initial text: %q", got)
Expand Down
Loading