BloomFlutterExtension<T> extension

Extensions on a single Bloom providing the build and listen functor entry points.

Canonical Invocation & Cascade Hierarchy

bloom
 ├── .build                    ((context, data) => ...)       [Declarative UI Rendering]
 │    ├── .child               ((context, data, child) => ..., child: W)
 │    └── .children            ((context, data, children) => ..., children: [...])
 │
 └── .listen                   ((context, state) => ...)      [0-Rebuild Side Effects]
      ├── .debounce            (duration, (context, state) => ...)
      └── .throttle            (duration, (context, state) => ...)

Built using Dart extension types (extension type const), bloom.build and bloom.listen incur zero runtime allocation overhead while providing a fully type-safe, fluent, and canonical API for inline reactive UI composition and 0-rebuild side-effect dispatch.

2-Phase LPDAG & Terminal Invariant Architecture

Unlike composed which uses RawComputedTerminal for dynamic multi-dependency discovery, bloom.build provisions a dedicated 1:1 RawBloomTerminal hosted inside an internal ComponentElement (_InlineSingleBloomElement, etc.) mixing in _BloomTerminalElementMixin<T>.

System Architectural Flow

[ Upstream Bloom<T> Mutates ]
             │
             │ (Phase 1: 0-Compute Push-Dirty Invalidation)
             ▼
[ RawBloomTerminal<T>.onInvalidated: markNeedsBuild() ]
             │
             │ (Flutter Render Pipeline Scheduling)
             ▼
[ _InlineSingleBloomElement.build() ]
             │
             ├─► .build()        ──► Evaluates builder(context, untracked(bloom))
             ├─► .build.child()  ──► If hasData: builder(..., child) | Else: returns child (fallback)
             └─► .build.children ──► If hasData: builder(..., children) | Else: returns SizedBox.shrink()

Key Invariants & Architectural Benefits

  1. Zero-Copy Auto-Healing Gateway: Directly routes dirty invalidation pulses to Element.markNeedsBuild without allocating intermediate tracking collections.
  2. Empty/Error State Fallback: When BloomState.hasData is false, builder variants with a static child parameter return the fallback child (or SizedBox.shrink for children), protecting against extraction exceptions during uninitialized states.
  3. Subtree Isolation: Static subtrees passed via child or children are pre-constructed and bypass re-evaluation when the enclosing reactive element rebuilds.
  4. Zero Runtime Allocation: Backed by extension type const, dispatching directly to dedicated 1:1 elements.

Warning (Anti-Pattern Prevention):

  • Avoid instantiating static child trees inside the builder closure, which forces them to rebuild on every emission. Pass static subtrees to the child: or children: parameter to isolate them from rebuilds.
  • When invoking bloom.build((context, data) => ...), ensure this Bloom node contains valid data. If the target node is uninitialized or in an error state, extracting data throws BloomSnapshotExtractionException. Use bloom.build.child or BloomAsyncBuilder for safe uninitialized/asynchronous state handling.

BAD:

// [Anti-Pattern] Static icon/chart recreated on every emission
counterBloom.build(
  (context, count) => Row(children: [Text('$count'), const HeavyChartWidget()]),
);

GOOD:

// [Recommended] Static subtree cached and passed via child parameter
counterBloom.build.child(
  (context, count, child) => Row(children: [Text('$count'), child]),
  child: const HeavyChartWidget(),
);
on

Properties

build → BloomBuildFunctor<T>

Available on Bloom<T>, provided by the BloomFlutterExtension extension

Entry point for inline single-node reactive UI build functors (BloomBuildFunctor).
no setter
listen → BloomListenFunctor<T>

Available on Bloom<T>, provided by the BloomFlutterExtension extension

Entry point for inline zero-rebuild side-effect listener functors (BloomListenFunctor).
no setter