Files
via/signal.go
Ryan Hamamura 7eb86999b2 feat: refactor maplibre for reactive signals and Via-native API
- Export Signal type (signal → Signal) so subpackages can reference it
- Expose viewport signals as public fields (CenterLng, CenterLat, Zoom,
  Bearing, Pitch) for .Text() display and .Bind() usage
- Add signal-backed marker positions (LngSignal/LatSignal) with
  data-effect reactivity for server push and dragend writeback
- Add event system (MapEvent, OnClick, OnLayerClick, OnMouseMove,
  OnContextMenu) using hidden inputs + action triggers
- Add Source interface replacing type-switch, with RawSource escape hatch
- Add CameraOptions for FlyTo/EaseTo/JumpTo/FitBounds/Stop
- Add Control interface with NavigationControl, ScaleControl,
  GeolocateControl, FullscreenControl
- Expand Options with interaction toggles, MaxBounds, and Extra map
- Add effectspike example to validate data-effect with server-pushed signals
- Update maplibre example to showcase all new features
2026-02-20 08:29:24 -10:00

84 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package via
import (
"fmt"
"strconv"
"strings"
"github.com/ryanhamamura/via/h"
)
// Signal represents a value that is reactive in the browser. Signals
// are synced with the server right before an action triggers.
//
// Use Bind() to connect a signal to an input and Text() to display it
// reactively on an html element.
type Signal struct {
id string
val any
changed bool
err error
}
// ID returns the signal ID.
func (s *Signal) ID() string {
return s.id
}
// Err returns a signal error or nil if it contains no error.
//
// It is useful to check for errors after updating signals with
// dynamic values.
func (s *Signal) Err() error {
return s.err
}
// Bind binds this signal to an input element. When the input changes
// its value the signal updates in real-time in the browser.
//
// Example:
//
// h.Input(h.Type("number"), mysignal.Bind())
func (s *Signal) Bind() h.H {
return h.Data("bind", s.id)
}
// Text binds the signal value to an html span element as text.
//
// Example:
//
// h.Div(mysignal.Text())
func (s *Signal) Text() h.H {
return h.Span(h.Data("text", "$"+s.id))
}
// SetValue updates the signals value and marks it for synchronization with the browser.
// The change will be propagated to the browser using *Context.Sync() or *Context.SyncSignals().
func (s *Signal) SetValue(v any) {
s.val = v
s.changed = true
s.err = nil
}
// String returns the signal value as a string.
func (s *Signal) String() string {
return fmt.Sprintf("%v", s.val)
}
// Bool tries to read the signal value as a bool.
// Returns the value or false on failure.
func (s *Signal) Bool() bool {
val := strings.ToLower(s.String())
return val == "true" || val == "1" || val == "yes" || val == "on"
}
// Int tries to read the signal value as an int.
// Returns the value or 0 on failure.
func (s *Signal) Int() int {
if n, err := strconv.Atoi(s.String()); err == nil {
return n
}
return 0
}