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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.3.1

* **Fix (Transitions & Pop Visibility)**: Prevented underlying screen from disappearing or flashing black during push and pop route transitions by eliminating destructive secondary opacity fading in `Scale`, `FadeScale`, and `SharedAxis` widgets.
* **Feat (Transitions)**: Added optional `fillColor` property support in `FadeThrough` transition widget.
* **Test**: Added integration test suite verifying that underlying screens remain visible and mounted throughout transition lifecycle during push and pop operations.

## 0.3.0

* **Feat (Transitions & Motion)**: Implemented modern **Material 3 Transitions** (`fade_through`, `fade_scale`, `shared_axis_x`, `shared_axis_y`, `shared_axis_z`, `scale`) and authentic **Cupertino iOS 16–18** transition (`slide_cupertino` with flat edges, 1/3 horizontal parallax, and left-edge drop shadow).
Expand Down
47 changes: 21 additions & 26 deletions example/lib/app_traces.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ enum AppPath {
/// event, bundling the path, arguments, and presentation (`TraceRoute`).
class AppTrace extends Trace {
/// Private constructor to be used by the factory constructors.
const new _({
required super.path,
super.args,
super.traceRoute,
});
const new _({required super.path, super.args, super.traceRoute});

/// Navigates to the push arguments screen.
factory toPushArgs({
Expand Down Expand Up @@ -86,27 +82,26 @@ class AppTrace extends Trace {
source: 'CustomBuildTransition',
),
traceRoute: PageTraceRoute(
customTransition: CustomBuildTransition(
({
required animation,
required secondaryAnimation,
required child,
}) {
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: Curves.easeOutBack,
);
return ScaleTransition(
scale: curvedAnimation,
child: RotationTransition(
turns: Tween<double>(begin: 0.85, end: 1).animate(
curvedAnimation,
),
child: child,
),
);
},
),
customTransition: CustomBuildTransition(({
required animation,
required secondaryAnimation,
required child,
}) {
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: Curves.easeOutBack,
);
return ScaleTransition(
scale: curvedAnimation,
child: RotationTransition(
turns: Tween<double>(
begin: 0.85,
end: 1,
).animate(curvedAnimation),
child: child,
),
);
}),
),
);
}
Expand Down
4 changes: 1 addition & 3 deletions example/lib/detail_args.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'package:browser_router/browser.dart';

