juice_routing 1.0.0 copy "juice_routing: ^1.0.0" to clipboard
juice_routing: ^1.0.0 copied to clipboard

Declarative, state-driven navigation for Juice applications with Navigator 2.0 integration, route guards, and deep linking support.

juice_routing #

Declarative, state-driven navigation for Juice applications with Navigator 2.0 integration, route guards, and deep linking.

pub package License: MIT

Features #

  • Declarative Routes - Define routes as configuration, not scattered push() calls
  • Route Guards - Async guards for auth, permissions, onboarding with redirect loop protection
  • Navigation Atomicity - Navigation either commits fully or not at all
  • Observable State - Current route, stack, params, pending navigation all in RoutingState
  • Navigator 2.0 - Full integration with Flutter's declarative navigation API
  • Deep Linking - Same path resolution for cold start, warm start, and in-app navigation

Installation #

dependencies:
  juice_routing: ^1.0.0

Quick Start #

1. Define Your Routes #

import 'package:juice_routing/juice_routing.dart';

final appRoutes = RoutingConfig(
  routes: [
    RouteConfig(
      path: '/',
      title: 'Home',
      builder: (ctx) => const HomeScreen(),
    ),
    RouteConfig(
      path: '/profile/:userId',
      title: 'Profile',
      builder: (ctx) => ProfileScreen(userId: ctx.params['userId']!),
      guards: [AuthGuard()],
    ),
    RouteConfig(
      path: '/settings',
      title: 'Settings',
      builder: (ctx) => const SettingsScreen(),
      guards: [AuthGuard()],
      children: [
        RouteConfig(
          path: 'account',
          builder: (ctx) => const AccountSettingsScreen(),
        ),
        RouteConfig(
          path: 'privacy',
          builder: (ctx) => const PrivacySettingsScreen(),
        ),
      ],
    ),
  ],
  notFoundRoute: RouteConfig(
    path: '/404',
    builder: (ctx) => const NotFoundScreen(),
  ),
);

2. Add Route Guards #

Use the built-in guards or create your own:

// Built-in guards (callback-based, no auth dependency)
AuthGuard(isAuthenticated: () => authBloc.state.isLoggedIn)
GuestGuard(isAuthenticated: () => authBloc.state.isLoggedIn)
RoleGuard(hasRole: () => userBloc.state.isAdmin, roleName: 'admin')

// Or create custom guards
class OnboardingGuard extends RouteGuard {
  @override
  String get name => 'OnboardingGuard';

  @override
  Future<GuardResult> check(RouteContext context) async {
    if (userBloc.state.hasCompletedOnboarding) {
      return const GuardResult.allow();
    }
    return const GuardResult.redirect('/onboarding');
  }
}

3. Initialize and Use #

import 'package:flutter/material.dart';
import 'package:juice/juice.dart';
import 'package:juice_routing/juice_routing.dart';

void main() {
  // Register RoutingBloc
  BlocScope.register<RoutingBloc>(
    () => RoutingBloc(),
    lifecycle: BlocLifecycle.permanent,
  );

  // Initialize with config
  final routingBloc = BlocScope.get<RoutingBloc>();
  routingBloc.send(InitializeRoutingEvent(config: appRoutes));

  runApp(MyApp(routingBloc: routingBloc));
}

class MyApp extends StatelessWidget {
  final RoutingBloc routingBloc;

  const MyApp({required this.routingBloc});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: JuiceRouterDelegate(routingBloc: routingBloc),
      routeInformationParser: const JuiceRouteInformationParser(),
    );
  }
}

4. Navigate #

final routingBloc = BlocScope.get<RoutingBloc>();

// Push a route
routingBloc.navigate('/profile/123');

// Replace current route
routingBloc.navigate('/home', replace: true);

// Pop
routingBloc.pop();

// Pop to root
routingBloc.popToRoot();

// Reset stack
routingBloc.resetStack('/login');

Route Guards #

Guards run automatically before navigation commits:

Result Behavior
GuardResult.allow() Navigation proceeds
GuardResult.redirect('/path') Redirects to another route
GuardResult.block('reason') Blocks navigation, stays on current route

Guards support:

  • Priority ordering - Lower priority runs first
  • Async operations - Token refresh, permission checks
  • Redirect loop protection - Max 5 redirects before error
Method Guards Run? Description
navigate(path) Yes Push new route
navigate(path, replace: true) Yes Replace current route
pop() No Go back one route
popToRoot() No Clear stack to root
popUntil(predicate) No Pop until condition met
resetStack(path) Yes Clear and start fresh

Observable State #

final state = routingBloc.state;

state.currentPath      // Current route path
state.stack            // Full navigation stack
state.stackDepth       // Number of routes in stack
state.canPop           // Whether pop is possible
state.isNavigating     // Guards currently running
state.history          // Navigation history
state.error            // Last navigation error

Rebuild Groups #

Subscribe to specific state changes:

Group Updates When
routing.stack Stack changes (push, pop, replace)
routing.current Current route changes
routing.pending Navigation in progress
routing.history History entry added
routing.error Navigation error occurred

Contract Guarantees #

Guarantee Behavior
Atomicity Navigation commits fully or not at all
Concurrency One pending navigation; new ones queue (latest wins)
Redirect cap Max 5 redirects before RedirectLoopError
Guard errors Exception becomes GuardExceptionError, navigation aborted
Pop behavior Pop events bypass guards, execute immediately

Documentation #

Example App #

See the example directory for a complete demo app showcasing:

  • Route configuration with guards
  • Navigation playground for testing all navigation types
  • Aviator pattern for loose coupling
  • History tracking and visualization

License #

MIT License - see LICENSE for details.

1
likes
150
points
179
downloads

Publisher

unverified uploader

Weekly Downloads

Declarative, state-driven navigation for Juice applications with Navigator 2.0 integration, route guards, and deep linking support.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#navigation #routing #bloc #state-management #flutter

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter, juice

More

Packages that depend on juice_routing