Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void main() => runApp(const MaterialApp(home: CounterPage()));
| Package | Use when |
| :-- | :-- |
| [`levit_flutter`](./packages/kits/levit_flutter) | Building Flutter applications |
| [`levit/levit_dart`](./packages/kits/levit) | Building pure Dart applications |
| [`levit`](./packages/kits/levit) | Building pure Dart applications |

### Core packages

Expand Down
2 changes: 2 additions & 0 deletions examples/nexus_studio/app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ void main({
'ws://localhost:9200/ws',
appId: 'nexus-studio',
channelBuilder: devToolsChannelBuilder,
onError: (e) => debugPrint(
'⚠️ DevTool Server not available. Running without monitoring.'),
);

LevitMonitor.attach(transport: transport);
Expand Down
2 changes: 1 addition & 1 deletion examples/nexus_studio/app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter_lints: ^6.0.0
async: ^2.11.0
stream_channel: ^2.1.1

Expand Down
5 changes: 3 additions & 2 deletions examples/nexus_studio/app/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ void main() {
await tester.pump();
expect(find.byType(app.NodeWidget), findsNWidgets(3));

// Select first node and apply a color via sidebar button.
await tester.tap(find.byType(app.NodeWidget).first);
// Select first node deterministically to avoid brittle hit-testing taps.
final projectController = Levit.find<ProjectController>();
projectController.toggleSelection(projectController.engine.nodes.first.id);
await tester.pump();
await tester.tap(find.byKey(ValueKey('color_${0xFF818CF8}')));
await tester.pump();
Expand Down
2 changes: 2 additions & 0 deletions examples/nexus_studio/server/bin/server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ void main() async {
final transport = WebSocketTransport.connect(
'ws://localhost:9200/ws',
appId: 'nexus-server',
onError: (e) =>
print('⚠️ DevTool Server not available. Running without monitoring.'),
);

LevitMonitor.attach(transport: transport);
Expand Down
3 changes: 3 additions & 0 deletions packages/core/levit_dart_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

## 0.0.7
- Bumped version to 0.0.7

## 0.0.6

### Breaking Changes
Expand Down
12 changes: 12 additions & 0 deletions packages/core/levit_dart_core/lib/src/auto_linking.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ class _AutoLinkMiddleware extends LevitReactiveMiddleware {
final captureList = Zone.current[_AutoLinkScope._captureKey];
if (captureList is List<LxReactive>) {
captureList.add(reactive);
} else {
assert(() {
// ignore: avoid_print
print(
'Levit: Reactive "${reactive.name ?? reactive.runtimeType}" '
'created inside an active capture scope but no capture list '
'found in current Zone. This may indicate the reactive was '
'created in a different Zone (e.g., runZonedGuarded). '
'Use autoDispose() to manually register it.',
);
return true;
}());
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/core/levit_dart_core/lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ part of '../levit_dart_core.dart';
/// Implementers should override [onInit] for setup and [onClose] for cleanup.
/// Use [autoDispose] to simplify resource management.
///
/// Example:
/// // Example usage:
/// ```dart
/// class CounterController extends LevitController {
/// final count = 0.lx;
Expand Down Expand Up @@ -109,7 +109,7 @@ abstract class LevitController implements LevitScopeDisposable {
///
/// Returns the [object] to allow inline use during initialization.
///
/// Example:
/// // Example usage:
/// ```dart
/// late final sub = autoDispose(stream.listen((_) {}));
/// ```
Expand Down
6 changes: 3 additions & 3 deletions packages/core/levit_dart_core/lib/src/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Levit {
/// Notifications are deferred until the batch completes, ensuring that
/// observers are only notified once even if multiple values change.
///
/// Example:
/// // Example usage:
/// ```dart
/// Levit.batch(() {
/// firstName.value = 'Jane';
Expand Down Expand Up @@ -97,7 +97,7 @@ class Levit {
/// The [builder] is executed immediately.
/// If [permanent] is true, the instance survives [reset].
///
/// Example:
/// // Example usage:
/// ```dart
/// final service = Levit.put(() => AuthService());
/// ```
Expand Down Expand Up @@ -128,7 +128,7 @@ class Levit {

/// Finds a registered instance of type [S].
///
/// Example:
/// // Example usage:
/// ```dart
/// final service = Levit.find<AuthService>();
/// ```
Expand Down
2 changes: 1 addition & 1 deletion packages/core/levit_dart_core/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: levit_dart_core
description: The core framework for pure Dart applications. Aggregates dependency injection and reactivity.
repository: https://github.com/softilab/levit
version: 0.0.6
version: 0.0.7
topics:
- state-management
- dependency-injection
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import 'dart:async';
import 'package:test/test.dart';
import 'package:levit_dart_core/levit_dart_core.dart';

void main() {
setUp(() {
Levit.enableAutoLinking();
});

tearDown(() {
Levit.reset(force: true);
Levit.disableAutoLinking();
});

group('AutoLinking Assertion Coverage', () {
test(
'prints warning when reactive created in active scope but without capture list in zone',
() {
// Capture printed output
final printLogs = <String>[];
final spec = ZoneSpecification(
print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
printLogs.add(line);
},
);

runZoned(() {
runCapturedForTesting(() {
// Now we are inside a capture scope (_activeCaptureScopes > 0)
// But we need to erase the captureKey from the Zone.
final erasedZone = Zone.current.fork(zoneValues: {
// Overwrite the capture list with null
autoLinkCaptureKeyForTesting: null,
});

erasedZone.run(() {
// Creating an LxInt here should trigger the specific assert.
0.lx.named('ErasedTestVar');
});
});
}, zoneSpecification: spec);

expect(
printLogs.any((line) => line.contains(
'created inside an active capture scope but no capture list')),
isTrue,
reason: 'Should have printed the missing capture list warning.',
);
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class InterceptController extends LevitController {
}

class TestController extends LevitController {
late final LxNum<int> count;
late final LxInt count;
late final LxComputed<int> doubled;

@override
Expand All @@ -153,7 +153,7 @@ class TestController extends LevitController {
}

class ParentController extends LevitController {
late final LxNum<int> parentValue;
late final LxInt parentValue;

@override
void onInit() {
Expand All @@ -163,7 +163,7 @@ class ParentController extends LevitController {
}

class ChildController extends LevitController {
late final LxNum<int> childValue;
late final LxInt childValue;

@override
void onInit() {
Expand All @@ -173,7 +173,7 @@ class ChildController extends LevitController {
}

class MultiReactiveController extends LevitController {
late final List<LxNum<int>> values;
late final List<LxInt> values;

@override
void onInit() {
Expand All @@ -183,7 +183,7 @@ class MultiReactiveController extends LevitController {
}

class IndexTestController extends LevitController {
late final List<LxNum<int>> values;
late final List<LxInt> values;

@override
void onInit() {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/levit_flutter_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

## Unreleased
## 0.0.7

### Breaking Changes
- Removed `LAsyncScopedView`; use explicit `LAsyncScope + LView` composition instead.
Expand Down
6 changes: 3 additions & 3 deletions packages/core/levit_flutter_core/lib/src/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ part of '../levit_flutter_core.dart';
/// Use [LBuilder] when you want to be explicit about the dependency, or when
/// avoiding the overhead of proxy-tracking in [LWatch].
///
/// Example:
/// // Example usage:
/// ```dart
/// LBuilder(counter, (value) {
/// return Text('Count: $value');
Expand Down Expand Up @@ -72,7 +72,7 @@ class _LBuilderElement<T> extends ComponentElement
/// widget subtree. The computed value is automatically disposed when the
/// widget is unmounted.
///
/// Example:
/// // Example usage:
/// ```dart
/// LSelectorBuilder(
/// () => user.firstName() + user.lastName(),
Expand Down Expand Up @@ -153,7 +153,7 @@ class _LSelectBuilderElement<T> extends ComponentElement
/// Eliminates boilerplate when handling loading, error, and success states
/// of an asynchronous reactive value.
///
/// Example:
/// // Example usage:
/// ```dart
/// LStatusBuilder(
/// userStatus,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/levit_flutter_core/lib/src/scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class _ScopeProvider extends InheritedWidget {
/// Use [LScope] to provide dependencies for a specific subtree.
/// The scope is automatically closed when the widget is unmounted.
///
/// Example:
/// // Example usage:
/// ```dart
/// LScope(
/// dependencyFactory: (scope) => scope.put(() => MyController()),
Expand Down Expand Up @@ -229,7 +229,7 @@ class _LScopeState extends State<LScope> {
/// Initializes the scope using an asynchronous [dependencyFactory] and
/// only renders [child] when initialization completes.
///
/// Example:
/// // Example usage:
/// ```dart
/// LAsyncScope(
/// dependencyFactory: (scope) async {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/levit_flutter_core/lib/src/scoped_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ part of '../levit_flutter_core.dart';
/// via [dependencyFactory], and then builds the UI using [LView].
/// When the widget is unmounted, the scope and all its dependencies are disposed.
///
/// Example:
/// // Example usage:
/// ```dart
/// LScopedView<ProfileController>.put(
/// () => ProfileController(),
Expand Down
2 changes: 1 addition & 1 deletion packages/core/levit_flutter_core/lib/src/watch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ part of '../levit_flutter_core.dart';
/// [LWatch] tracks which [LxReactive] values are accessed within its [builder]
/// and automatically triggers a rebuild when any of them change.
///
/// Example:
/// // Example usage:
/// ```dart
/// LWatch(() {
/// return Text('Count: ${controller.count()}');
Expand Down
2 changes: 1 addition & 1 deletion packages/core/levit_flutter_core/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: levit_flutter_core
description: Flutter widgets for the Levit framework - bridges reactive state and DI to the Flutter widget tree.
repository: https://github.com/softilab/levit
version: 0.0.6
version: 0.0.7
topics:
- flutter
- state-management
Expand Down
Loading