A VSCode extension which helps you automate the process of adding new widget entries for Widgetbook - a widget library for Flutter.
The extension allows you to generate a base for widgetbook use-cases for a chosen widget (or for the whole directory of widgets). It will go through the widget, and for every constructor it will create a widgetbook use case. All those use cases will be put in one file which should be a representation of a chosen widget in the widgetbook. For each constructor property the extension will try to find the most suitable knob.
There is a set of predefined type-knob pairs. You can also configure your own knobs (see Custom Knobs) and override existing ones. If none of defined types matches the property, it's assumed the property is a custom enum (so list
knob will be used).
NOTE: The code generated by the extension should always be revised and corrected where needed. The extension is just supposed to provide a solid base for further adjustments, do the job of writing repeatable, schematic code.
The extension can be installed from the VSCode Marketplace.
A couple of settings need to be specified for the extension to work. They can be set in VSCode Settings after typing "widgetbook" in the searchbar.
- Approach - the Widgetbook approach you want to use. Can be set to Manual or Generation. In Manual approach you'll need to add widgets to the Widgetbook manually, in Generation approach
build_runner
will do that for you. - Widgetbook Version - should be set as the same version you use in your
pubspec.yaml
file. - Widgets Directory Path - a directory in which you want to create new widgetbook entries. Whenever you use the extension to generate an entry for the widget, the generated file will be placed in this directory. The path is relative to the directory you have open in the VSCode.
- Root Directory Name - root name of the directory you have open in the VSCode. It's shown by default on the VSCode's app bar or on top of the file explorer tab. It's needed to correctly generate widgetbook path.
- Barrel File Import - the file which exports all your custom widgets. E.g.
package:my_common_ui/widgets.dart
. If you don't use a barrel file for exporting your widgets, you can leave this setting empty, you'll need to add proper imports manually then. - Number Knob Type - the type of knob that will be used for numeric fields. Can be
Input
orSlider
. - Custom Knobs Path - path to the file which contains your custom knobs (see more in Custom Knobs). Leave this setting empty if you don't want to provide custom knobs.
Those settings are purely project specific. If you work on multiple projects at the same time and all of them use widgetbook, you can override above settings for each of them. Just create settings.json
file under .vscode
directory in your project. You can override specific settings there just for the current workspace:
{
"widgetbook-generator.widgetsDirectoryPath": "apps/my_widgetbook/lib/widgets",
"widgetbook-generator.barrelFileImport": "package:my_common_ui/my_common_ui.dart",
"widgetbook-generator.rootDirectoryName": "my_project",
"widgetbook-generator.widgetbookVersion": "3.2.0", // must be supported by the extension
"widgetbook-generator.approach": "Manual",
"widgetbook-generator.customKnobsPath": "custom_knobs.json"
}
If you want to see a complete usage example in a real application (along with settings.json
file), you can have a look at the example project and its README.
Before using the extension to generate files, make sure you've configured your extension before by following steps described in Configuration. Also, make sure the code meets the requirements.
Put the cursor on the line with class name declaration, press a shortcut for Quick Fix
action (by default Ctrl+.
on Windows/Linux and Cmd+.
on macOS), then select option Create widgetbook entry for this widget
.
In VSCode explorer, right-click on the directory that contains widgets for which you want to generate entries, then select Widgetbook: generate entry for each widget in the directory
. The extension will generate a new file with widgetbook entries for each of the widgets in the directory. If the directory contains subdirectories, the extension will also generate entries for them.
Note: This feature is currently experimental and may require adjustments. We're working on making it stable.
Note: After generating the components, remember to add them to directories
parameter in your WidgetbookApp
widget.
The extension allows for adding custom knobs for specified types (e.g. your custom widgets/enums that you want to handle differently). These custom knobs can also override knobs predefined by the extension.
To define custom knobs, create a JSON file containing your knobs, and set the Custom Knob Path property from Configuration section. Your JSON structure should look like this:
[
{
"type": "Duration",
"nullability": "both", // can be any of: "nonNullable", "nullable", "both"
"value": "context.knobs.duration(label: '$fieldName')" // $fieldName will be replaced by the actual name of the field when generating the use-case
}
// other custom knobs
]
This project is still in very early stage of development. If you find that something is not working properly or you think some features are missing, feel free to create an issue or even a pull request.
Disclaimer: This is not an official Widgetbook extension. It's made and maintained by the community.
Since the project is still in very early stage of development, some rules need to be followed for the extension to work correctly.
-
File must be formatted when generating entries (using
dart format
). VSCode often does this for you when you save the file (if you have Format On Save option selected). -
Trailing commas in widget constructors must be used.
Good:
const Button({ super.key, required this.label, required this.icon, this.onTap, });
Bad:
const Button( {super.key, required this.label, required this.icon, this.onTap});
const Button({super.key, required this.onTap, required this.label});
-
Code must use 2 spaces for indents (this is a default setting in Flutter).
- Single-line constructors are not supported. If you need to generate a use-case for a single-line constructor, convert it into a multi-line constructor.
Good:
const Text(
this.text
);
Bad:
const Text(this.text);