{"id":13548616,"url":"https://github.com/woltapp/wolt_modal_sheet","last_synced_at":"2025-04-02T21:32:03.404Z","repository":{"id":179151573,"uuid":"651571678","full_name":"woltapp/wolt_modal_sheet","owner":"woltapp","description":"This package provides a responsive modal with multiple pages, motion animation for page transitions, and scrollable content within each page.","archived":false,"fork":false,"pushed_at":"2024-10-17T11:48:42.000Z","size":46032,"stargazers_count":488,"open_issues_count":38,"forks_count":65,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-10-19T15:35:45.020Z","etag":null,"topics":["dart","flutter","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/woltapp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-09T14:35:25.000Z","updated_at":"2024-10-18T05:48:48.000Z","dependencies_parsed_at":"2023-10-15T09:12:52.443Z","dependency_job_id":"326197ce-a4e4-47d6-aabe-f80c53f10832","html_url":"https://github.com/woltapp/wolt_modal_sheet","commit_stats":null,"previous_names":["woltapp/wolt_modal_sheet"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woltapp%2Fwolt_modal_sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woltapp%2Fwolt_modal_sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woltapp%2Fwolt_modal_sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/woltapp%2Fwolt_modal_sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/woltapp","download_url":"https://codeload.github.com/woltapp/wolt_modal_sheet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246895851,"owners_count":20851338,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","flutter","hacktoberfest"],"created_at":"2024-08-01T12:01:12.456Z","updated_at":"2025-04-02T21:31:58.396Z","avatar_url":"https://github.com/woltapp.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://wolt.com/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Powered%20by-Wolt-blue.svg\" alt=\"Wolt\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet/publisher\"\u003e\u003cimg src=\"https://img.shields.io/pub/publisher/wolt_modal_sheet.svg\" alt=\"Wolt on pub.dev\"\u003e\u003c/a\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet\"\u003e\u003cimg src=\"https://badgen.net/pub/flutter-platform/wolt_modal_sheet\" alt=\"Platforms\"\u003e\u003c/a\u003e\n    \u003cbr\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet\"\u003e\u003cimg src=\"https://img.shields.io/pub/v/wolt_modal_sheet?logo=dart\u0026logoColor=white\" alt=\"Pub Version\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet\"\u003e\u003cimg src=\"https://badgen.net/pub/points/wolt_modal_sheet\" alt=\"Pub points\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet\"\u003e\u003cimg src=\"https://badgen.net/pub/likes/wolt_modal_sheet\" alt=\"Pub Likes\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pub.dev/packages/wolt_modal_sheet\"\u003e\u003cimg src=\"https://badgen.net/pub/popularity/wolt_modal_sheet\" alt=\"Pub popularity\"\u003e\u003c/a\u003e\n    \u003cbr\u003e    \n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/woltapp/wolt_modal_sheet?style=social\" alt=\"Repo stars\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet/commits/main\"\u003e\u003cimg src=\"https://img.shields.io/github/last-commit/woltapp/wolt_modal_sheet/main?logo=git\" alt=\"Last Commit\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet/pulls\"\u003e\u003cimg src=\"https://img.shields.io/github/issues-pr/woltapp/wolt_modal_sheet\" alt=\"Repo PRs\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet/issues?q=is%3Aissue+is%3Aopen\"\u003e\u003cimg src=\"https://img.shields.io/github/issues/woltapp/wolt_modal_sheet\" alt=\"Repo issues\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet/graphs/contributors\"\u003e\u003cimg src=\"https://badgen.net/github/contributors/woltapp/wolt_modal_sheet\" alt=\"Contributors\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/woltapp/wolt_modal_sheet/blob/main/LICENSE\"\u003e\u003cimg src=\"https://badgen.net/github/license/woltapp/wolt_modal_sheet\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003cbr\u003e       \n    \u003ca href=\"https://app.codecov.io/gh/woltapp/wolt_modal_sheet\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/woltapp/wolt_modal_sheet?logo=codecov\u0026logoColor=white\" alt=\"Coverage Status\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# WoltModalSheet\n\nWoltModalSheet is designed to revolutionize the use of modal sheets in \nFlutter apps. Built with Wolt-grade design quality and used extensively\nin [Wolt](https://wolt.com/) products, this UI component offers a visually \nappealing and highly customizable modal sheets with multiple pages, motion \nfor page transitions, and scrollable content within each page.\n\n- [Usage](#usage)\n  * [Basic Starter App](#basic-starter-app)\n  * [Basic Multi Page Example app](#basic-multi-page-example-app)\n  * [Playground app with imperative navigation](#playground-app-with-imperative-navigation)\n  * [Playground app with declarative navigation](#playground-app-with-declarative-navigation)\n  * [Coffee maker app for state management example](#coffee-maker-app-for-state-management-example)\n  * [CupertinoApp support](#cupertinoapp-support)\n- [Features](#features)\n  * [Multi-Page Layout](#multi-page-layout)\n  * [Scrollable Content](#scrollable-content)\n  * [Responsive Design](#responsive-design)\n  * [Custom Modal Types](#custom-modal-types)\n  * [Motion](#motion)\n  * [Imperative and Declarative Navigation](#imperative-and-declarative-navigation)\n  * [Dynamic Pagination](#dynamic-pagination)\n  * [State Management Integration](#state-management-integration)\n- [Modal Types](#modal-types)\n  * [Defining Custom Modal Types](#defining-custom-modal-types)\n  * [Modal Type Responsiveness](#modal-type-responsiveness)\n- [Decorating modal types, modal, and pages](#decorating-modal-types-modal-and-pages)\n  * [Decoration Approaches](#decoration-approaches)\n    + [Modal Type Level Decoration](#modal-type-level-decoration)\n    + [Modal Level Decoration](#modal-level-decoration)\n  * [Types of Decoration](#types-of-decoration)\n    + [Page Content Decoration](#page-content-decoration)\n    + [Modal Decoration](#modal-decoration)\n      - [Why use modalDecorator for state management?](#why-use-modaldecorator-for-state-management)\n  * [Migration to v0.8.0](#migration-to-v080)\n- [Usage of WoltModalSheet Pages](#usage-of-woltmodalsheet-pages)\n  * [SliverWoltModalSheetPage](#sliverwoltmodalsheetpage)\n  * [WoltModalSheetPage](#woltmodalsheetpage)\n  * [NonScrollingWoltModalSheetPage](#nonscrollingwoltmodalsheetpage)\n- [In-Modal Navigation](#in-modal-navigation)\n  * [Managing Navigation Stack](#managing-navigation-stack)\n    + [Adding Pages to the Stack](#adding-pages-to-the-stack)\n    + [Modifying Existing Pages](#modifying-existing-pages)\n      - [Replace a specific page](#replace-a-specific-page)\n      - [Replace or update the current page](#replace-or-update-the-current-page)\n      - [Remove a specific page](#remove-a-specific-page)\n      - [Add or replace pages](#add-or-replace-pages)\n  * [Navigation Between Pages](#navigation-between-pages)\n    + [Direct navigation](#direct-navigation)\n    + [Pushing Pages](#pushing-pages)\n    + [Popping Page](#popping-page)\n  * [Dynamic Navigation with ValueNotifiers](#dynamic-navigation-with-valuenotifiers)\n    + [Navigation by Page Index Notifier](#navigation-by-page-index-notifier)\n    + [Dynamic Page List Management by Page List Builder Notifier](#dynamic-page-list-management-by-page-list-builder-notifier)\n- [Design Guidelines](#design-guidelines)\n  * [Overview](#overview)\n  * [Breakpoints](#breakpoints)\n  * [Modal Types](#modal-types)\n    + [Alert Dialog](#alert-dialog)\n    + [Dialog](#dialog)\n    + [Side Sheet](#side-sheet)\n    + [Bottom Sheet](#bottom-sheet)\n- [Understanding the page elements](#understanding-the-page-elements)\n  * [Navigation bar widgets](#navigation-bar-widgets)\n  * [Top bar and top bar title](#top-bar-and-top-bar-title)\n  * [Sticky action bar (SAB)](#sticky-action-bar-sab)\n  * [Hero image](#hero-image)\n  * [Page Title](#page-title)\n  * [Main content](#main-content)\n- [Designer's Collaboration Guide](#designer-collaboration-guide)\n  * [What's Inside the Figma File](#what-is-inside-the-figma-file)\n- [Customizable Animations](#customizable-animations)\n  * [Default Animation Style Specifications](#default-animation-style-specifications)\n    + [Pagination Animation](#pagination-animation)\n    + [Scrolling Animation](#scrolling-animation)\n  * [Example Configuration](#example-configuration)\n- [Additional information](#additional-information)\n\n\n## Usage\n\nThis package includes five example projects, but if you're looking to get a quick feel for it, check out the basic starter app.\n\n\u003e Besides the \"Basic Starter App,\" be sure to clone the related example repository to get a feel for the fully functioning samples.\n\n### Basic Starter App\n\nInstall the library to your project by running: \n\n```bash\nflutter pub add wolt_modal_sheet\n```\n\nAfterwards, if you copy and paste following code to your `main.dart` file and run it, it will help you get started:\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:wolt_modal_sheet/wolt_modal_sheet.dart';\n\nvoid main() {\n  runApp(\n    const WoltModalSheetApp(),\n  );\n}\n\nclass WoltModalSheetApp extends StatelessWidget {\n  const WoltModalSheetApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const MaterialApp(\n      home: WoltModalSheetHomePage(),\n    );\n  }\n}\n\nclass WoltModalSheetHomePage extends StatelessWidget {\n  const WoltModalSheetHomePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: const Text('Wolt Modal Bottom Sheet Sample'),\n      ),\n      floatingActionButton: FloatingActionButton.extended(\n        onPressed: () {\n          WoltModalSheet.show(\n            context: context,\n            pageListBuilder: (bottomSheetContext) =\u003e [\n              SliverWoltModalSheetPage(\n                mainContentSliversBuilder: (context) =\u003e [\n                  SliverList.builder(\n                    itemBuilder: (context, index) {\n                      return ListTile(\n                        title: Text('Index is $index'),\n                        onTap: Navigator.of(bottomSheetContext).pop,\n                      );\n                    },\n                  ),\n                ],\n              )\n            ],\n          );\n        },\n        label: const Text('Trigger Wolt Sheet'),\n      ),\n    );\n  }\n}\n```\n\nThe code above will show you the screen below:\n\n\u003cimg src=\"https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/basic_app_screenshot.png?raw=true\" alt=\"WoltModalSheet with an endless list of items indicating the index of each item.\" width=\"280\"/\u003e\n\n### Basic Multi Page Example app\n\nThe [example](./example/) app demonstrates how to display a two-pages modal\nsheet that can be customized for dark and light themes\nusing [WoltModalSheetThemeData](./lib/src/theme/wolt_modal_sheet_theme_data.dart) theme\nextension.\n\n```dart\n@override\nWidget build(BuildContext context) {\n  SliverWoltModalSheetPage page1(BuildContext modalSheetContext, TextTheme textTheme) {\n    return WoltModalSheetPage(\n      hasSabGradient: false,\n      stickyActionBar: Padding(\n        padding: const EdgeInsets.all(_pagePadding),\n        child: Column(\n          children: [\n            ElevatedButton(\n              onPressed: Navigator.of(modalSheetContext).pop,\n              child: const SizedBox(\n                height: _buttonHeight,\n                width: double.infinity,\n                child: Center(child: Text('Cancel')),\n              ),\n            ),\n            const SizedBox(height: 8),\n            ElevatedButton(\n              onPressed: WoltModalSheet.of(modalSheetContext).showNext,\n              child: const SizedBox(\n                height: _buttonHeight,\n                width: double.infinity,\n                child: Center(child: Text('Next page')),\n              ),\n            ),\n          ],\n        ),\n      ),\n      topBarTitle: Text('Pagination', style: textTheme.titleSmall),\n      isTopBarLayerAlwaysVisible: true,\n      trailingNavBarWidget: IconButton(\n        padding: const EdgeInsets.all(_pagePadding),\n        icon: const Icon(Icons.close),\n        onPressed: Navigator.of(modalSheetContext).pop,\n      ),\n      child: const Padding(\n              padding: EdgeInsets.fromLTRB(\n                _pagePadding,\n                _pagePadding,\n                _pagePadding,\n                _bottomPaddingForButton,\n              ),\n              child: Text(\n                '''\nPagination involves a sequence of screens the user navigates sequentially. We chose a lateral motion for these transitions. When proceeding forward, the next screen emerges from the right; moving backward, the screen reverts to its original position. We felt that sliding the next screen entirely from the right could be overly distracting. As a result, we decided to move and fade in the next page using 30% of the modal side.\n''',\n              )),\n    );\n  }\n\n  SliverWoltModalSheetPage page2(BuildContext modalSheetContext, TextTheme textTheme) {\n    return SliverWoltModalSheetPage(\n      pageTitle: Padding(\n        padding: const EdgeInsets.all(_pagePadding),\n        child: Text(\n          'Material Colors',\n          style: textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold),\n        ),\n      ),\n      heroImage: Image(\n        image: NetworkImage(\n          'https://raw.githubusercontent.com/woltapp/wolt_modal_sheet/main/example/lib/assets/images/material_colors_hero${_isLightTheme ? '_light' : '_dark'}.png',\n        ),\n        fit: BoxFit.cover,\n      ),\n      leadingNavBarWidget: IconButton(\n        padding: const EdgeInsets.all(_pagePadding),\n        icon: const Icon(Icons.arrow_back_rounded),\n        onPressed: WoltModalSheet.of(modalSheetContext).showPrevious,\n      ),\n      trailingNavBarWidget: IconButton(\n        padding: const EdgeInsets.all(_pagePadding),\n        icon: const Icon(Icons.close),\n        onPressed: Navigator.of(modalSheetContext).pop,\n      ),\n      mainContentSliversBuilder: (context) =\u003e [\n        SliverGrid(\n          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(\n            crossAxisCount: 2,\n            mainAxisSpacing: 10.0,\n            crossAxisSpacing: 10.0,\n            childAspectRatio: 2.0,\n          ),\n          delegate: SliverChildBuilderDelegate(\n                    (_, index) =\u003e ColorTile(color: materialColorsInGrid[index]),\n            childCount: materialColorsInGrid.length,\n          ),\n        ),\n        SliverList(\n          delegate: SliverChildBuilderDelegate(\n                    (_, index) =\u003e ColorTile(color: materialColorsInSliverList[index]),\n            childCount: materialColorsInSliverList.length,\n          ),\n        ),\n      ],\n    );\n  }\n\n  return MaterialApp(\n    themeMode: _isLightTheme ? ThemeMode.light : ThemeMode.dark,\n    theme: ThemeData.light().copyWith(\n      extensions: const \u003cThemeExtension\u003e[\n        WoltModalSheetThemeData(\n          heroImageHeight: _heroImageHeight,\n          topBarShadowColor: _lightThemeShadowColor,\n          modalBarrierColor: Colors.black54,\n          mainContentScrollPhysics: ClampingScrollPhysics(),\n        ),\n      ],\n    ),\n    darkTheme: ThemeData.dark().copyWith(\n      extensions: const \u003cThemeExtension\u003e[\n        WoltModalSheetThemeData(\n          topBarShadowColor: _darkThemeShadowColor,\n          modalBarrierColor: Colors.white12,\n          sabGradientColor: _darkSabGradientColor,\n          mainContentScrollPhysics: ClampingScrollPhysics(),\n        ),\n      ],\n    ),\n    home: Scaffold(\n      body: Builder(\n        builder: (context) {\n          return Column(\n            mainAxisAlignment: MainAxisAlignment.center,\n            children: [\n              Row(...),\n              ElevatedButton(\n                onPressed: () {\n                  WoltModalSheet.show\u003cvoid\u003e(\n                    context: context,\n                    pageListBuilder: (modalSheetContext) {\n                      final textTheme = Theme.of(context).textTheme;\n                      return [\n                        page1(modalSheetContext, textTheme),\n                        page2(modalSheetContext, textTheme),\n                      ];\n                    },\n                    modalTypeBuilder: (context) {\n                      final size = MediaQuery.sizeOf(context).width;\n                      if (size \u003c _pageBreakpoint) {\n                        return WoltModalType.bottomSheet();\n                      } else {\n                        return WoltModalType.dialog();\n                      }\n                    },\n                    onModalDismissedWithBarrierTap: () {\n                      debugPrint('Closed modal sheet with barrier tap');\n                      Navigator.of(context).pop();\n                    },\n                  );\n                },\n                child: const SizedBox(\n                  height: _buttonHeight,\n                  width: _buttonWidth,\n                  child: Center(child: Text('Show Modal Sheet')),\n                ),\n              ),\n            ],\n          );\n        },\n      ),\n    ),\n  );\n}\n```\n\nThe example project above will create the following:\n\u003c/br\u003e\n\u003c/br\u003e\n\n![Example app](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/example_wms_demo.gif?raw=true)\n\n### Playground app with imperative navigation\n\nThe playground app ([source code](https://github.com/woltapp/wolt_modal_sheet/tree/main/playground), [web app](https://playgroundwoltexample.web.app))\ndemonstrates how to imperatively show the\nmodal sheet. The purpose of this module is to play and experiment with various\nuse cases.\n\n### Playground app with declarative navigation\n\nThe playground_navigator2 app ([source code](https://github.com/woltapp/wolt_modal_sheet/tree/main/playground_navigator2), [web app](https://playgroundnavigator2woltexample.web.app)) has the similar content with\nthe [playground](./playground/) app but the modal sheet is shown using \nNavigator 2.0 (Router API) in a declarative way.\n\n### Coffee maker app for state management example\n\nThe coffee_maker app ([source code](https://github.com/woltapp/wolt_modal_sheet/tree/main/coffee_maker), [web app](https://coffeemakerexample.web.app)) demonstrates how to manage the state among the page components with an opinionated use of the Provider state\nmanagement library.\n\nThe following code snippet demonstrates how to decorate the modal sheet with a change\nnotifier provider so that the page components can be rebuilt according to the\ncurrent state:\n\n```dart\n  void _onCoffeeOrderSelectedInAddWaterState(\n      BuildContext context, String coffeeOrderId) {\n    final model = context.read\u003cStoreOnlineViewModel\u003e();\n\n    WoltModalSheet.show(\n      context: context,\n      pageContentDecorator: (child) {\n        return ChangeNotifierProvider\u003cStoreOnlineViewModel\u003e.value(\n          value: model,\n          builder: (_, __) =\u003e child,\n        );\n      },\n      pageListBuilder: (context) {\n        return [\n          AddWaterDescriptionModalPage.build(coffeeOrderId),\n          WaterSettingsModalPage.build(coffeeOrderId)\n        ];\n      },\n      modalTypeBuilder: _modalTypeBuilder,\n    );\n  }\n```\n\n![Dynamic pagination in action in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_coffee_maker.gif?raw=true)\n\n### Coffee maker app with Navigator 2.0\n\nThe coffee_maker_navigator2 ([source code](https://github.com/woltapp/wolt_modal_sheet/tree/main/coffee_maker_navigator_2), [web app](https://coffeemakernavigator2.web.app)) app demonstrates how to manage app navigation including the modal sheet with Navigator 2.0 by \napplying the MVVM pattern with the Provide state management package.\n\n### CupertinoApp support\n\nIn the package, certain Material widgets rely on retrieving Material localizations information\nfrom the widget tree. However, Material localizations are not inherently available in CupertinoApp,\nleading to potential errors. To mitigate this issue, if your application utilizes CupertinoApp\nrather than MaterialApp, it is needed to incorporate a default Material localization delegate\ninto your application configuration.\n\n```dart\nCupertinoApp(\n  localizationsDelegates: const \u003cLocalizationsDelegate\u003cdynamic\u003e\u003e[DefaultMaterialLocalizations.delegate],\n)\n```\nTo see its usage, please check [coffee maker example app](coffee_maker/lib/main.dart).\n\n## Features\n\n### Multi-Page Layout\n\nTraverse through numerous pages within a single sheet.\n\n![Experience multi-page navigation in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_multi.gif?raw=true)\n\n### Scrollable Content\n\nEasily accommodates large content by using scrollable pages.\n\n![Scroll with ease in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_scrolling.gif?raw=true)\n\n### Responsive Design\n\nThe modal sheet is responsive, appearing as a dialog or side sheet on large \nscreens and as a bottom sheet on small screens, guided by user-specified \nconditions.\n\n![Adaptability to different screen sizes in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_type_builder.gif?raw=true)\n\n### Custom Modal Types\n\nThe package offers four customizable modal types: bottom sheet, dialog, side \nsheet, and alert dialog. It also supports creating entirely custom modal types.\n\n![Custom modal types in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_custom_modals.gif?raw=true)\n\n### Motion\n\nEngage users with dynamic motion for page transitions and scrolling.\n\n| Pagination                                                                                                 | Scrolling                                                                                             |\n| ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |\n| ![Pagination](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_motion_pagination.gif?raw=true) | ![Scrolling](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_scroll_motion.gif?raw=true) |\n\n### Imperative and Declarative Navigation\n\nThe package showcases examples of both imperative and declarative navigation\npatterns to display modal sheet on screen.\n\n![Illustration of imperative and declarative navigation in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_navigator_2.gif?raw=true)\n\n### Dynamic Pagination\n\nUser input can dynamically shape the modal sheet's page list.\n\n![Dynamic pagination in action in WoltModalSheet](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_dynamic_pagination.gif?raw=true)\n\n### State Management Integration\n\nPages in the Wolt Modal Sheet offer a customizable look. The page components \nare provided with an instance of WoltModalSheetPage class. The API provides a\nway to manage the state among the page components to be used with popular \nlibraries such as Bloc and Provider.\n\u003c/br\u003e\n\u003c/br\u003e\n\n## Modal Types\n\nThe WoltModalSheet package provides four modal types which can be \ninstantiated as follows:\n- Bottom sheet: `WoltBottomSheetType()` or `WoltModalType.bottomSheet()`   \n- Dialog: `WoltDialogType()` or `WoltModalType.dialog()`\n- Side sheet: `WoltSideSheetType()` or `WoltModalType.sideSheet()`\n- Alert dialog: `WoltAlertDialogType()` or `WoltModalType.alertDialog()` \n\nThese modal types are designed according to the Wolt design system specs and \ncan be customized to suit your application's design language by extending \nthese classes. For example:\n\n```dart\nclass MyCustomBottomSheetType extends WoltBottomSheetType {\n  const MyCustomBottomSheetType()\n      : super(\n          shapeBorder: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),\n          showDragHandle: false,\n          barrierDismissible: false,\n        );\n}\n```\n\nAlternatively, you can change the modal properties with the `copyWith method:\n\n```dart\nWoltModalSheet.show(\n  context: context,\n  modalTypeBuilder: (_) =\u003e WoltModalType.bottomSheet().copyWith(barrierDismissible: false),\n);\n```\n\n### Defining Custom Modal Types\n\nCustom modal types can be defined by extending the abstract `WoltModalType` \nclass. This approach allows you to create modal types that align with your \ndesign language and application requirements. \n\nTo define a custom modal type, you need to override the following methods:\n- `routeLabel`: Provides an accessibility label for the modal.\n- `layoutModal`: Returns the constraints for the modal layout.\n- `positionModal`: Returns the offset for the modal position from the \n  top-left corner of the route screen.\n- `buildTransitions`: Allows defining custom animation effects for the modal's \n  entry and exit.\n\nAdditionally, you can override the following properties:\n- `shapeBorder`: Defines the shape of the modal.\n- `dismissDirection`: Specifies the direction in which the modal can be \n  dismissed. The dismiss direction can be set to `up`, `down`, `startToEnd`, \n  or `endToStart`.\n- `showDragHandle`: Determines whether the modal displays a drag handle on top.\n- `closeProgressThreshold`: Sets the threshold for closing the modal.\n- `barrierDismissible`: Determines whether the modal can be dismissed by \n  tapping outside the modal.\n- `enableDrag`: Enables or disables dragging the modal.\n- `minFlingVelocity`: Sets the minimum fling velocity required for a drag \n  gesture to be considered a fling.\n- `transitionDuration` and `reverseTransitionDuration`: Specifies the \n  duration of the modal's entry and exit animations.\n- `forceMaxHeight`: Forces the modal content to have a maximum height. \n  Useful for modal types such as side sheets.\n\nExample:\n\n```dart\nclass TopNotificationSheetType extends WoltModalType {\n  final EdgeInsetsDirectional padding;\n\n  const TopNotificationSheetType({\n    this.padding = const EdgeInsetsDirectional.all(32.0),\n  }) : super(\n          shapeBorder: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),\n          dismissDirection: WoltModalDismissDirection.up,\n          showDragHandle: false,\n          closeProgressThreshold: 0.8,\n          barrierDismissible: false,\n        );\n\n  @override\n  String routeLabel(BuildContext context) {\n    final MaterialLocalizations localizations = MaterialLocalizations.of(context);\n    return localizations.dialogLabel;\n  }\n\n  @override\n  BoxConstraints layoutModal(Size availableSize) {\n    final availableWidth = availableSize.width;\n    double width = availableWidth \u003e 523.0 ? 312.0 : availableWidth - padding.end;\n    return BoxConstraints(\n      minWidth: width,\n      maxWidth: width,\n      minHeight: 0,\n      maxHeight: availableSize.height * 0.6,\n    );\n  }\n\n  @override\n  Offset positionModal(\n      Size availableSize, Size modalContentSize, TextDirection textDirection) {\n    final xOffset = max(0.0, (availableSize.width - modalContentSize.width) / 2);\n    final yOffset = padding.top;\n    return Offset(xOffset, yOffset);\n  }\n\n  @override\n  Widget buildTransitions(\n    BuildContext context,\n    Animation\u003cdouble\u003e animation,\n    Animation\u003cdouble\u003e secondaryAnimation,\n    Widget child,\n  ) {\n    final alphaAnimation = Tween\u003cdouble\u003e(\n      begin: 0.0,\n      end: 1.0,\n    ).animate(CurvedAnimation(\n      parent: animation,\n      curve: const Interval(0.0, 100.0 / 300.0, curve: Curves.linear),\n      reverseCurve: const Interval(100.0 / 250.0, 1.0, curve: Curves.linear),\n    ));\n\n    return FadeTransition(\n      opacity: alphaAnimation,\n      child: SlideTransition(\n        position: animation.drive(\n          Tween(\n            begin: const Offset(0.0, -1.0),\n            end: Offset.zero,\n          ).chain(CurveTween(curve: Curves.easeOutQuad)),\n        ),\n        child: child,\n      ),\n    );\n  }\n}\n```\n\nThe above code creates this custom modal type:\n\n![Custom modal type](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_custom_modal_type.gif?raw=true)\n\n### Modal Type Responsiveness\n\nThe modal types are designed to be responsive, adapting to different screen \nsizes. The modal type's layout, position, and animation can be customized \ndynamically based on the available screen size.\n\n```dart\nWoltModalSheet.show(\n  context: context,\n  modalTypeBuilder: (BuildContext context) {\n    final width = MediaQuery.sizeOf(context).width;\n    if (width \u003c 523) {\n      return WoltModalType.bottomSheet();\n    } else if (width \u003c 800) {\n      return WoltModalType.dialog();\n    } else {\n      return WoltModalType.sideSheet();\n    },\n    ...\n},\n```\nThe above code snippet produces the following modal types based on the\ndynamical screen width:\n\n![Responsive modals](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/ss_type_builder.gif?raw=true)\n\n## Decorating modal types, modal, and pages\nWoltModalSheet uses the decorator pattern, which is a structural design \npattern allowing dynamic addition of behavior to individual objects. In \nFlutter, this is typically achieved by wrapping widgets with other widgets \nto enhance or modify their behavior.\n\n### Decoration Approaches\n\nDecoration can be achieved at both the modal type level and the modal level.\n\n#### Modal Type Level Decoration\n\nThe modal type level decoration is applied to all modals of the same type. \nTo decorate at the modal type level, the corresponding `WoltModalType` class \nshould be extended and the related methods should be overridden.\n\nExample:\n\n```dart\nclass MyCustomBottomSheetType extends WoltBottomSheetType {\n  const MyCustomBottomSheetType() : super();\n\n  @override\n  Widget decoratePageContent(BuildContext context, Widget child, bool useSafeArea) {\n    return Padding(\n      padding: const EdgeInsets.all(16.0),\n      child: child,\n    );\n  }\n\n  @override\n  Widget decorateModal(BuildContext context, Widget modal, bool useSafeArea) {\n    return useSafeArea ? SafeArea(child: modal) : modal;\n  }\n}\n```\n\n#### Modal Level Decoration\n\nDecoration at the modal level is applied when using the modal and can be \napplied to all modal types when the modal sheet is visible. This is done \nthrough the `pageContentDecorator` and `modalDecorator`.\n\nExample:\n\n```dart\nWoltModalSheet.show(\n  context: context,\n  pageContentDecorator: (widget) =\u003e Align(\n      alignment: Alignment.bottomCenter,\n      child: ClipRRect(\n        ..., // Your clipRRect properties\n        child: BackdropFilter(\n          ..., // Your backdrop filter properties\n          child: widget,\n        ),\n    ),\n  ),\n  modalDecorator: (child) {\n    // Wrap the modal with `ChangeNotifierProvider` to manage the state of \n    // the entire pages in the modal.\n    return ChangeNotifierProvider\u003cStoreOnlineViewModel\u003e(\n      builder: (_, __) =\u003e StoreOnlineViewModel(),\n      child: child,\n    );\n  },\n  pageListBuilder: (context) {\n    final viewModel = context.read\u003cStoreOnlineViewModel\u003e();\n    return [\n      WoltModalSheetPage(\n        child: FirstPageContent(viewModel.data),\n        pageTitle: Text('First Page Title'),\n        // Other properties...\n      ),\n      WoltModalSheetPage(\n        child: SecondPageContent(viewModel.data),\n        pageTitle: Text('Second Page Title'),\n        // Other properties...\n      ),\n    ];\n  },\n);\n```\n\n### Types of Decoration\n\n#### Page Content Decoration\n\n- Purpose: Applies additional decorations to the modal page content only, \n  excluding the barrier.\n- Usage: Useful for modifying or enhancing the appearance and behavior of \n  the modal content without affecting the surrounding barrier and the \n  placement of the modal on the screen.\n\n```dart\nWidget Function(Widget)? pageContentDecorator;\n```\n\n#### Modal Decoration\n\n- Purpose: Applies additional decorations to the entire modal, including the \n  barrier and the page content.\n- Usage: Useful for wrapping the entire modal with a widget that manages the \n  state of the entire pages.\n\n```dart\nWidget Function(Widget)? modalDecorator;\n```\n\n##### Why use modalDecorator for state management?\n\nWhen managing the state across the entire modal, for example by providing a \n[ChangeNotifierProvider](https://pub.dev/documentation/provider/latest/provider/ChangeNotifierProvider-class.html) for state management, it is important to wrap the\nentire modal rather than just the page content. This ensures that the state\nis accessible throughout the entire modal lifecycle and all its components.\n\n### Migration to v0.8.0\n\nVersions before the v0.6.0 release used the `decorator` field to decorate as \n`modalDecorator`. In release v0.6.0 and later, the `decorator` field was \nused as `pageContentDecorator`. In v0.8.0, the `decorator` field was removed \nand replaced with `pageContentDecorator` and `modalDecorator`.\n\n## Usage of WoltModalSheet Pages\n\nThe WoltModalSheet library provides three primary classes for constructing \nmodal sheet pages: `WoltModalSheetPage`, `SliverWoltModalSheetPage`, and \n`NonScrollingWoltModalSheetPage`.\n\n### SliverWoltModalSheetPage\n\n`SliverWoltModalSheetPage` is designed for layouts requiring the use of \n`Sliver` widgets, such as lists, grids, and other scrollable content within \na modal sheet.\n\n```dart\nSliverWoltModalSheetPage(\n  mainContentSliversBuilder: (context) =\u003e [\n    SliverList(\n      delegate: SliverChildBuilderDelegate((BuildContext context, int index) {\n        // Your list items\n      }),\n    ),\n    // Other sliver widgets...\n  ],\n  // Additional page elements like pageTitle, topBarTitle, etc.\n)\n```\n\n### WoltModalSheetPage\n\nWoltModalSheetPage simplifies the process of creating modal sheet pages \nwithout needing to deal with slivers directly. This class is ideal for \nstraightforward widgets that don't require the advanced capabilities of \nslivers and are not lazily built.\n\n ```dart\nWoltModalSheetPage(\n  child: MyCustomContentWidget(),\n  pageTitle: Text('My Page Title'),\n  // Other properties...\n)\n ```\n\n### NonScrollingWoltModalSheetPage\n\n`NonScrollingWoltModalSheetPage` is designed to display content which is \nflexible in height but unlikely to require scrolling. This class is ideal \nfor content that adapts to the available vertical space within the modal \nsheet's maximum height. The main content can utilize the Flex layout model \nof a Column for space management.\n\n ```dart\nNonScrollingWoltModalSheetPage(\n  child: MyFlexibleHeightWidget(),\n  // Additional properties...\n)\n\n ```\n\n## In-Modal Navigation\n\nThe package provides in-modal navigation capabilities, allowing for dynamic \ntransitions and stack manipulations directly within the modal. This section \ndetails how to utilize these features effectively in your applications.\n\n### Managing Navigation Stack\n\nhe following methods facilitate the addition, removal, and modification of \npages within the navigation stack. These functionalities allow you to \ndynamically adapt the navigation stack based on user interactions without \ndisrupting the currently displayed page.\n\n#### Adding Pages to the Stack\n\nYou can append one or more pages to the navigation stack. This feature is \nparticularly useful for preloading pages or preparing navigation paths for \nfuture steps without changing the currently displayed page.\n\n```dart\nWoltModalSheet.of(context).addPages([newPage1, newPage2, newPage3]);\nWoltModalSheet.of(context).addPage(newPage1);\n```\n\n#### Modifying Existing Pages\n\nThese methods allow you to replace or remove specific pages within the stack.\nIf the page being modified is currently visible, appropriate adjustments are \nmade to ensure seamless navigation.\n\n##### Replace a specific page\nWhen you need to update or change the content of a specific page within the \nstack, this method allows you to replace any page by its identifier without \naltering the rest of the stack.\n    \n```dart\nWoltModalSheet.of(context).replacePage(pageId, newPage);\n```\n\n##### Replace or update the current page\n\nWhen the current page needs to be removed from the page list and replaced by \na new page, with a pagination animation at the same position in the list, \nuse `replaceCurrentPage` method.\n\n```dart\nWoltModalSheet.of(context).replaceCurrentPage(newPage);\n```\n\nWhen the overall context or the purpose of the current page is still \nrelevant, but you need to modify specific attributes of the current page, use \n`updateCurrentPage` method.\n\n```dart\nWoltModalSheet.of(context).updateCurrentPage((currentPage) {\n  return currentPage.copyWith(\n    enableDrag: true,\n    hasTopBarLayer: false,\n    // Other updated properties...\n  );\n});\n```\n\n##### Remove a specific page\nThis method enables you to selectively remove a page from the navigation \nstack using its identifier. If the page being removed is the currently \ndisplayed page, it will remove the page and adjust the currently displayed page \naccordingly. If it is not the current page, it is removed from the stack \nwithout impacting the current view.\n\n```dart\nWoltModalSheet.of(context).removePage(pageId);\n```\n\n##### Add or replace pages\nThis method updates the navigation stack by either adding new pages or \nreplacing all subsequent pages depending on the position of the current page.\nIf the current page is the last in the stack it simply appends the new pages.\nHowever, if the current page is not the last, it replaces all pages \nfollowing it with the new ones. This functionality is particularly useful \nfor adapting the user's navigation path dynamically based on their \ninteractions with the currently displayed page or when making adjustments to \npreviously made decisions.\n\n```dart\nWoltModalSheet.of(context).addOrReplacePages([newPage1, newPage2, newPage3]);\nWoltModalSheet.of(context).addOrReplacePage(newPage);\n```\n\n### Navigation Between Pages\n\nThis subsection details the methods for moving within the modal's navigation \nstack, allowing users to navigate through pages effectively.\n\n#### Direct navigation\nNavigate within the modal stack using specific methods to move directly to a \ndesired page. You can go to the next or previous page, jump to a page at a \nspecific index in the page list, or navigate to a page by its unique identifier.\n\n```dart\n// Move to the next page\nbool movedNext = WoltModalSheet.of(context).showNext();\n\n// Move to the previous page\nbool movedPrevious = WoltModalSheet.of(context).showPrevious();\n\n// Jump directly to a page at a specific index\nbool navigatedByIndex = WoltModalSheet.of(context).showAtIndex(2);\n\n// Navigate to a page by its unique identifier\nbool navigatedById = WoltModalSheet.of(context).showPageWithId(pageId);\n```\n\n#### Pushing Pages\nUsing push methods, you can add one or more new pages to the end of the \nnavigation stack and navigate to the first of the newly added pages.\n\n```dart\nWoltModalSheet.of(context).pushPages([newPage1, newPage2, newPage3]);\nWoltModalSheet.of(context).pushPage(newPage);\n```\n\n#### Popping Page\nUsing pop method, you can remove the last page of the navigation stack. If the\nuser is on the last page, the method will navigate to the previous page.\n    \n```dart\nbool popped = WoltModalSheet.of(context).popPage();\n```\n\n### Dynamic Navigation with ValueNotifiers\n`ValueNotifier\u003cint\u003e pageIndexNotifier` and \n`ValueNotifier\u003cWoltModalSheetPageListBuilder\u003e pageListBuilderNotifier` can \nalso be utilized for in-modal navigation and setting the modal navigation \nstack. These notifiers dynamically manage the visible page index \nand the page list, enhancing flexibility in response to the state changes.\n\n#### Navigation by Page Index Notifier\n`ValueNotifier\u003cint\u003e pageIndexNotifier` controls the visible page index, \nenabling transitions between pages based on user interactions or other events.\n\n```dart\n// Example of setting up a modal with navigation between pages controlled by \n// a ValueNotifier\u003cint\u003e.\nfinal pageIndexNotifier = ValueNotifier(0); // Initializes the page index\n\nWoltModalSheet.show(\n  context: context,\n  pageListBuilder: (modalSheetContext) =\u003e [\n    PageOne(onNextButtonPressed: () =\u003e pageIndexNotifier.value = 1),\n    PageTwo(onBackButtonPressed: () =\u003e pageIndexNotifier.value = pageIndexNotifier.value - 1),\n  ],\n  pageIndexNotifier: pageIndexNotifier,  // Tracks and updates the displayed page\n);\n\n```\n\n#### Dynamic Page List Management by Page List Builder Notifier\n`ValueNotifier\u003cWoltModalSheetPageListBuilder\u003e pageListBuilderNotifier` \nmanages updates to the modal's page list based on user interactions or other \napp state changes. This is useful when implementing Navigator 2.0 for \ndeclarative navigation scenarios. It is not suggested to mix the usage of \nthis notifier with the imperative navigation methods provided by the package.\n\n```dart\nfinal pageIndexNotifier = ValueNotifier(0); // Initializes the page index\nfinal pageListBuilderNotifier = ValueNotifier((context) =\u003e [\n  PageOne(onNextButtonPressed: () =\u003e pageIndexNotifier.value++),\n  PageTwo(onBackButtonPressed: () =\u003e pageIndexNotifier.value--),\n]);\n\nWoltModalSheet.showWithDynamicPath(\n  context: context,\n  pageListBuilderNotifier: pageListBuilderNotifier,\n  pageIndexNotifier: pageIndexNotifier,  // Dynamically updates the navigation stack\n);\n```\n\n## Design Guidelines\n\nThis section outlines the design guidelines for the modal sheet component, including breakpoints and behavior across different devices. The guidelines are based on the Wolt design system specs.\n\n### Overview\n\nThe modal sheet component is used to display critical information or interactive elements to users in a non-intrusive way. This component adapts to different screen sizes and orientations.\n\n### Breakpoints\n\nThe modal sheet component adjusts its layout and positioning based on the \nfollowing breakpoints:\n\n- **Breakpoint Large**: Width ≥ 1400px\n- **Breakpoint Medium**: 768px ≤ Width \u003c 1400px\n- **Breakpoint Small**: 524px ≤ Width \u003c 768px\n- **Breakpoint XSmall**: Width \u003c 524px\n\n![Breakpoints](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/breakpoints_design_guidelines.png?raw=true)\n\n### Modal Types\n\n#### Alert Dialog\n- Used for critical information that requires immediate attention.\n- Must be dismissed by user interaction to ensure the alert is acknowledged.\n\n#### Dialog\n- Used for single user actions or to convey information related to changes in state (success, errors).\n- Provides clear actions for users to acknowledge or dismiss the dialog.\n- We recommend to use dialogs in small, medium and large windows sizes.\n\n#### Side Sheet\n- Used to focus users' attention on a specific task while keeping the context visible.\n- We recommend to use side sheets in small, medium and large windows sizes.\n\n#### Bottom Sheet\n- Provides additional options or actions without leaving the current context.\n- We recommend to use bottom sheets only in xsmall window size. The side \n  sheet and dialog content should be shown in a bottom sheet in xsmall window.\n\n## Understanding the page elements\n\nEach element within the WoltModalSheet has a role to play, offering context,\nnavigational assistance, and explicit action prompts to the user. By\nunderstanding these elements and their roles, you can fully harness the power of\nWoltModalSheet and create an intuitive and engaging user experience.\n\nThe structure is organized across layers on the z-axis:\n\n\u003cli\u003e\u003cb\u003eMain Content Layer\u003c/b\u003e: The fundamental content of the page,\nincluding the optional page title, optional hero image, and the main content,\nwhich may be scrollable.\u003c/li\u003e\n\u003cli\u003e\u003cb\u003eTop Bar Layer\u003c/b\u003e: Further above the main content layer, this layer\nwith the filled color includes the top bar title and may become hidden or\nsticky based on scroll position and specific properties.\u003c/li\u003e\n\u003cli\u003e\u003cb\u003eNavigation Bar Layer\u003c/b\u003e: Sitting at the top of the top bar layer on\nz-axis, this transparent-background layer contains navigational widgets for\nthe interface, such as back or close buttons.\u003c/li\u003e\n\u003cli\u003e\u003cb\u003eSticky Action Bar Layer\u003c/b\u003e: Positioned at the top of the z axis,\nthis layer guides the user towards the next step, uses an optional gentle\ngradient on top to hint that there is more content below ready for scrolling.\u003c/li\u003e\n\u003c/br\u003e\n\n![Modal sheet page layers](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/modal_sheet_page.png?raw=true)\n\u003c/br\u003e\n\nBy employing these various layers, you can create an interactive and visually\nappealing interface that resonates with users. Each layer contributes to the\noverall coherence of the page, serving a specific purpose and enhancing the\noverall user experience.\n\u003c/br\u003e\n\n![Modal sheet elements breakdown](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/bottom_sheet_elements.jpeg?raw=true)\n\n### Navigation bar widgets\n\nThe navigation bar has a transparent background, and resides at the top of\nthe sheet, situated directly above the top bar on the z-axis. It includes\ntwo specific widgets: the leading and the trailing. The leading widget\nusually functions as the back button, enabling users to navigate to the\nprevious page. The trailing widget often serves as the close button, utilized to\nclose the modal sheet. The middle area is reserved and left empty for the\nvisibility of the top bar title.\n\u003c/br\u003e\n\u003c/br\u003e\nThe navigation bar widgets provide clear and intuitive navigational control,\ndifferentiating themselves from the top bar by focusing specifically on\ndirectional navigation within the interface.\n\n### Top bar and top bar title\n\nThe top bar layer sits above the main content layer and below the navigation\nbar layer in z axis. It helps users grasping the context by displaying an\noptional title. In scenarios where the sheet is filled with content\nrequiring scrolling, the top bar becomes visible as the user scrolls, and\nreplaces the page title. At this point, the top bar adopts a 'sticky'\nposition at the top, guaranteeing consistent visibility.\n\u003c/br\u003e\n\u003c/br\u003e\nThe top bar widget has a flexible design. When `hasTopBarLayer` is set to\nfalse, the top bar and the top bar title will not be shown. If\n`isTopBarLayerAlwaysVisible` set to true, the top bar will be always visible\nregardless of the scroll position.\n\u003c/br\u003e\n\u003c/br\u003e\nA custom top bar widget can be provided using the `topBar` field. In this\ncase, the `topBarTitle` field will be ignored, and will not be displayed.\n\u003c/br\u003e\n\u003c/br\u003e\nThe navigation bar widgets overlay above the top bar, and when the default\ntop bar widget is used in the page, the top bar title is symmetrically\nframed between the leading and trailing navigation bar widgets.\n\n### Sticky action bar (SAB)\n\nThe Sticky Action Bar (SAB) guides the user towards the next step. Anchored to\nthe bottom of the view, the SAB elevates above the content with an optional\ngentle gradient. This position guarantees that the action remains visible, subtly\nhinting to the user that there is more content to be explored below the fold\nby scrolling.\n\n### Hero image\n\nAn optional Hero Image can be positioned at the top of the main content. This\nelement immediately grabs the user's attention, effectively conveying the\nprimary theme or message of the content.\n\n### Page Title\n\nAn optional page title above the main content provides users with a quick\nunderstanding of what to expect from the page. As the user scrolls, this title\nbecomes hidden, at which point the top bar title continues to serve this\ncontext-providing purpose.\n\n### Main content\n\nThe main content delivers information according to the user need. It can be\nscrollable to handle larger content. The content is built lazily to improve the\nperformance.\n\nHere is an example that shows all the modal sheet elements in use:\n\n![Modal sheet elements in use](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/bottom_sheet_example.jpeg?raw=true)\n\n## Designer Collaboration Guide\n\nTo ensure seamless collaboration between designers and developers, we have \nprovided a [Figma file](https://www.figma.com/file/jRQUhvi44bkUxRxSWGhSXO/Wolt-Modal-Sheet-Specs?type=design\u0026node-id=7%3A514\u0026mode=design\u0026t=NULXGTxl2YvnawyH-1) dedicated to the WoltModalSheet package. This resource aims to guide designers through the process of creating and handing over designs that leverage the WoltModalSheet's capabilities effectively.\n\n### What is inside the Figma File\n\n- **Example Design Specifications**: Detailed design guidelines and \n  specifications mirroring those used internally at Wolt. These specs \n  illustrate how to prepare designs for development handoff, ensuring a \n  smooth transition from design to implementation.\n\n- **Modal Types Specifications**: This section showcases specifications for \n  different modal types, including dialog, alert dialog, side sheet, bottom \n  sheet modals. It covers essential details like dimensions, layout of \n  elements, and visual arrangements, providing clear instructions for \n  replicating these styles in your projects.\n\n- **Motion Specs for Modal Interactions**: To complement the \n  static design aspects, this section demonstrates motion \n  specifications for pagination and scrolling interactions. It includes \n  guidelines for animating transitions between modal sheet pages and within \n  the content scroll, enabling designers to specify dynamic, engaging user \n  experiences.\n\n## Customizable Animations\n\nDevelopers can customize the page scrolling and pagination animations by\nproviding an instance of  `WoltModalSheetAnimationStyle` class to \n`WoltModalSheetThemeData`.\n\n### Default Animation Style Specifications\n\n#### Pagination Animation\n\n![Modal sheet elements in use](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/pagination_modal_sheet.png?raw=true)\n\n#### Scrolling Animation\n\n![Modal sheet elements in use](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/scrolling_modal_sheet.png?raw=true)\n\n### Example Configuration\n\n```dart\nWoltModalSheetThemeData(\n  animationStyle: WoltModalSheetAnimationStyle(\n    paginationAnimationStyle: WoltModalSheetPaginationAnimationStyle(\n      paginationDuration = Duration(milliseconds: 250),\n      mainContentIncomingOpacityCurve: const Interval(\n        150 / 350,\n        350 / 350,\n        curve: Curves.linear,\n      ),\n      modalSheetHeightTransitionCurve: const Interval(\n        0 / 350,\n        300 / 350,\n        curve: Curves.fastOutSlowIn,\n      ),\n      incomingSabOpacityCurve: const Interval(\n        100 / 350,\n        300 / 350,\n        curve: Curves.linear,\n      ),\n      // Define additional pagination animation styles as needed.\n    ),\n    scrollAnimationStyle: WoltModalSheetScrollAnimationStyle(\n      heroImageScaleStart: 1.0,\n      heroImageScaleEnd: 0.9,\n      topBarTitleTranslationYInPixels: 8.0,\n      topBarTranslationYInPixels: 4.0,\n      // Define additional scroll animation styles as needed.\n    ),\n  ),\n),\n```\n\n## Additional information\n\n* \u003cb\u003eDesign Philosophy\u003c/b\u003e: Dive into the creative thought process behind\n  WoltModalSheet's functionality [in our blog post](https://careers.wolt.com/en/blog/engineering/an-overview-of-the-multi-page-scrollable-bottom-sheet-ui-design)\n  . Explore how we tackled the design challenges to create an intuitive and \n  responsive experience.\n* \u003cb\u003eInsights from FlutterCon'23\n  talk\u003c/b\u003e: We delved into both the design and developmental facets of this \n  package at the FlutterCon'23 conference. Catch the\n  enlightening [recording of his talk](https://www.droidcon.com/2023/08/07/the-art-of-responsive-modals-building-a-multi-page-sheet-in-flutter/)\n  to understand the nuances.\n* \u003cb\u003eFlutter\u0026Friends talk\u003c/b\u003e: This is a lightening talk given at the\n  Flutter\u0026Friends conference on September'23. It covers the design\n  guidelines and best practices by showing real-world examples highlighting\n  what to do—and what not to do. It also covers the technical details of the\n  implementation. The recording of the talk can be found [here](https://www.youtube.com/live/X3bw1pr1kyQ?si=1SielcIbW6rF-4IC\u0026t=4449).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwoltapp%2Fwolt_modal_sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwoltapp%2Fwolt_modal_sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwoltapp%2Fwolt_modal_sheet/lists"}