{"id":20940274,"url":"https://github.com/widgetbook/widgetbook_4","last_synced_at":"2026-04-27T06:32:42.161Z","repository":{"id":203812910,"uuid":"685021383","full_name":"widgetbook/widgetbook_4","owner":"widgetbook","description":"The API design of Widgetbook 4","archived":false,"fork":false,"pushed_at":"2023-11-14T15:05:56.000Z","size":122,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-30T13:12:16.284Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/widgetbook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-08-30T10:48:51.000Z","updated_at":"2025-06-01T02:07:23.000Z","dependencies_parsed_at":"2024-11-18T23:09:50.655Z","dependency_job_id":"d4a714c7-1e74-4d04-8c9f-b22bb07a5d0d","html_url":"https://github.com/widgetbook/widgetbook_4","commit_stats":null,"previous_names":["widgetbook/widgetbook_4"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/widgetbook/widgetbook_4","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgetbook%2Fwidgetbook_4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgetbook%2Fwidgetbook_4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgetbook%2Fwidgetbook_4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgetbook%2Fwidgetbook_4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/widgetbook","download_url":"https://codeload.github.com/widgetbook/widgetbook_4/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widgetbook%2Fwidgetbook_4/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32325933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-18T23:09:45.793Z","updated_at":"2026-04-27T06:32:37.152Z","avatar_url":"https://github.com/widgetbook.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Widgetbook 4: A Clean Slate\n\n## Why?\n\nWidgetbook 3 is now facing some issues that result in a bad developer experience or some limitations. These issues are:\n\n1. There is no defined structure for **projects**. It can be defined inside the `lib`, `test` or `widgetbook` folders, and each one has it’s pros and cons.\n1. Generator is slow inside big projects, because all `.dart` files are taken as an input.\n1. Mocking use-cases dependencies is not easy, because using mocking library is weird thing to do if `widgetbook` is not a dev dependency.\n1. There is no defined structure for **use-cases**. Users can do any of the following setups:\n   - They can define use-cases in the same file as the widget.\n   - They can define all use-cases from different components in one file.\n1. Use-cases are **not reusable for tests**, they cannot be easily used for golden or widget tests.\n1. Users need to define the `label` for knobs using a magic string that usually is the same name as the parameter name.\n1. CLI is not actively used by users, which makes some features hard to implement.\n\n## Solution\n\nIn 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.\n\n### Terminology\n\nSome terminologies (along with their code names) will be changed as follows:\n\n| Old Name | New Name |\n| -------- | -------- |\n| Use-case | Story    |\n| Addon    | Mode     |\n| Knob     | Arg      |\n\n### Project Structure\n\nWidgetbook projects will now be defined inside a **separate package** as follows:\n\n```\n# Polyrepo\n├── lib/\n├── test/\n├── widgetbook/\n│   └── pubspec.yaml # widgetbook_workspace\n└── pubspec.yaml # app\n\n# Monorepo\n├── apps/\n│   ├── app_1/\n│   └── app_2/\n├── packages/\n│   ├── package_1/\n│   └── package_2/\n└── widgetbook/\n    └── pubspec.yaml # widgetbook_workspace\n\n# Unsupported Polyrepo\n├── lib/\n├── test/\n├── widgetbook/ # folder not project, for simplicity\n└── pubspec.yaml # app\n```\n\nThere will be an **intentional cyclic dependency** _(sorry for using the c-word, we know it hurts)_ between `widgetbook_workspace` projects and `app` projects because:\n\n1. `widgetbook_workspace` project needs dependency on `app` to catalog the widgets defined there.\n2. `app` needs dependency on `widgetbook_workspace` to define the tests inside the `test` folder, re-using the stories defined in the workspace.\n\n### Story Structure\n\n\u003e [!IMPORTANT]\n\u003e Full code can be found in [`button.stories.dart`](./example/widgetbook/lib/button.stories.dart) or [`home_screen.stories.dart`](./example/widgetbook/lib/home_screen.stories.dart).\n\nStories will now be created in a file named `\u003ccomponent\u003e.stories.dart`. The `.stories.dart` file extension makes it easier for the generator to find these files. This file will contain:\n\n1. Metadata about the Component itself (e.g. name, description, etc.)\n2. Stories definitions.\n\nThe workflow for cataloging widgets will be as follows:\n\n1. Write the widget as usual in a file named `\u003ccomponent\u003e.dart` inside the **app directory**. Here is an example of a `Button` widget defined in [`button.dart`](./example/lib/button.dart):\n\n   ```dart\n   /// A button to click on.\n   class Button extends StatelessWidget {\n     const Button({\n       super.key,\n       required this.text,\n       required this.color,\n     });\n\n     /// The text of this button.\n     final String text;\n\n     /// The background color of this button.\n     final Color color;\n\n     @override\n     Widget build(BuildContext context) {\n       return Container(\n         color: color,\n         child: Text(text),\n       );\n     }\n   }\n   ```\n\n1. Create a file named [`button.stories.dart`](./example/widgetbook/lib/button.stories.dart) inside the **`widgetbook` directory** with the following content:\n\n   ```dart\n   import 'package:user_app/button.dart';\n\n   part 'button.stories.g.dart';\n\n   const metadata = ComponentMetadata(\n     type: Button, // Used to for code generation\n     // Optional config here...\n   );\n   ```\n\n1. After running the generator _(or possibly a Widgetbook CLI command)_, the following content will be generated in [`button.stories.g.dart`](./example/widgetbook/lib/button.stories.g.dart):\n\n   ```dart\n   part of 'button.stories.dart';\n\n   typedef ButtonScenario = WidgetbookScenario\u003cButton\u003e;\n\n   class ButtonStory extends WidgetbookStory\u003cButton, ButtonArgs\u003e { ... }\n\n   class ButtonArgs extends WidgetbookArgs\u003cButton\u003e { ... }\n   ```\n\n1. They can now define stories in [`button.stories.dart`](./example/widgetbook/lib/button.stories.dart) with the following content using the generated classes\n\n   ```dart\n   final $DefaultButton = ButtonStory(\n     name: 'Default',\n     args: ButtonArgs(\n       text: StringArg('Press'),\n       color: ColorArg(\n         Colors.red,\n         name: 'Background Color',\n         description: '....',\n       ),\n     ),\n   );\n   ```\n\n### Golden Tests Structure\n\n\u003e [!IMPORTANT]\n\u003e Full code can be found in [`golden_test.dart`](./example/test/golden_test.dart).\n\nWhen 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.\n\n1. **Single Scenario:**\n\n   ```dart\n   ButtonScenario(\n     story: $DefaultButton,\n     modes: [],\n     args: ButtonArgs(\n       color: ColorArg(Colors.black),\n       text: StringArg('Very LongLongLongLongLong Text'),\n     ),\n   ),\n   ```\n\n1. **Matrix Scenario:**  \n   Generates 4 scenarios in the following case:\n\n   1. Dark Theme + First Args\n   2. Dark Theme + Second Args\n   3. Light Theme + First Args\n   4. Light Theme + Second Args\n\n   ```dart\n   ButtonScenario.matrix(\n     story: $DefaultButton,\n     modes: [\n      [ThemeMode.value(ThemeData.dark())], // Dark Theme\n      [ThemeMode.value(ThemeData.light())] // Light Theme\n     ],\n     args: [\n       ButtonArgs(...), // First Args\n       ButtonArgs(...), // Second Args\n     ],\n   )\n   ```\n\n## CLI 4\n\nWidgetbook 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:\n\n| Command                     | Description                                                                         |\n| --------------------------- | ----------------------------------------------------------------------------------- |\n| `widgetbook init`           | Creates a new project template, could prompt for Widgetbook Cloud or GitHub Actions |\n| `widgetbook login`          | Gets Widgetbook Cloud API key via a login redirect, and stores it                   |\n| `widgetbook run \u003cplatform\u003e` | Similar to `flutter run`                                                            |\n| `widgetbook gen`            | Similar to `dart run build_runner` to generate the stories files                    |\n\n## VSCode Plugin\n\nWe can have a plugin that helps:\n\n1. Navigating between Widget file and Stories file.\n2. Creating a template file for a story.\n\n## Consequences\n\n1. `widgetbook_annotation` will no longer be needed.\n\n## Migration Plan\n\nThe 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.\n\nAll breaking changes will then be done and a new major release will be available.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidgetbook%2Fwidgetbook_4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwidgetbook%2Fwidgetbook_4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidgetbook%2Fwidgetbook_4/lists"}