Files
kjol/go/wasmruntime/vdom/ref.go

56 lines
2.0 KiB
Go

package vdom
// Ref is a handle on the real DOM node a VNode rendered to. It is the bridge the
// neutral component code uses to ask the browser for things it cannot know on its
// own — how big an element is, where it sits in the viewport — without importing
// anything platform-specific: the value inside is opaque (`any`), filled in by the
// wasm reconciler and always nil on the server. Read it through the wasmruntime
// host API (wasmruntime.Rect, SetStyle, Focus, …), which no-ops when it is nil.
//
// A component creates one ref per element it needs to measure and keeps it across
// renders (in a closure, next to its signals — NOT rebuilt inside the render
// function, or it would be a fresh empty ref every frame):
//
// panel := vdom.NewRef()
// return func() *VNode {
// return Div(WithRef(panel), Attr("class", "…"), …)
// }
//
// and later, after the DOM exists (see wasmruntime.AfterRender):
//
// r := wasmruntime.Rect(panel) // zero Rect if unmounted or on the server
type Ref struct{ node any }
// NewRef returns an unattached Ref.
func NewRef() *Ref { return &Ref{} }
// Node is the platform DOM handle (a js.Value in the browser), or nil if the ref
// is not currently attached to a mounted element. Component code should not need
// this — it is for the host API and the reconciler.
func (r *Ref) Node() any {
if r == nil {
return nil
}
return r.node
}
// Mounted reports whether the ref currently points at a live DOM node.
func (r *Ref) Mounted() bool { return r != nil && r.node != nil }
type refMod struct{ ref *Ref }
func (m refMod) apply(n *VNode) { n.Ref = m.ref }
// WithRef attaches a Ref to this element, so the DOM node it renders to can be
// measured and manipulated. Ignored on the server.
func WithRef(r *Ref) Mod { return refMod{r} }
// SetRefNode points a Ref at a platform DOM handle (or nil to detach). It exists
// for the reconciler and the host API, which live in another package; component
// code has no reason to call it.
func SetRefNode(r *Ref, node any) {
if r != nil {
r.node = node
}
}