Documentation
¶
Overview ¶
Package componentview is the typed per-component complement to the generic leewaywidgets.Table2CardEmitter (ADR-0075). Where Table2CardEmitter renders any leeway table structurally, this renders *recognised* components with bespoke widgets: each registered RendererI is an ECS "system that draws", matched to entities that carry its component. A Dispatcher lays the detected components out as a collapsible single-record report — one foldable panel per component, the archetype made visible — and routes anything unrecognised to a generic fallback.
Detection and typed decode live in this package too, as Binder (see componentview_detect.go): Bind ties a component kind to the leeway DTO that reads it, and Binder.Components decodes a row into the components it carries by asking each bound kind in turn. That is ADR-0075's detect-then-render, finally built on ADR-0146's read contract.
Rendering does not depend on it — Dispatcher.RenderReport takes decoded Component values from anywhere, so a caller with its own decode path is unaffected. Earlier revisions of this doc claimed the package was free of leeway-codec dependencies; it no longer is, because the detection half had to live somewhere and the renderer↔component mapping is what this package owns.
Index ¶
- Variables
- type BatteryVal
- type Binder
- func (inst *Binder) Add(b Binding) (err error)
- func (inst *Binder) Bindings() []Binding
- func (inst *Binder) Components(readers *marshallreflect.SectionReaders, i int) (out []Component, err error)
- func (inst *Binder) Detect(readers *marshallreflect.SectionReaders, i int) (out []KindPresence, err error)
- func (inst *Binder) Registry() *component.Registry
- type Binding
- type Component
- type ComponentKindE
- type Dispatcher
- type IdentityVal
- type KindPresence
- type Registry
- type RendererI
- type TaskedVal
Constants ¶
This section is empty.
Variables ¶
var PackageProps = packageprops.Props{ WASMWASI: packageprops.WASMBlocked, WASMJS: packageprops.WASMBlocked, WASMFreestanding: packageprops.WASMBlocked, }
PackageProps records this package's curated properties (ADR-0080).
Blocked: rendering leeway components means reading them reflectively, and the reflective marshaller's closure reaches arrow-go — componentview → leeway/marshall/go/marshallreflect → arrow/array, which the survey classifies unsupported-external. The dependency is what the widget is for.
Declared amenable at the 2026-06-12 rollout, which was true then; the marshallreflect edge came later and nothing was checking.
Functions ¶
This section is empty.
Types ¶
type BatteryVal ¶
type BatteryVal struct{ Charge uint64 }
IdentityVal, BatteryVal and TaskedVal are the decoded carriers the seed renderers expect. Tasked is tags-only for now — its time window (timeRange) is deferred together with the timeline widget (stage-2 defers timeRange).
type Binder ¶ added in v0.0.17
type Binder struct {
// Lookup resolves ref-channel membership names to ids for every binding.
// Nil means every membership is verbatim.
Lookup marshallreflect.LookupI
// contains filtered or unexported fields
}
Binder detects the components of a row. It holds the bindings and, alongside them, a component.Registry of their contracts — the catalogue answering which kinds are known and which slots they claim.
func (*Binder) Add ¶ added in v0.0.17
Add registers a binding. Two bindings claiming the same slot is NOT an error: components overlap when stages fuse facts they each know only part of, and no process holds the global component vocabulary to judge it. Use Registry().SlotClaims() to see what overlaps.
A repeated KIND is an error — the report renders one panel per kind, so two bindings for one kind would silently drop a reader.
func (*Binder) Components ¶ added in v0.0.17
func (inst *Binder) Components(readers *marshallreflect.SectionReaders, i int) (out []Component, err error)
Components decodes row i into the components it carries, ready for Dispatcher.RenderReport. Absent components are omitted — the dispatcher's ShowAbsent draws them from the registry instead.
A component the row carries but does not CONFORM to (a slot holding more attributes than its DTO admits, which fusion can produce) is reported as an error rather than silently dropped: it is present, and rendering the report without it would misstate the archetype.
func (*Binder) Detect ¶ added in v0.0.17
func (inst *Binder) Detect(readers *marshallreflect.SectionReaders, i int) (out []KindPresence, err error)
Detect reports each bound component's presence on row i, in registration order, without decoding any value. Cheap enough to run per row over a heterogeneous table: it reads only the membership columns of the sections its bindings claim.
type Binding ¶ added in v0.0.17
type Binding struct {
// contains filtered or unexported fields
}
Binding ties a component kind to the DTO that reads it. Build one with Bind.
func Bind ¶ added in v0.0.17
func Bind[T any](kind ComponentKindE, project func(T) any) (b Binding, err error)
Bind binds a component kind to the leeway DTO T that reads it, projecting the decoded DTO to the carrier the kind's renderer expects.
T is a COMPONENT DTO — it declares only the slots its component owns, not a row's worth of fields. That is what makes detection meaningful: a fat DTO spanning several components can only ever answer "is all of this here?".
func (Binding) Contract ¶ added in v0.0.17
func (inst Binding) Contract() mappingplan.ReadContract
Contract is the read contract of the binding's DTO: the (section, membership) slots it claims and the attribute arity each admits.
func (Binding) Kind ¶ added in v0.0.17
func (inst Binding) Kind() ComponentKindE
Kind reports which component the binding reads.
type Component ¶
type Component struct {
Kind ComponentKindE
Value any
}
Component is one decoded component on an entity: its kind plus the typed value the kind's renderer understands (type-asserted by that renderer). A nil Value renders as present-but-empty.
type ComponentKindE ¶
type ComponentKindE string
ComponentKindE names a recognised leeway component — a section or section-bundle treated as one logical thing. The seed kinds are the ecsdemo drone components; fact-components register their own.
const ( KindIdentity ComponentKindE = "identity" KindBattery ComponentKindE = "battery" KindTasked ComponentKindE = "tasked" )
type Dispatcher ¶
type Dispatcher struct {
// ShowAbsent renders registered-but-absent components as dimmed lines.
ShowAbsent bool
// DefaultOpen sets the initial expanded state of each component panel.
DefaultOpen bool
// Fallback renders a present component that no renderer claims — a consumer
// wires this to the generic Table2CardEmitter. Nil renders a short note.
Fallback func(ids *c.WidgetIdStack, comp Component)
// contains filtered or unexported fields
}
Dispatcher renders one entity's components as a collapsible single-record report: a foldable panel per registered component present on the entity, optionally a dimmed line per registered-but-absent component (so the archetype is legible at a glance), and a generic fallback panel for any present component no renderer claims.
func NewDispatcher ¶
func NewDispatcher(reg *Registry) (inst *Dispatcher)
func (*Dispatcher) RenderReport ¶
func (inst *Dispatcher) RenderReport(ids *c.WidgetIdStack, comps []Component)
RenderReport draws the report for one entity's decoded components. Collapse state is keyed by component kind, so it survives clicking through records.
type IdentityVal ¶
type IdentityVal struct{ Status string }
IdentityVal, BatteryVal and TaskedVal are the decoded carriers the seed renderers expect. Tasked is tags-only for now — its time window (timeRange) is deferred together with the timeline widget (stage-2 defers timeRange).
type KindPresence ¶ added in v0.0.17
type KindPresence struct {
Kind ComponentKindE
Presence mappingplan.PresenceE
}
KindPresence is one component's verdict for a row.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry holds the per-kind renderers in a stable registration order, which is also the report's rendering order.
func DefaultRegistry ¶
func DefaultRegistry() (inst *Registry)
DefaultRegistry returns a Registry seeded with the light-version drone renderers in archetype order: identity, battery, tasked.
func NewRegistry ¶
func NewRegistry() (inst *Registry)
type RendererI ¶
type RendererI interface {
Kind() ComponentKindE
Title() string
Render(ids *c.WidgetIdStack, value any)
}
RendererI draws one component kind from its decoded value. Implementations type-assert value to their own carrier.