Custom Addon

Custom addons in Widgetbook offer the flexibility to tailor your development environment according to the unique needs of your project. We will explore two examples, simple and advanced, demonstrating the process of creating custom addons.

Setup

To create a custom Addons, follow these steps:

  • Define a model for your custom Addon. This model will hold the data and behavior of your Addon.
  • Create a new class that extends the WidgetbookAddon class with a generic parameter corresponding to your defined model.

Writing a custom Alignment Addon

Here's an example demonstrating how to create a simple Alignment Addon:

import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';

class AlignmentAddon extends WidgetbookAddon<Alignment> {
  final Alignment initialAlignment;

  AlignmentAddon({
    this.initialAlignment = Alignment.center,
  }) : super(name: 'Alignment');

  @override
  Widget buildUseCase(
    BuildContext context,
    Widget child,
    Alignment setting,
  ) {
    // customize how the use case is built using your custom Addon
    return Align(
      alignment: setting,
      child: child,
    );
  }

  @override
  List<Field<Alignment>> get fields {
    return [
      ListField<Alignment>(
        name: 'alignment',
        initialValue: initialAlignment,
        values: [
          Alignment.topLeft,
          Alignment.topCenter,
          Alignment.topRight,
          Alignment.centerLeft,
          Alignment.center,
          Alignment.centerRight,
          Alignment.bottomLeft,
          Alignment.bottomCenter,
          Alignment.bottomRight,
        ],
      )
    ];
  }

  @override
  Alignment valueFromQueryGroup(Map<String, String> group) {
    return valueOf<Alignment>('alignment', group)!;
  }
}

In this example, we create a AlignmentAddon that manages a Alignment value. The initialSetting is the initial state of the Alignment value. The fields list contains a single ListField which represents the Alignment value managed by the addon in the Widgetbook UI

Let's break down the code to understand better.

class AlignmentAddon extends WidgetbookAddon<Alignment> {

We create a new class called AlignmentAddon, which extends WidgetbookAddon. The Alignment generic indicates that this addon will handle a Alignment value.

class AlignmentAddon extends WidgetbookAddon<Alignment> {
  final Alignment initialAlignment;

  AlignmentAddon({
    this.initialAlignment = Alignment.center,
  }) : super(name: 'Alignment');

The constructor for AlignmentAddon takes a parameter. initialAlignment is Alignment with default value, if provided, will be used as the initial value of the addon.

We define one final fields in the class, alignment, to hold the values passed in from the constructor. You may add more fields if necessitates.

  @override
  Widget buildUseCase(
    BuildContext context,
    Widget child,
    Alignment setting,
  ) {
    return Align(
      alignment: setting,
      child: child,
    );
  }

The buildUseCase method is where we specify how the addon will affect the widget tree. It's an abstract method from the WidgetbookAddon class that we need to implement. It takes three parameters: a BuildContext, a Widget that is the child of this addon, and a Alignment that is the current setting of the addon. For now, we wrap the child widget with an Align widget that uses the setting parameter (which is the current Alignment setting for this addon) as its alignment value.

    @override
  List<Field<Alignment>> get fields {
    return [
      ListField<Alignment>(
        name: 'alignment',
        initialValue: initialAlignment,
        values: [
          Alignment.topLeft,
          Alignment.topCenter,
          Alignment.topRight,
          Alignment.centerLeft,
          Alignment.center,
          Alignment.centerRight,
          Alignment.bottomLeft,
          Alignment.bottomCenter,
          Alignment.bottomRight,
        ],
      )
    ];
  }

The fields getter is where we specify the fields that will represent the addon in the Widgetbook UI. Each field corresponds to an input field in the UI. In this case, we have a single ListField with an initial value of initialAlignment and values of possible alignments for Align widget.

  @override
  Alignment valueFromQueryGroup(Map<String, String> group) {
    return valueOf<Alignment>('alignment', group) ?? initialAlignment;
  }

Lastly, the valueFromQueryGroup method is overridden. This method is responsible for generating a new Alignment setting for the addon from the URL's query parameters. It uses the helper method valueOf to extract the Alignment value associated with the 'alignment' key from the group map. If the value is not found (i.e., it's null), it falls back to the initialAlignment.

Congratulation! you have managed to created your first custom Addon that wraps Align widget. So now, nothing cannot stop you to write what your project need.

Field Types in Widgetbook

For more detailed information, visit the Fields page.