56 lines
2.0 KiB
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
|
|
}
|
|
}
|