Widgetbook 3 is now facing some issues that result in a bad developer experience or some limitations. These issues are:
lib
, test
or widgetbook
folders, and each one has itβs pros and cons..dart
files are taken as an input.widgetbook
is not a dev dependency.label
for knobs using a magic string that usually is the same name as the parameter name.In Widgetbook 4.0 (where the burgers are finally on master chef level π), we aim to introduce a well thought out structure on how to work and maintain Widgetbook for any size of project featuring poly and mono repo approaches as well as quick-setups to try out Widgetbook.
Some terminologies (along with their code names) will be changed as follows:
Old Name | New Name |
---|---|
Use-case | Story |
Addon | Mode |
Knob | Arg |
Widgetbook projects will now be defined inside a separate package as follows:
# Polyrepo
βββ lib/
βββ test/
βββ widgetbook/
β βββ pubspec.yaml # widgetbook_workspace
βββ pubspec.yaml # app
# Monorepo
βββ apps/
β βββ app_1/
β βββ app_2/
βββ packages/
β βββ package_1/
β βββ package_2/
βββ widgetbook/
βββ pubspec.yaml # widgetbook_workspace
# Unsupported Polyrepo
βββ lib/
βββ test/
βββ widgetbook/ # folder not project, for simplicity
βββ pubspec.yaml # app
There will be an intentional cyclic dependency (sorry for using the c-word, we know it hurts) between widgetbook_workspace
projects and app
projects because:
widgetbook_workspace
project needs dependency on app
to catalog the widgets defined there.app
needs dependency on widgetbook_workspace
to define the tests inside the test
folder, re-using the stories defined in the workspace.[!IMPORTANT] Full code can be found in
button.stories.dart
orhome_screen.stories.dart
.
Stories will now be created in a file named <component>.stories.dart
. The .stories.dart
file extension makes it easier for the generator to find these files. This file will contain:
The workflow for cataloging widgets will be as follows:
Write the widget as usual in a file named <component>.dart
inside the app directory. Here is an example of a Button
widget defined in button.dart
:
/// A button to click on.
class Button extends StatelessWidget {
const Button({
super.key,
required this.text,
required this.color,
});
/// The text of this button.
final String text;
/// The background color of this button.
final Color color;
@override
Widget build(BuildContext context) {
return Container(
color: color,
child: Text(text),
);
}
}
Create a file named button.stories.dart
inside the widgetbook
directory with the following content:
import 'package:user_app/button.dart';
part 'button.stories.g.dart';
const metadata = ComponentMetadata(
type: Button, // Used to for code generation
// Optional config here...
);
After running the generator (or possibly a Widgetbook CLI command), the following content will be generated in button.stories.g.dart
:
part of 'button.stories.dart';
typedef ButtonScenario = WidgetbookScenario<Button>;
class ButtonStory extends WidgetbookStory<Button, ButtonArgs> { ... }
class ButtonArgs extends WidgetbookArgs<Button> { ... }
They can now define stories in button.stories.dart
with the following content using the generated classes
final $DefaultButton = ButtonStory(
name: 'Default',
args: ButtonArgs(
text: StringArg('Press'),
color: ColorArg(
Colors.red,
name: 'Background Color',
description: '....',
),
),
);
[!IMPORTANT] Full code can be found in
golden_test.dart
.
When it comes to widget or golden testing, users can re-use stories and convert them to scenarios. Since stories define the way a component is build, a story just needs to define the used modes and the default value of the args.
Single Scenario:
ButtonScenario(
story: $DefaultButton,
modes: [],
args: ButtonArgs(
color: ColorArg(Colors.black),
text: StringArg('Very LongLongLongLongLong Text'),
),
),
Matrix Scenario:
Generates 4 scenarios in the following case:
ButtonScenario.matrix(
story: $DefaultButton,
modes: [
[ThemeMode.value(ThemeData.dark())], // Dark Theme
[ThemeMode.value(ThemeData.light())] // Light Theme
],
args: [
ButtonArgs(...), // First Args
ButtonArgs(...), // Second Args
],
)
Widgetbook 4 will be so dependent on the CLI to make it easier to add features in the future. Here are some commands that we might add:
Command | Description |
---|---|
widgetbook init |
Creates a new project template, could prompt for Widgetbook Cloud or GitHub Actions |
widgetbook login |
Gets Widgetbook Cloud API key via a login redirect, and stores it |
widgetbook run <platform> |
Similar to flutter run |
widgetbook gen |
Similar to dart run build_runner to generate the stories files |
We can have a plugin that helps:
widgetbook_annotation
will no longer be needed.The new features should be introduced in Widgetbook 3 as βexperimentalβ features. In the last minor release of Widgetbook 3, all old code should be deprecated and users should be referenced to use the new code.
All breaking changes will then be done and a new major release will be available.