Build Status Build Status codecov

Features

Declaratively switch child widgets based on the current Router location.

class SideBar extends StatelessWidget {
    Widget build(_){
     return RoutedSwitcher(
        builders: (_) => [
            Routed('/', MainMenu.new), 
            Routed('/dashboard', DashboardMenu.new), 
        ]);
    }
}

Intended as a complimentary package for any Router (aka Nav2) implementation. Including popular routing solutions like GoRouter, RouteMaster or VRouter.

This is useful in 2 primary use cases:

  • when you have scaffolding around your Navigator, like a SideBar or a TitleBar and you would like it to react to location changes
  • when multiple paths resolve to the same Page and you want to move subsequent routing further down the tree

Note: This package does not provide any control of the routers location, it simply reads the current location and responds accordingly.

🔨 Installation

dependencies:
  routed_widget_switcher: ^2.0.1

🕹ī¸ Usage

Place the widget anywhere below the root Router widget and define the paths you would like to match. By default paths are considered to be case-insensitive, and treated as prefixes, but this can be disabled using the .exact extension method, or usePrefix: false setting.

All widgets are lazy loaded, and can be defined using a closure: () => MyPage or a constructor tear-off: MyPage.new:

return RoutedSwitcher(
  caseSensitive: true,
  builders: (info) => [
    // use '.exact' to match only '/'
    Routed('/', MainMenu.new).exact,
     // match anything prefixed with `/dashboard`
    Routed('/dashboard', DashboardMenu.new),
    // use the closure, so we can access query params
    Routed('/settings', () => SettingsMenu(type: info.queryParams['type'])),
  ],
);

As shown above, the builders delegate passes a RoutedInfo object which contains info about the current match. This includes:

  • url
  • matchingRoute
  • pathParams
  • queryParams

You can also call RoutedInfo.of(context) from any descendant widgets to access the info on demand.

Unknown routes

Use the unknownRouteBuilder to handle unexpected routes. If the delegate is not provided, a DefaultUnknownRoute widget will be used.

Path matching

Paths can be defined as simple strings like /user/new or user/:userId, or use regular expression syntax like r'/user/:id(\d+)'. See pathToRegExp library for more details on advanced use cases: https://pub.dev/packages/path_to_regexp.

In addition to the matching performed by pathToRegExp, a wildcard * character can be used to match any location.

Most specific match

RoutedSwitcher will attempt to use the most specific match. For example, the url /users/new matches all three of these builders:

Routed('/users/:userId', TeamDetails.new),
Routed('/users/new', NewTeamForm.new),
Routed('*', TeamStandings.new),

Since /users/new is the more exact match, it will be the one to render, it does not matter which order you declare them in. /users/:userId would go next, with the wildcard * finally matching last.

Transitions

Internally Flutters AnimatedSwitcher widget is used for transitions, so that full API is exposed for different transition effects.

return RoutedSwitcher(
  transitionBuilder: ...
  duration: ...,
  builders: ...,
)

Relative links and inheritance

Nested switchers are supported to any depth, and relative paths can be defined by omitting the / character.

return RoutedSwitcher(
  builders: (_) => [
    Routed(
      '/messages',
      () => RoutedSwitcher(
        builders: (_) => [
          Routed('', Inbox.new), // -> /messages/
          Routed('inbox', Inbox.new), // -> /messages/inbox
          Routed('outbox', Outbox.new), // -> /messages/outbox
        ],
      ),
    ),
  ],
);

🐞 Bugs/Requests

If you encounter any problems please open an issue. If you feel the library is missing a feature, please raise a ticket on Github and we'll look into it. Pull request are welcome.

📃 License

MIT License

Libraries

routed_widget_switcher