diff --git a/docs/src/content/docs/architecture.mdx b/docs/src/content/docs/architecture.mdx index 3f9b41a1168..4c3ae21f424 100644 --- a/docs/src/content/docs/architecture.mdx +++ b/docs/src/content/docs/architecture.mdx @@ -24,7 +24,7 @@ Using the bloc library allows us to separate our application into three layers: We're going to start at the lowest level layer (farthest from the user interface) and work our way up to the presentation layer. -## Data Layer +## [Data Layer](#data-layer) The data layer's responsibility is to retrieve/manipulate data from one or more sources. @@ -35,7 +35,7 @@ The data layer can be split into two parts: This layer is the lowest level of the application and interacts with databases, network requests, and other asynchronous data sources. -### Data Provider +### [Data Provider](#data-provider) The data provider's responsibility is to provide raw data. The data provider should be generic and versatile. @@ -44,7 +44,7 @@ We might have a `createData`, `readData`, `updateData`, and `deleteData` method -### Repository +### [Repository](#repository) The repository layer is a wrapper around one or more data providers with which the Bloc Layer communicates. @@ -52,7 +52,7 @@ The repository layer is a wrapper around one or more data providers with which t As you can see, our repository layer can interact with multiple data providers and perform transformations on the data before handing the result to the business logic layer. -## Business Logic Layer +## [Business Logic Layer](#business-logic-layer) The business logic layer's responsibility is to respond to input from the presentation layer with new states. This layer can depend on one or more repositories to retrieve data needed to build up the application state. @@ -60,7 +60,7 @@ Think of the business logic layer as the bridge between the user interface (pres -### Bloc-to-Bloc Communication +### [Bloc-to-Bloc Communication](#bloc-to-bloc-communication) Because blocs expose streams, it may be tempting to make a bloc which listens to another bloc. You should **not** do this. There are better alternatives than resorting to the code below: @@ -76,7 +76,7 @@ A bloc should only receive information through events and from injected reposito If you're in a situation where a bloc needs to respond to another bloc, you have two other options. You can push the problem up a layer (into the presentation layer), or down a layer (into the domain layer). -#### Connecting Blocs through Presentation +#### [Connecting Blocs through Presentation](#connecting-blocs-through-presentation) You can use a `BlocListener` to listen to one bloc and add an event to another bloc whenever the first bloc changes. @@ -86,7 +86,7 @@ The code above prevents `SecondBloc` from needing to know about `FirstBloc`, enc In some situations, you may not want to couple two blocs in the presentation layer. Instead, it can often make sense for two blocs to share the same source of data and update whenever the data changes. -#### Connecting Blocs through Domain +#### [Connecting Blocs through Domain](#connecting-blocs-through-domain) Two blocs can listen to a stream from a repository and update their states independent of each other whenever the repository data changes. Using reactive repositories to keep state synchronized is common in large-scale enterprise applications. @@ -100,7 +100,7 @@ The same repository can be injected into each bloc that needs to react to new ap For more about using streams with Bloc, see [How to use Bloc with streams and concurrency](https://verygood.ventures/blog/how-to-use-bloc-with-streams-and-concurrency). -## Presentation Layer +## [Presentation Layer](#presentation-layer) The presentation layer's responsibility is to figure out how to render itself based on one or more bloc states. In addition, it should handle user input and application lifecycle events. diff --git a/docs/src/content/docs/bloc-concepts.mdx b/docs/src/content/docs/bloc-concepts.mdx index 65056d2bb29..da5847766b5 100644 --- a/docs/src/content/docs/bloc-concepts.mdx +++ b/docs/src/content/docs/bloc-concepts.mdx @@ -56,7 +56,7 @@ There are several core concepts that are critical to understanding how to use th In the upcoming sections, we're going to discuss each of them in detail as well as work through how they would apply to a counter app. -## Streams +## [Streams](#streams) :::note Check out the official [Dart Documentation](https://dart.dev/tutorials/language/streams) for more information about `Streams`. @@ -88,7 +88,7 @@ We can put it all together like so: Now that we have a basic understanding of how `Streams` work in Dart we're ready to learn about the core component of the bloc package: a `Cubit`. -## Cubit +## [Cubit](#cubit) A `Cubit` is a class which extends `BlocBase` and can be extended to manage any type of state. @@ -102,7 +102,7 @@ States are the output of a `Cubit` and represent a part of your application's st For more information about the origins of `Cubit` checkout [the following issue](https://github.com/felangel/cubit/issues/69). ::: -### Creating a Cubit +### [Creating a Cubit](#creating-a-cubit) We can create a `CounterCubit` like: @@ -118,7 +118,7 @@ This would allow us to instantiate `CounterCubit` instances with different initi -### Cubit State Changes +### [Cubit State Changes](#cubit-state-changes) Each `Cubit` has the ability to output a new state via `emit`. @@ -130,7 +130,7 @@ In the above snippet, the `CounterCubit` is exposing a public method called `inc The `emit` method is protected, meaning it should only be used inside of a `Cubit`. ::: -### Using a Cubit +### [Using a Cubit](#using-a-cubit) We can now take the `CounterCubit` we've implemented and put it to use! @@ -140,7 +140,7 @@ We can now take the `CounterCubit` we've implemented and put it to use! In the above snippet, we start by creating an instance of the `CounterCubit`. We then print the current state of the cubit which is the initial state (since no new states have been emitted yet). Next, we call the `increment` function to trigger a state change. Finally, we print the state of the `Cubit` again which went from `0` to `1` and call `close` on the `Cubit` to close the internal state stream. -#### Stream Usage +#### [Stream Usage](#stream-usage) `Cubit` exposes a `Stream` which allows us to receive real-time state updates: @@ -156,7 +156,7 @@ In the above snippet, we are subscribing to the `CounterCubit` and calling print Only subsequent state changes will be received when calling `listen` on a `Cubit`. ::: -### Observing a Cubit +### [Observing a Cubit](#observing-a-cubit) When a `Cubit` emits a new state, a `Change` occurs. We can observe all changes for a given `Cubit` by overriding `onChange`. @@ -174,7 +174,7 @@ The above example would output: A `Change` occurs just before the state of the `Cubit` is updated. A `Change` consists of the `currentState` and the `nextState`. ::: -#### BlocObserver +#### [BlocObserver](#blocobserver) One added bonus of using the bloc library is that we can have access to all `Changes` in one place. Even though in this application we only have one `Cubit`, it's fairly common in larger applications to have many `Cubits` managing different parts of the application's state. @@ -202,7 +202,7 @@ The internal `onChange` override is called first, which calls `super.onChange` n In `BlocObserver` we have access to the `Cubit` instance in addition to the `Change` itself. ::: -### Cubit Error Handling +### [Cubit Error Handling](#cubit-error-handling) Every `Cubit` has an `addError` method which can be used to indicate that an error has occurred. @@ -224,13 +224,13 @@ If we run the same program again we should see the following output: Just as with `onChange`, the internal `onError` override is invoked before the global `BlocObserver` override. ::: -## Bloc +## [Bloc](#bloc) A `Bloc` is a more advanced class which relies on `events` to trigger `state` changes rather than functions. `Bloc` also extends `BlocBase` which means it has a similar public API as `Cubit`. However, rather than calling a `function` on a `Bloc` and directly emitting a new `state`, `Blocs` receive `events` and convert the incoming `events` into outgoing `states`. ![Bloc Architecture](~/assets/concepts/bloc_architecture_full.png) -### Creating a Bloc +### [Creating a Bloc](#creating-a-bloc) Creating a `Bloc` is similar to creating a `Cubit` except in addition to defining the state that we'll be managing, we must also define the event that the `Bloc` will be able to process. @@ -240,7 +240,7 @@ Events are the input to a Bloc. They are commonly added in response to user inte Just like when creating the `CounterCubit`, we must specify an initial state by passing it to the superclass via `super`. -### Bloc State Changes +### [Bloc State Changes](#bloc-state-changes) `Bloc` requires us to register event handlers via the `on` API, as opposed to functions in `Cubit`. An event handler is responsible for converting any incoming events into zero or more outgoing states. @@ -268,11 +268,11 @@ Blocs should never directly `emit` new states. Instead every state change must b Both blocs and cubits will ignore duplicate states. If we emit `State nextState` where `state == nextState`, then no state change will occur. ::: -### Using a Bloc +### [Using a Bloc](#using-a-bloc) At this point, we can create an instance of our `CounterBloc` and put it to use! -#### Basic Usage +#### [Basic Usage](#basic-usage) @@ -282,7 +282,7 @@ In the above snippet, we start by creating an instance of the `CounterBloc`. We `await Future.delayed(Duration.zero)` is added to ensure we wait for the next event-loop iteration (allowing the `EventHandler` to process the event). ::: -#### Stream Usage +#### [Stream Usage](#stream-usage) Just like with `Cubit`, a `Bloc` is a special type of `Stream`, which means we can also subscribe to a `Bloc` for real-time updates to its state: @@ -294,7 +294,7 @@ In the above snippet, we are subscribing to the `CounterBloc` and calling print `await Future.delayed(Duration.zero)` is added for this example to avoid canceling the subscription immediately. ::: -### Observing a Bloc +### [Observing a Bloc](#observing-a-bloc) Since `Bloc` extends `BlocBase`, we can observe all state changes for a `Bloc` using `onChange`. @@ -324,7 +324,7 @@ If we then rerun the same `main.dart` snippet from before, we should see the fol `onTransition` is invoked before `onChange` and contains the event which triggered the change from `currentState` to `nextState`. ::: -#### BlocObserver +#### [BlocObserver](#blocobserver) Just as before, we can override `onTransition` in a custom `BlocObserver` to observe all transitions that occur from a single place. @@ -356,7 +356,7 @@ We can run the same `main.dart` as before and should see the following output: `onEvent` is called as soon as the event is added. The local `onEvent` is invoked before the global `onEvent` in `BlocObserver`. ::: -### Bloc Error Handling +### [Bloc Error Handling](#bloc-error-handling) Just like with `Cubit`, each `Bloc` has an `addError` and `onError` method. We can indicate that an error has occurred by calling `addError` from anywhere inside our `Bloc`. We can then react to all errors by overriding `onError` just as with `Cubit`. @@ -378,13 +378,13 @@ The local `onError` is invoked first followed by the global `onError` in `BlocOb Any unhandled exceptions that occur within an `EventHandler` are also reported to `onError`. ::: -## Cubit vs. Bloc +## [Cubit vs. Bloc](#cubit-vs-bloc) Now that we've covered the basics of the `Cubit` and `Bloc` classes, you might be wondering when you should use `Cubit` and when you should use `Bloc`. -### Cubit Advantages +### [Cubit Advantages](#cubit-advantages) -#### Simplicity +#### [Simplicity](#simplicity) One of the biggest advantages of using `Cubit` is simplicity. When creating a `Cubit`, we only have to define the state as well as the functions which we want to expose to change the state. In comparison, when creating a `Bloc`, we have to define the states, events, and the `EventHandler` implementation. This makes `Cubit` easier to understand and there is less code involved. @@ -400,9 +400,9 @@ Now let's take a look at the two counter implementations: The `Cubit` implementation is more concise and instead of defining events separately, the functions act like events. In addition, when using a `Cubit`, we can simply call `emit` from anywhere in order to trigger a state change. -### Bloc Advantages +### [Bloc Advantages](#bloc-advantages) -#### Traceability +#### [Traceability](#traceability) One of the biggest advantages of using `Bloc` is knowing the sequence of state changes as well as exactly what triggered those changes. For state that is critical to the functionality of an application, it might be very beneficial to use a more event-driven approach in order to capture all events in addition to state changes. @@ -420,7 +420,7 @@ The above `Transition` gives us all the information we need to understand why th This tells us that the user was logged out but it doesn't explain why which might be critical to debugging and understanding how the state of the application is changing over time. -#### Advanced Event Transformations +#### [Advanced Event Transformations](#advanced-event-transformations) Another area in which `Bloc` excels over `Cubit` is when we need to take advantage of reactive operators such as `buffer`, `debounceTime`, `throttle`, etc. diff --git a/docs/src/content/docs/faqs.mdx b/docs/src/content/docs/faqs.mdx index 267a8ccb171..1c0e01dff7a 100644 --- a/docs/src/content/docs/faqs.mdx +++ b/docs/src/content/docs/faqs.mdx @@ -21,7 +21,7 @@ import BlocInternalAddEventSnippet from '~/components/faqs/BlocInternalAddEventS import BlocInternalEventSnippet from '~/components/faqs/BlocInternalEventSnippet.astro'; import BlocExternalForEachSnippet from '~/components/faqs/BlocExternalForEachSnippet.astro'; -## State Not Updating +## [State Not Updating](#state-not-updating) ❔ **Question**: I'm emitting a state in my bloc but the UI is not updating. What am I doing wrong? @@ -84,7 +84,7 @@ like: -## Handling Errors +## [Handling Errors](#handling-errors) ❔ **Question**: How can I handle an error while still showing previous data? @@ -102,7 +102,7 @@ when an error has occurred. -## Bloc vs. Redux +## [Bloc vs. Redux](#bloc-vs-redux) ❔ **Question**: What's the difference between Bloc and Redux? @@ -137,7 +137,7 @@ across multiple blocs. Furthermore, there is no concept of middleware in bloc and bloc is designed to make async state changes very easy, allowing you to emit multiple states for a single event. -## Bloc vs. Provider +## [Bloc vs. Provider](#bloc-vs-provider) ❔ **Question**: What's the difference between Bloc and Provider? @@ -147,7 +147,7 @@ multiple states for a single event. internally to make it easy to provide and access blocs throughout the widget tree. -## BlocProvider.of() Fails to Find Bloc +## [BlocProvider.of() Fails to Find Bloc](#blocproviderof-fails-to-find-bloc) ❔ **Question**: When using `BlocProvider.of(context)` it cannot find the bloc. How can I fix this? @@ -166,7 +166,7 @@ provided so you must ensure `BlocProvider.of()` is called within a child -## Project Structure +## [Project Structure](#project-structure) ❔ **Question**: How should I structure my project? @@ -180,7 +180,7 @@ recommended references are The most important thing is having a **consistent** and **intentional** project structure. -## Adding Events within a Bloc +## [Adding Events within a Bloc](#adding-events-within-a-bloc) ❔ **Question**: Is it okay to add events within a bloc? @@ -227,7 +227,7 @@ The drawbacks of the above approach are: - We need to expose a public `Started` event which must be added externally - We cannot use a custom `transformer` to adjust how we react to user updates -## Exposing Public Methods +## [Exposing Public Methods](#exposing-public-methods) ❔ **Question**: Is it okay to expose public methods on my bloc and cubit instances? diff --git a/docs/src/content/docs/flutter-bloc-concepts.mdx b/docs/src/content/docs/flutter-bloc-concepts.mdx index 163f7eaf022..c04c95d7dea 100644 --- a/docs/src/content/docs/flutter-bloc-concepts.mdx +++ b/docs/src/content/docs/flutter-bloc-concepts.mdx @@ -42,9 +42,9 @@ Please make sure to carefully read the following sections before working with [` All widgets exported by the `flutter_bloc` package integrate with both `Cubit` and `Bloc` instances. ::: -## Bloc Widgets +## [Bloc Widgets](#bloc-widgets) -### BlocBuilder +### [BlocBuilder](#blocbuilder) **BlocBuilder** is a Flutter widget which requires a `Bloc` and a `builder` function. `BlocBuilder` handles building the widget in response to new states. `BlocBuilder` is very similar to `StreamBuilder` but has a more simple API to reduce the amount of boilerplate code needed. The `builder` function will potentially be called many times and should be a [pure function](https://en.wikipedia.org/wiki/Pure_function) that returns a widget in response to the state. @@ -62,7 +62,7 @@ For fine-grained control over when the `builder` function is called an optional -### BlocSelector +### [BlocSelector](#blocselector) **BlocSelector** is a Flutter widget which is analogous to `BlocBuilder` but allows developers to filter updates by selecting a new value based on the current bloc state. Unnecessary builds are prevented if the selected value does not change. The selected value must be immutable in order for `BlocSelector` to accurately determine whether `builder` should be called again. @@ -70,7 +70,7 @@ If the `bloc` parameter is omitted, `BlocSelector` will automatically perform a -### BlocProvider +### [BlocProvider](#blocprovider) **BlocProvider** is a Flutter widget which provides a bloc to its children via `BlocProvider.of(context)`. It is used as a dependency injection (DI) widget so that a single instance of a bloc can be provided to multiple widgets within a subtree. @@ -92,7 +92,7 @@ then from either `ChildA`, or `ScreenA` we can retrieve `BlocA` with: -### MultiBlocProvider +### [MultiBlocProvider](#multiblocprovider) **MultiBlocProvider** is a Flutter widget that merges multiple `BlocProvider` widgets into one. `MultiBlocProvider` improves the readability and eliminates the need to nest multiple `BlocProviders`. @@ -104,7 +104,7 @@ to: -### BlocListener +### [BlocListener](#bloclistener) **BlocListener** is a Flutter widget which takes a `BlocWidgetListener` and an optional `Bloc` and invokes the `listener` in response to state changes in the bloc. It should be used for functionality that needs to occur once per state change such as navigation, showing a `SnackBar`, showing a `Dialog`, etc... @@ -122,7 +122,7 @@ For fine-grained control over when the `listener` function is called an optional -### MultiBlocListener +### [MultiBlocListener](#multibloclistener) **MultiBlocListener** is a Flutter widget that merges multiple `BlocListener` widgets into one. `MultiBlocListener` improves the readability and eliminates the need to nest multiple `BlocListeners`. @@ -134,7 +134,7 @@ to: -### BlocConsumer +### [BlocConsumer](#blocconsumer) **BlocConsumer** exposes a `builder` and `listener` in order to react to new states. `BlocConsumer` is analogous to a nested `BlocListener` and `BlocBuilder` but reduces the amount of boilerplate needed. `BlocConsumer` should only be used when it is necessary to both rebuild UI and execute other reactions to state changes in the `bloc`. `BlocConsumer` takes a required `BlocWidgetBuilder` and `BlocWidgetListener` and an optional `bloc`, `BlocBuilderCondition`, and `BlocListenerCondition`. @@ -147,7 +147,7 @@ An optional `listenWhen` and `buildWhen` can be implemented for more granular co -### RepositoryProvider +### [RepositoryProvider](#repositoryprovider) **RepositoryProvider** is a Flutter widget which provides a repository to its children via `RepositoryProvider.of(context)`. It is used as a dependency injection (DI) widget so that a single instance of a repository can be provided to multiple widgets within a subtree. `BlocProvider` should be used to provide blocs whereas `RepositoryProvider` should only be used for repositories. @@ -157,7 +157,7 @@ then from `ChildA` we can retrieve the `Repository` instance with: -### MultiRepositoryProvider +### [MultiRepositoryProvider](#multirepositoryprovider) **MultiRepositoryProvider** is a Flutter widget that merges multiple `RepositoryProvider` widgets into one. `MultiRepositoryProvider` improves the readability and eliminates the need to nest multiple `RepositoryProvider`. @@ -169,7 +169,7 @@ to: -## BlocProvider Usage +## [BlocProvider Usage](#blocprovider-usage) Lets take a look at how to use `BlocProvider` to provide a `CounterBloc` to a `CounterPage` and react to state changes with `BlocBuilder`. @@ -181,7 +181,7 @@ Lets take a look at how to use `BlocProvider` to provide a `CounterBloc` to a `C At this point we have successfully separated our presentational layer from our business logic layer. Notice that the `CounterPage` widget knows nothing about what happens when a user taps the buttons. The widget simply tells the `CounterBloc` that the user has pressed either the increment or decrement button. -## RepositoryProvider Usage +## [RepositoryProvider Usage](#repositoryprovider-usage) We are going to take a look at how to use `RepositoryProvider` within the context of the [`flutter_weather`][flutter_weather_link] example. @@ -203,7 +203,7 @@ Now when instantiating a bloc, we can access the instance of a repository via `c [flutter_weather_link]: https://github.com/felangel/bloc/blob/master/examples/flutter_weather -## Extension Methods +## [Extension Methods](#extension-methods) [Extension methods](https://dart.dev/guides/language/extension-methods), introduced in Dart 2.7, are a way to add functionality to existing libraries. In this section, we'll take a look at extension methods included in `package:flutter_bloc` and how they can be used. @@ -215,7 +215,7 @@ Internally, `package:flutter_bloc` uses `package:provider` to implement: `BlocPr Learn more about [`package:provider`](https://pub.dev/packages/provider). ::: -### context.read +### [context.read](#contextread) `context.read()` looks up the closest ancestor instance of type `T` and is functionally equivalent to `BlocProvider.of(context)`. `context.read` is most commonly used for retrieving a bloc instance in order to add an event within `onPressed` callbacks. @@ -249,7 +249,7 @@ The above usage is error prone because the `Text` widget will not be rebuilt if Use `BlocBuilder` or `context.watch` instead in order to rebuild in response to state changes. ::: -### context.watch +### [context.watch](#contextwatch) Like `context.read()`, `context.watch()` provides the closest ancestor instance of type `T`, however it also listens to changes on the instance. It is functionally equivalent to `BlocProvider.of(context, listen: true)`. @@ -331,7 +331,7 @@ Widget build(BuildContext context) { Using `context.watch` at the root of the `build` method will result in the entire widget being rebuilt when the bloc state changes. ::: -### context.select +### [context.select](#contextselect) Just like `context.watch()`, `context.select(R function(T value))` provides the closest ancestor instance of type `T` and listens to changes on `T`. Unlike `context.watch`, `context.select` allows you listen for changes in a smaller part of a state. diff --git a/docs/src/content/docs/getting-started.mdx b/docs/src/content/docs/getting-started.mdx index 7a3d9fbff59..ac334d2dabd 100644 --- a/docs/src/content/docs/getting-started.mdx +++ b/docs/src/content/docs/getting-started.mdx @@ -6,7 +6,7 @@ description: Everything you need to start building with Bloc. import InstallationTabs from '~/components/getting-started/InstallationTabs.astro'; import ImportTabs from '~/components/getting-started/ImportTabs.astro'; -## Packages +## [Packages](#packages) The bloc ecosystem consists of multiple packages listed below: @@ -20,7 +20,7 @@ The bloc ecosystem consists of multiple packages listed below: | [hydrated_bloc](https://github.com/felangel/bloc/tree/master/packages/hydrated_bloc) | Caching/Persistence Support | [![pub package](https://img.shields.io/pub/v/hydrated_bloc.svg)](https://pub.dev/packages/hydrated_bloc) | | [replay_bloc](https://github.com/felangel/bloc/tree/master/packages/replay_bloc) | Undo/Redo Support | [![pub package](https://img.shields.io/pub/v/replay_bloc.svg)](https://pub.dev/packages/replay_bloc) | -## Installation +## [Installation](#installation) @@ -28,7 +28,7 @@ The bloc ecosystem consists of multiple packages listed below: In order to start using bloc you must have the [Dart SDK](https://dart.dev/get-dart) installed on your machine. ::: -## Imports +## [Imports](#imports) Now that we have successfully installed bloc, we can create our `main.dart` and import the respective `bloc` package. diff --git a/docs/src/content/docs/naming-conventions.mdx b/docs/src/content/docs/naming-conventions.mdx index e6443a9c428..5bb3acd21a3 100644 --- a/docs/src/content/docs/naming-conventions.mdx +++ b/docs/src/content/docs/naming-conventions.mdx @@ -11,11 +11,11 @@ import StateExamplesBad1Snippet from '~/components/naming-conventions/StateExamp The following naming conventions are simply recommendations and are completely optional. Feel free to use whatever naming conventions you prefer. You may find some of the examples/documentation do not follow the naming conventions mainly for simplicity/conciseness. These conventions are strongly recommended for large projects with multiple developers. -## Event Conventions +## [Event Conventions](#event-conventions) Events should be named in the **past tense** because events are things that have already occurred from the bloc's perspective. -### Anatomy +### [Anatomy](#anatomy) `BlocSubject` + `Noun (optional)` + `Verb (event)` @@ -25,7 +25,7 @@ Initial load events should follow the convention: `BlocSubject` + `Started` The base event class should be name: `BlocSubject` + `Event`. ::: -### Examples +### [Examples](#examples) ✅ **Good** @@ -35,13 +35,13 @@ The base event class should be name: `BlocSubject` + `Event`. -## State Conventions +## [State Conventions](#state-conventions) States should be nouns because a state is just a snapshot at a particular point in time. There are two common ways to represent state: using subclasses or using a single class. -### Anatomy +### [Anatomy](#anatomy-1) -#### Subclasses +#### [Subclasses](#subclasses) `BlocSubject` + `Verb (action)` + `State` @@ -53,7 +53,7 @@ When representing the state as multiple subclasses `State` should be one of the Initial states should follow the convention: `BlocSubject` + `Initial`. ::: -#### Single Class +#### [Single Class](#single-class) `BlocSubject` + `State` @@ -65,7 +65,7 @@ When representing the state as a single base class an enum named `BlocSubject` + The base state class should always be named: `BlocSubject` + `State`. ::: -### Examples +### [Examples](#examples-1) ✅ **Good** diff --git a/docs/src/content/docs/testing.mdx b/docs/src/content/docs/testing.mdx index f05af222090..b945e204a8f 100644 --- a/docs/src/content/docs/testing.mdx +++ b/docs/src/content/docs/testing.mdx @@ -19,7 +19,7 @@ To recap, the `CounterBloc` implementation looks like: -## Setup +## [Setup](#setup) Before we start writing our tests we're going to need to add a testing framework to our dependencies. @@ -27,7 +27,7 @@ We need to add [test](https://pub.dev/packages/test) and [bloc_test](https://pub -## Testing +## [Testing](#testing) Let's get started by creating the file for our `CounterBloc` Tests, `counter_bloc_test.dart` and importing the test package. diff --git a/docs/src/styles/landing.css b/docs/src/styles/landing.css index 067725656e8..3da5519dfe4 100644 --- a/docs/src/styles/landing.css +++ b/docs/src/styles/landing.css @@ -41,6 +41,24 @@ border: none; } +.sl-markdown-content h4 > a:not(:where(.not-content *)), +.sl-markdown-content h3 > a:not(:where(.not-content *)), +.sl-markdown-content h2 > a:not(:where(.not-content *)) { + color: var(--sl-color-white); + text-decoration: none; + position: relative; +} + +@media (hover: hover) { + .sl-markdown-content h4 > a:not(:where(.not-content *)):hover::after, + .sl-markdown-content h3 > a:not(:where(.not-content *)):hover::after, + .sl-markdown-content h2 > a:not(:where(.not-content *)):hover::after { + content: '🔗'; + font-size: 0.7em; + margin-inline-start: 0.5rem; + } +} + @media screen and (min-width: 50rem) { [data-has-hero] .hero { padding-block: clamp(2.5rem, calc(1rem + 10vmin), 2.5rem); @@ -53,4 +71,4 @@ [data-theme='dark'][data-has-hero] .hero > img { filter: drop-shadow(0 0 5rem #81d9ef); } -} +} \ No newline at end of file