drip_flutter 0.7.1-alpha
drip_flutter: ^0.7.1-alpha copied to clipboard
Flutter reactive render binding for DripState, enabling zero-rebuild UI updates through direct RenderObject synchronization.
0.7.1-alpha — 2026-05-18 #
Changed #
- Test-suite reliability improvements aligned with DRIP's two-pump reactive contract in widget tests.
drip_testhelper alignment for node lifecycle and async assertion coverage.- Final release-readiness documentation and metadata verification.
0.7.0-alpha — 2026-05-17 #
API Freeze #
The drip_flutter public API is now frozen. No new widgets, classes, or functions will be added without a documented proposal. No public symbol will be removed without a deprecation cycle of at least one minor version. This version is the last pre-1.0.0 version before the drip_flutter 1.0.0 stable release.
Frozen API Surface #
DripText— bindsDripState<String>to text rendering.DripOpacity— bindsDripState<double>to opacity.DripColor— bindsDripState<Color>to background color.DripTransform— bindsDripState<Matrix4>to transforms.DripImage— bindsDripState<ImageProvider>to images.DripCustomBinding<T>— user-defined render binding base.DripFrame<T>— controlled structural update frame.DripFrameBuilder<T>— widget builder for frame-driven updates.DripBuilder<T>— rebuilds a subtree on source changes.DripSelect— rebuilds only when the selected slice changes.DripAsyncBuilder<T>— handlesDripAsyncValue<T>states with slots.DripItemBuilder<T>— builds a single item fromDripItems<T>.DripLifecycle<N>— creates and disposes a node-backed scope with the widget.DripScope.asWidget()— wraps an existing scope as a widget ancestor.DripSemantics<T>— bridges reactive values into the semantics tree.DripNode— optional feature-module convenience base class.DripAsyncNode— optional async helper mixin forDripNode.
Changed #
DripNodeandDripAsyncNodedocumentation now explicitly presents them as optional convenience patterns, not required architectural components.DripSelect2,DripSelect3, andDripSelect4are internalized behind the frozenDripSelect.two,DripSelect.three, andDripSelect.fourentry points.DripFlutterBindingremains an internal integration bridge and is no longer exported from the public barrel.DripAsyncNodeMixinis replaced by the frozenDripAsyncNodemixin name.
Removed #
DripReadableXand itsasString,map, andwhereconvenience methods were removed from the public surface because they are not part of the frozen Flutter API.
0.6.0-alpha - 2026-05-17 #
BREAKING CHANGES #
This release removes all APIs deprecated in 0.5.1-alpha. If your code uses any of the following, it will not compile after this upgrade. See MIGRATION.md for the replacement for each:
DripNodeProvider— useDripLifecycle.context.node<N>()— useDripLifecycleand explicit dependency passing.DripRouteNode— useDripLifecyclewith a route observer.DripList<T>— useDripItems<T>from drip_core.DripListView<T>— useDripItemBuilderfrom drip_flutter.
Changed #
drip_coredependency updated to^1.0.0(stable).
0.5.1-alpha - 2026-05-16 #
Added #
DripItemBuilder<T>: Reactive builder that binds to a specific element index of aDripItemscollection, supporting standard rebuilding or high-performance zero-rebuild direct render binding mode.DripSemantics: Accessibility bridge forDripReadable<T>. Synchronizes reactive values to the semantics tree with debounced updates.DripLifecycle: High-level widget for managingDripNodeorDripScopelifetimes withoutInheritedWidget. Enforces context-free injection.DripScope.asWidget(): Extension to easily bind a scope's disposal to a widget's lifecycle.
Deprecated #
DripNodeProvider,context.node(),DripRouteNode,DripList, andDripListVieware now deprecated.- Migration: Use
DripLifecyclefor node management,DripItemsas the list-state model, andDripItemBuilderfor list item rendering.
Changed #
DripBinding: Now integrates withDripTraceto provide diagnostic context on render property updates.
0.5.0-alpha - 2026-05-16 #
Fixed #
Subscription Lifecycle — DripRenderParagraph (Risk 4 / CI-1.2)
- Root cause:
unbindState()was the only teardown path and always set_source = null. When Flutter reuses the sameRenderObjectinstance after unmounting a widget (same slot / same type),RenderObject.attach()fired on remount but_createBinding()returned early because_sourcewasnull— no new subscription was registered. - Fix: Split teardown into two methods:
detachBinding()— removes theDripBindingsubscription but preserves_source, soattach()can re-subscribe on remount. Called fromdidUnmountRenderObject.unbindState()— full teardown (clears both_bindingand_source). Called only when the source is replaced viabindState()or theRenderObjectis permanently disposed.
Test Timing — flutter_test two-pump pattern
- Root cause:
DripBatchschedules propagation viaFuture.microtask. Influtter_test'sFakeAsync, microtasks drain after the frame's build phase. Callingwrite()→ onepump()delivers the notification and callssetState, but the resulting dirty build is not picked up until the next frame. - Fix (
callback_identity_test.dart/scratch_test.dart): Changed all write-then-assert sequences to use two pumps after a reactive write:- First pump: microtask drains →
_onChangedfires →setStatemarks element dirty. - Second pump: Flutter builds the dirty element → widget remounts →
attach()→ subscription re-registered → listener count correct.
- First pump: microtask drains →
- Also added
await tester.pump()beforepumpWidget()in the unmount step so thewrite(false)notification is committed before the tree is replaced.
Internal #
- Diagnostic
printinstrumentation added toDripBuilder._onChanged,initState, anddisposeto trace the Flutter element lifecycle — removed after root cause confirmed. - All 113
drip_fluttertests pass. Zerodart analyzewarnings.
0.4.0-alpha #
Added #
DripBuilder<T>— general-purpose reactive builder widget. Accepts anyDripReadable<T>(DripState, DripComputed, or DripAsync) and rebuilds its subtree when the value changes. Scoped setState — only the builder's own subtree rebuilds.DripSelect— multi-source reactive builder. Uses an internalDripComputedto combine multiple reactive sources. Rebuilds only when the combined output changes (version-clock and equality checked). Supports Dart 3 record types as combined value.DripAsyncBuilder<T>— async state widget with exhaustive sealed-class switching. Providesloading,data, anderrorbuilder callbacks. BothloadinganderrorreceivepreviousDatafor continuity patterns. Sensible defaults for unimplemented callbacks (debug warnings included).DripAsyncNodemixin — addsasyncState<T>(),asyncFromFuture(), andasyncFromStream()toDripNodesubclasses. All async states are automatically scoped to the node'sDripScope.
Dependencies #
drip_coreconstraint updated to^0.2.0-alpha
0.3.0-alpha - 2026-05-15 #
Added — Node System #
DripNode— abstract feature module with an ownedDripScope. Extend to create a named, scoped business-logic unit. All state, computed values, and effects are automatically disposed when the node is disposed.DripNode.register<T>/DripNode.resolve<T>— scoped dependency injection. Singleton by default; no global service locators.DripNodelifecycle:onInit,onDispose,onBackground,onForeground.DripNodeProvider<N>—StatefulWidget+InheritedWidgetthat creates a node on mount, forwards app-lifecycle events, and disposes it on unmount. Uses aBuilderchild to ensure the context passed tobuildersits below theInheritedWidgetsocontext.node<N>()resolves correctly.DripRouteNode—DripNodesubclass with route-lifecycle hooks (onRouteEnter,onRouteLeave). Integrates with Flutter'sRouteObserver.BuildContext.node<N>()/BuildContext.maybeNode<N>()— ergonomic node lookup extensions.
Added — List System #
DripList<T>— reactive list with item-level subscriber granularity. Updating indexinotifies only the subscriber registered for indexi.DripListView<T>— list widget that rebuilds only the tile at the changed index. Structural changes (add/remove) trigger a minimal list-level rebuild.
Fixed #
DripNodeProvider.of()now injects the actual runtime type name$Nin the missing-provider error message (was$Nas a literal string due to escaped interpolation).DripNodeProvider.buildercontext now correctly resolves its ownInheritedWidgetby wrapping the child in aBuilder.
Architecture #
DripValue<T>interface introduced indrip_core— shared readable/subscribable contract implemented by bothDripState<T>andDripComputed<T>. All Flutter render widgets now acceptDripValue<T>, allowing computed values to be passed directly without casting.DripListener/ListenerSubscribermoved todrip_state_base.dartto be accessible package-wide without importing implementation files.DripNodeis pure Dart — fully unit-testable without a Flutter widget tree.
Testing (drip_flutter) #
drip_node_test.dart— 20+ tests coveringDripNodelifecycle,register/resolve, effects, and disposal.drip_node_provider_test.dart— 8 tests covering mount/unmount, lifecycle forwarding,Provider.of,context.node, error messages, and nested providers.drip_route_node_test.dart— route lifecycle integration tests.drip_list_test.dart— 10 tests coveringadd,removeAt,[]=,insert,replaceAll,update,dispose.drip_list_view_test.dart— 8 tests including a 10,000-item single-tile-rebuild benchmark.
0.2.0-alpha - 2026-05-13 #
First release of drip_flutter — the Flutter direct render binding layer.
Added #
DripBinding<T>— liveRenderObjectsubscriber. Applies state changes directly to render properties, bypassing the widget/element rebuild cycle.DripText— zero-rebuild text widget. BindsDripValue<String>toRenderParagraph.textviamarkNeedsLayout().DripOpacity— zero-rebuild opacity widget. BindsDripValue<double>(clamped[0.0, 1.0]) viamarkNeedsPaint().DripColor— zero-rebuild background color binding viamarkNeedsPaint().DripTransform— zero-rebuildMatrix4transform binding viamarkNeedsPaint().DripImage—ImageProviderbinding with async image resolution.DripCustomBinding<T>— abstract base class for customRenderObjectbindings.DripFrame<T>/DripFrameBuilder<T>— controlled rebuild boundary for deliberate structural updates.
Performance #
- Verified: 1,000 simultaneous
DripStatewrites → 0 widgetbuild()calls. - Demo app
demo_grid: 1,000-cell live grid at 60 fps, zero rebuilds.
Architecture #
- Invariant 2 enforced: zero
setState()calls in binding code path. - Invariant 7 enforced: all bindings deregistered in
didUnmountRenderObject.