final class DetailArgs extends RouteParams {
new({
required this.message,
});
new({required this.message});

final String message;

Expand Down
75 changes: 46 additions & 29 deletions example/lib/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ class _HomeScreenState extends State<HomeScreen> {
child: ListView(
children: [
// --- Material 3 Motion ---
const _SectionTitle(title: '✨ Material 3 Motion Transitions'),
const _SectionTitle(
title: '✨ Material 3 Motion Transitions',
),
_ExampleButton(
text: 'Fade Through (Top-Level Tabs / Bar)',
onTap: () => AppTrace.toPushArgs(
Expand Down Expand Up @@ -116,7 +118,9 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Apple Cupertino iOS Motion ---
const _SectionTitle(title: '🍎 iOS 16–18 Cupertino Native Motion'),
const _SectionTitle(
title: '🍎 iOS 16–18 Cupertino Native Motion',
),
_ExampleButton(
text: 'Slide Cupertino (Shadow + 1/3 Parallax)',
onTap: () => AppTrace.toPushArgs(
Expand All @@ -128,11 +132,14 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Web Micro-Transitions ---
const _SectionTitle(title: '🌐 Web Micro-Transitions (SPA)'),
const _SectionTitle(
title: '🌐 Web Micro-Transitions (SPA)',
),
_ExampleButton(
text: 'Fade Scale (Fast Zoom-Fade 0.95->1.0)',
onTap: () => AppTrace.toPushArgs(
message: 'Snappy SPA Zoom-Fade (0.95->1.0) with fastEasing',
message:
'Snappy SPA Zoom-Fade (0.95->1.0) with fastEasing',
source: 'Web Micro-Transition',
transition: RouteTransition.fade_scale,
).push(context),
Expand All @@ -150,7 +157,9 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Adaptive Transitions ---
const _SectionTitle(title: '📱 Platform-Adaptive Transition'),
const _SectionTitle(
title: '📱 Platform-Adaptive Transition',
),
_ExampleButton(
text: 'Browser.defaultAdaptiveTransition (Platform Auto-Detect)',
onTap: () {
Expand All @@ -161,7 +170,8 @@ class _HomeScreenState extends State<HomeScreen> {
),
);
AppTrace.toPushArgs(
message: 'Auto-detected adaptive transition: ${adaptive.name}',
message:
'Auto-detected adaptive transition: ${adaptive.name}',
source: 'Browser.defaultAdaptiveTransition',
transition: adaptive,
).push(context);
Expand All @@ -170,14 +180,20 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Presentations & Modals ---
const _SectionTitle(title: '🪟 Presentation (TraceRoute) Styles'),
const _SectionTitle(
title: '🪟 Presentation (TraceRoute) Styles',
),
_ExampleButton(
text: 'Present as Popup (Scale Transition)',
onTap: () => AppTrace.asPopup(transition: RouteTransition.scale).push(context),
onTap: () =>
AppTrace.asPopup(transition: RouteTransition.scale)
.push(context),
),
_ExampleButton(
text: 'Present as Popup (Fade Scale Transition)',
onTap: () => AppTrace.asPopup(transition: RouteTransition.fade_scale).push(context),
onTap: () => AppTrace.asPopup(
transition: RouteTransition.fade_scale,
).push(context),
),
_ExampleButton(
text: 'Present as Swipeable Bottom Sheet',
Expand All @@ -186,7 +202,9 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Legacy Presets ---
const _SectionTitle(title: '📦 Legacy Slide & Fade Presets'),
const _SectionTitle(
title: '📦 Legacy Slide & Fade Presets',
),
_ExampleButton(
text: 'Slide Right',
onTap: () => AppTrace.toPushArgs(
Expand Down Expand Up @@ -238,7 +256,9 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(height: 20),

// --- Argument Examples ---
const _SectionTitle(title: '🔗 Arguments & DeepLink Examples'),
const _SectionTitle(
title: '🔗 Arguments & DeepLink Examples',
),
_ExampleButton(
text: '1. Push with Typed Arguments',
onTap: () => AppTrace.toPushArgs(
Expand Down Expand Up @@ -289,26 +309,23 @@ class _HomeScreenState extends State<HomeScreen> {
const _SectionTitle(title: '📣 Overlay & Banners'),
_ExampleButton(
text: 'Enqueue Banner (Auto-dismiss 5s)',
onTap: () => Browser.enqueueBanner(
context,
(removableCallback) {
return const ColoredBox(
color: Color(0xFFF59E0B),
child: Padding(
padding: EdgeInsets.all(12),
child: Text(
'🔔 Real-time Notification Banner (Auto-closes in 5s)',
style: TextStyle(
color: Color(0xFF1E293B),
fontWeight: FontWeight.bold,
onTap: () =>
Browser.enqueueBanner(context, (removableCallback) {
return const ColoredBox(
color: Color(0xFFF59E0B),
child: Padding(
padding: EdgeInsets.all(12),
child: Text(
'🔔 Real-time Notification Banner (Auto-closes in 5s)',
style: TextStyle(
color: Color(0xFF1E293B),
fontWeight: FontWeight.bold,
),
textDirection: TextDirection.ltr,
),
textDirection: TextDirection.ltr,
),
),
);
},
topPadding: 0,
),
);
}, topPadding: 0),
),
_ExampleButton(
text: 'Enqueue Interactive Banner (Duration 0 + Close Button)',
Expand Down
5 changes: 4 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ class MyApp extends StatelessWidget {
onGenerateRoute: generate,
onGenerateInitialRoutes: (routePath) => [
generate(
RouteSettings(name: routePath, arguments: const <dynamic, dynamic>{}),
RouteSettings(
name: routePath,
arguments: const <dynamic, dynamic>{},
),
),
],
);
Expand Down
4 changes: 1 addition & 3 deletions example/lib/pop_args_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ class PopArgsScreen extends StatelessWidget {
GestureDetector(
onTap: () {
// Example 1: Pass arguments directly in pop()
context.pop(
args: PopResultArgs(result: 'Result from pop()'),
);
context.pop(args: PopResultArgs(result: 'Result from pop()'));
},
child: Container(
color: const Color(0xFFFFFFFF),
Expand Down
4 changes: 1 addition & 3 deletions example/lib/pop_result_args.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'package:browser_router/browser.dart';

final class PopResultArgs extends RouteParams {
new({
required this.result,
});
new({required this.result});

final String result;

Expand Down
5 changes: 1 addition & 4 deletions example/lib/push_args.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import 'package:browser_router/browser.dart';

final class PushArgs extends RouteParams {
const new({
required this.message,
required this.source,
});
const new({required this.message, required this.source});

final String message;
final String source;
Expand Down
6 changes: 4 additions & 2 deletions example/lib/push_args_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ class PushArgsScreen extends StatelessWidget {
child: Text(
'Message: "${args.message}"\n(From: ${args.source})',
textAlign: TextAlign.center,
style:
const TextStyle(color: Color(0xFFFFFFFF), fontSize: 18),
style: const TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 18,
),
textDirection: TextDirection.ltr,
),
),
Expand Down
10 changes: 2 additions & 8 deletions example/lib/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ final routes = [
return true;
},
),
BrowserRoute(
path: AppPath.popArgs.path,
page: const PopArgsScreen(),
),
BrowserRoute(path: AppPath.popArgs.path, page: const PopArgsScreen()),
BrowserRoute(
path: AppPath.toSetPopArgs.path,
page: const ToSetPopArgsScreen(),
Expand All @@ -39,8 +36,5 @@ final routes = [
path: AppPath.intermediate.path,
page: const IntermediateScreen(),
),
BrowserRoute(
path: AppPath.deep.path,
page: const DeepScreen(),
),
BrowserRoute(path: AppPath.deep.path, page: const DeepScreen()),
];
Loading
Loading