Add Widgetbook setup with theme configuration, analysis options, and initial component use cases
This commit is contained in:
parent
d3ad4b9c9d
commit
80ca8f665a
46 changed files with 6031 additions and 2 deletions
37
widgetbook/lib/app_bar_m3e/INDEX-app_bar_m3e.md
Normal file
37
widgetbook/lib/app_bar_m3e/INDEX-app_bar_m3e.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# INDEX — app_bar_m3e
|
||||
|
||||
This index lists all components in the app_bar_m3e package and their Widgetbook variants generated under packages/app_bar_m3e/lib/widgetbook.
|
||||
|
||||
## Components and Variants
|
||||
|
||||
- AppBarM3E
|
||||
- default
|
||||
- with_icon
|
||||
- with_label
|
||||
- without_label
|
||||
- small
|
||||
- medium
|
||||
- large
|
||||
- long_text
|
||||
- many_actions
|
||||
- shape_family
|
||||
- semantics_label
|
||||
|
||||
- SliverAppBarM3E
|
||||
- default
|
||||
- small
|
||||
- medium
|
||||
- large
|
||||
- pinned
|
||||
- floating
|
||||
- snap
|
||||
- long_text
|
||||
- many_actions
|
||||
- shape_family
|
||||
- density
|
||||
- semantics_label
|
||||
|
||||
## Notes
|
||||
- Variants use Widgetbook knobs for critical parameters (title, behavior flags), and visual options (density, shape, colors) according to the plan/guide.md.
|
||||
- Callbacks emit print statements with clear variant context.
|
||||
- Complex objects are avoided or provided with sensible defaults; future enhancements can expand these demos.
|
||||
191
widgetbook/lib/app_bar_m3e/app_bar_m3e_usecases.dart
Normal file
191
widgetbook/lib/app_bar_m3e/app_bar_m3e_usecases.dart
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
import 'package:app_bar_m3e/app_bar_m3e.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
import 'package:widgetbook_annotation/widgetbook_annotation.dart';
|
||||
|
||||
// Helper: build a list of action buttons with informative prints
|
||||
List<Widget> _buildActions(int count) {
|
||||
return List.generate(count, (i) {
|
||||
return IconButton(
|
||||
tooltip: 'Action \'${i + 1}\'',
|
||||
icon:
|
||||
Icon([Icons.search, Icons.tune, Icons.more_vert, Icons.share][i % 4]),
|
||||
onPressed: () => print('[AppBarM3E] action ${i + 1} pressed'),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@UseCase(name: 'default', type: AppBarM3E)
|
||||
Widget buildAppBarM3EDefaultUseCase(BuildContext context) {
|
||||
final centerTitle =
|
||||
context.knobs.boolean(label: 'centerTitle', initialValue: false);
|
||||
final title = context.knobs.string(label: 'title', initialValue: 'App Bar');
|
||||
final bg = context.knobs.colorOrNull(label: 'backgroundColor');
|
||||
final fg = context.knobs.colorOrNull(label: 'foregroundColor');
|
||||
final elevation = context.knobs.doubleOrNull.input(label: 'elevation');
|
||||
final shapeFamily = context.knobs.object.dropdown<AppBarM3EShapeFamily>(
|
||||
label: 'shapeFamily',
|
||||
initialOption: AppBarM3EShapeFamily.round,
|
||||
options: const [AppBarM3EShapeFamily.round, AppBarM3EShapeFamily.square],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final density = context.knobs.object.dropdown<AppBarM3EDensity>(
|
||||
label: 'density',
|
||||
initialOption: AppBarM3EDensity.regular,
|
||||
options: const [AppBarM3EDensity.regular, AppBarM3EDensity.compact],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final toolbarHeight =
|
||||
context.knobs.doubleOrNull.input(label: 'toolbarHeight');
|
||||
final implyLeading = context.knobs
|
||||
.boolean(label: 'automaticallyImplyLeading', initialValue: true);
|
||||
final clip = context.knobs.object.dropdown<Clip>(
|
||||
label: 'clipBehavior',
|
||||
initialOption: Clip.none,
|
||||
options: const [
|
||||
Clip.none,
|
||||
Clip.hardEdge,
|
||||
Clip.antiAlias,
|
||||
Clip.antiAliasWithSaveLayer
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final actionsCount = context.knobs.int
|
||||
.slider(label: 'actions', initialValue: 1, min: 0, max: 5);
|
||||
|
||||
return AppBarM3E(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.menu),
|
||||
onPressed: () => print('[AppBarM3E] leading pressed'),
|
||||
),
|
||||
titleText: title,
|
||||
centerTitle: centerTitle,
|
||||
backgroundColor: bg,
|
||||
foregroundColor: fg,
|
||||
elevation: elevation,
|
||||
shapeFamily: shapeFamily,
|
||||
density: density,
|
||||
toolbarHeight: toolbarHeight,
|
||||
automaticallyImplyLeading: implyLeading,
|
||||
clipBehavior: clip,
|
||||
actions: _buildActions(actionsCount),
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'with_icon', type: AppBarM3E)
|
||||
Widget buildAppBarM3EWithIconUseCase(BuildContext context) {
|
||||
return AppBarM3E(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.menu),
|
||||
onPressed: () => print('[AppBarM3E] menu tapped'),
|
||||
),
|
||||
titleText: context.knobs.string(label: 'title', initialValue: 'With icon'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.search),
|
||||
onPressed: () => print('[AppBarM3E] search tapped'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'with_label', type: AppBarM3E)
|
||||
Widget buildAppBarM3EWithLabelUseCase(BuildContext context) {
|
||||
return AppBarM3E(
|
||||
title: Text(
|
||||
context.knobs.string(label: 'label', initialValue: 'Title Widget'),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
centerTitle:
|
||||
context.knobs.boolean(label: 'centerTitle', initialValue: true),
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'without_label', type: AppBarM3E)
|
||||
Widget buildAppBarM3EWithoutLabelUseCase(BuildContext context) {
|
||||
return AppBarM3E(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => print('[AppBarM3E] back tapped'),
|
||||
),
|
||||
actions: _buildActions(context.knobs.int
|
||||
.slider(label: 'actions', initialValue: 2, min: 0, max: 6)),
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'small', type: AppBarM3E)
|
||||
Widget buildAppBarM3ESmallUseCase(BuildContext context) {
|
||||
final h = context.knobs.double
|
||||
.slider(label: 'height', initialValue: 56, min: 40, max: 80);
|
||||
return AppBarM3E(
|
||||
titleText: 'Small',
|
||||
toolbarHeight: h,
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'medium', type: AppBarM3E)
|
||||
Widget buildAppBarM3EMediumUseCase(BuildContext context) {
|
||||
final h = context.knobs.double
|
||||
.slider(label: 'height', initialValue: 64, min: 48, max: 96);
|
||||
return AppBarM3E(
|
||||
titleText: 'Medium',
|
||||
toolbarHeight: h,
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'large', type: AppBarM3E)
|
||||
Widget buildAppBarM3ELargeUseCase(BuildContext context) {
|
||||
final h = context.knobs.double
|
||||
.slider(label: 'height', initialValue: 72, min: 56, max: 120);
|
||||
return AppBarM3E(
|
||||
titleText: 'Large',
|
||||
toolbarHeight: h,
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'long_text', type: AppBarM3E)
|
||||
Widget buildAppBarM3ELongTextUseCase(BuildContext context) {
|
||||
final repeat = context.knobs.int
|
||||
.slider(label: 'repeat', initialValue: 3, min: 1, max: 10);
|
||||
final base =
|
||||
context.knobs.string(label: 'base', initialValue: 'A very long title');
|
||||
return AppBarM3E(
|
||||
titleText: List.filled(repeat, base).join(' • '),
|
||||
centerTitle:
|
||||
context.knobs.boolean(label: 'centerTitle', initialValue: false),
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'many_actions', type: AppBarM3E)
|
||||
Widget buildAppBarM3EManyActionsUseCase(BuildContext context) {
|
||||
final count = context.knobs.int
|
||||
.slider(label: 'actions', initialValue: 4, min: 0, max: 10);
|
||||
return AppBarM3E(
|
||||
titleText: 'Many actions',
|
||||
actions: _buildActions(count),
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'shape_family', type: AppBarM3E)
|
||||
Widget buildAppBarM3EShapeFamilyUseCase(BuildContext context) {
|
||||
final family = context.knobs.object.dropdown<AppBarM3EShapeFamily>(
|
||||
label: 'shapeFamily',
|
||||
initialOption: AppBarM3EShapeFamily.round,
|
||||
options: const [AppBarM3EShapeFamily.round, AppBarM3EShapeFamily.square],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
return AppBarM3E(
|
||||
titleText: 'Shape: ${family.name}',
|
||||
shapeFamily: family,
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'semantics_label', type: AppBarM3E)
|
||||
Widget buildAppBarM3ESemanticsLabelUseCase(BuildContext context) {
|
||||
final label = context.knobs
|
||||
.string(label: 'semanticLabel', initialValue: 'Primary application bar');
|
||||
return AppBarM3E(
|
||||
titleText: 'Semantics',
|
||||
semanticLabel: label,
|
||||
);
|
||||
}
|
||||
248
widgetbook/lib/app_bar_m3e/sliver_app_bar_m3e_usecases.dart
Normal file
248
widgetbook/lib/app_bar_m3e/sliver_app_bar_m3e_usecases.dart
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
import 'package:app_bar_m3e/app_bar_m3e.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:widgetbook/widgetbook.dart';
|
||||
import 'package:widgetbook_annotation/widgetbook_annotation.dart';
|
||||
|
||||
List<Widget> _buildActions(int count) => List.generate(count, (i) {
|
||||
return IconButton(
|
||||
tooltip: 'Action \'${i + 1}\'',
|
||||
icon: Icon(
|
||||
[Icons.search, Icons.tune, Icons.more_vert, Icons.share][i % 4]),
|
||||
onPressed: () => print('[SliverAppBarM3E] action ${i + 1} pressed'),
|
||||
);
|
||||
});
|
||||
|
||||
Widget _demoScrollBody({required SliverAppBarM3E appBar}) {
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
appBar,
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => ListTile(
|
||||
title: Text('Item #${index + 1}'),
|
||||
onTap: () => print('[Sliver] tapped item ${index + 1}'),
|
||||
),
|
||||
childCount: 30,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@UseCase(name: 'default', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EDefaultUseCase(BuildContext context) {
|
||||
final title =
|
||||
context.knobs.string(label: 'title', initialValue: 'Sliver App Bar');
|
||||
final centerTitle =
|
||||
context.knobs.boolean(label: 'centerTitle', initialValue: false);
|
||||
final pinned = context.knobs.boolean(label: 'pinned', initialValue: true);
|
||||
final floating =
|
||||
context.knobs.boolean(label: 'floating', initialValue: false);
|
||||
final snap = context.knobs.boolean(label: 'snap', initialValue: false);
|
||||
final variant = context.knobs.object.dropdown<AppBarM3EVariant>(
|
||||
label: 'variant',
|
||||
initialOption: AppBarM3EVariant.medium,
|
||||
options: const [
|
||||
AppBarM3EVariant.small,
|
||||
AppBarM3EVariant.medium,
|
||||
AppBarM3EVariant.large
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final shapeFamily = context.knobs.object.dropdown<AppBarM3EShapeFamily>(
|
||||
label: 'shapeFamily',
|
||||
initialOption: AppBarM3EShapeFamily.round,
|
||||
options: const [AppBarM3EShapeFamily.round, AppBarM3EShapeFamily.square],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final density = context.knobs.object.dropdown<AppBarM3EDensity>(
|
||||
label: 'density',
|
||||
initialOption: AppBarM3EDensity.regular,
|
||||
options: const [AppBarM3EDensity.regular, AppBarM3EDensity.compact],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final bg = context.knobs.colorOrNull(label: 'backgroundColor');
|
||||
final fg = context.knobs.colorOrNull(label: 'foregroundColor');
|
||||
final actionsCount = context.knobs.int
|
||||
.slider(label: 'actions', initialValue: 1, min: 0, max: 6);
|
||||
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: title,
|
||||
centerTitle: centerTitle,
|
||||
pinned: pinned,
|
||||
floating: floating,
|
||||
snap: snap,
|
||||
variant: variant,
|
||||
shapeFamily: shapeFamily,
|
||||
density: density,
|
||||
backgroundColor: bg,
|
||||
foregroundColor: fg,
|
||||
actions: _buildActions(actionsCount),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'small', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3ESmallUseCase(BuildContext context) {
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Small',
|
||||
variant: AppBarM3EVariant.small,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'medium', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EMediumUseCase(BuildContext context) {
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Medium',
|
||||
variant: AppBarM3EVariant.medium,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'large', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3ELargeUseCase(BuildContext context) {
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Large',
|
||||
variant: AppBarM3EVariant.large,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'pinned', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EPinnedUseCase(BuildContext context) {
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Pinned',
|
||||
pinned: true,
|
||||
floating: false,
|
||||
snap: false,
|
||||
variant: context.knobs.object.dropdown<AppBarM3EVariant>(
|
||||
label: 'variant',
|
||||
initialOption: AppBarM3EVariant.medium,
|
||||
options: const [
|
||||
AppBarM3EVariant.small,
|
||||
AppBarM3EVariant.medium,
|
||||
AppBarM3EVariant.large
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'floating', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EFloatingUseCase(BuildContext context) {
|
||||
final snap = context.knobs.boolean(label: 'snap', initialValue: false);
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Floating',
|
||||
pinned: false,
|
||||
floating: true,
|
||||
snap: snap,
|
||||
variant: context.knobs.object.dropdown<AppBarM3EVariant>(
|
||||
label: 'variant',
|
||||
initialOption: AppBarM3EVariant.medium,
|
||||
options: const [
|
||||
AppBarM3EVariant.small,
|
||||
AppBarM3EVariant.medium,
|
||||
AppBarM3EVariant.large
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'snap', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3ESnapUseCase(BuildContext context) {
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Snap',
|
||||
pinned: false,
|
||||
floating: true,
|
||||
snap: true,
|
||||
variant: context.knobs.object.dropdown<AppBarM3EVariant>(
|
||||
label: 'variant',
|
||||
initialOption: AppBarM3EVariant.medium,
|
||||
options: const [
|
||||
AppBarM3EVariant.small,
|
||||
AppBarM3EVariant.medium,
|
||||
AppBarM3EVariant.large
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'long_text', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3ELongTextUseCase(BuildContext context) {
|
||||
final repeat = context.knobs.int
|
||||
.slider(label: 'repeat', initialValue: 3, min: 1, max: 10);
|
||||
final base =
|
||||
context.knobs.string(label: 'base', initialValue: 'A very long title');
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: List.filled(repeat, base).join(' • '),
|
||||
variant: context.knobs.object.dropdown<AppBarM3EVariant>(
|
||||
label: 'variant',
|
||||
initialOption: AppBarM3EVariant.medium,
|
||||
options: const [
|
||||
AppBarM3EVariant.small,
|
||||
AppBarM3EVariant.medium,
|
||||
AppBarM3EVariant.large
|
||||
],
|
||||
labelBuilder: (v) => v.name,
|
||||
),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'many_actions', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EManyActionsUseCase(BuildContext context) {
|
||||
final count = context.knobs.int
|
||||
.slider(label: 'actions', initialValue: 4, min: 0, max: 10);
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Many actions',
|
||||
actions: _buildActions(count),
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'shape_family', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EShapeFamilyUseCase(BuildContext context) {
|
||||
final family = context.knobs.object.dropdown<AppBarM3EShapeFamily>(
|
||||
label: 'shapeFamily',
|
||||
initialOption: AppBarM3EShapeFamily.round,
|
||||
options: const [AppBarM3EShapeFamily.round, AppBarM3EShapeFamily.square],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Shape: ' + family.name,
|
||||
shapeFamily: family,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'density', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3EDensityUseCase(BuildContext context) {
|
||||
final density = context.knobs.object.dropdown<AppBarM3EDensity>(
|
||||
label: 'density',
|
||||
initialOption: AppBarM3EDensity.regular,
|
||||
options: const [AppBarM3EDensity.regular, AppBarM3EDensity.compact],
|
||||
labelBuilder: (v) => v.name,
|
||||
);
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Density: ' + density.name,
|
||||
density: density,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
|
||||
@UseCase(name: 'semantics_label', type: SliverAppBarM3E)
|
||||
Widget buildSliverAppBarM3ESemanticsLabelUseCase(BuildContext context) {
|
||||
final label = context.knobs
|
||||
.string(label: 'semanticLabel', initialValue: 'Scrollable app bar');
|
||||
final appBar = SliverAppBarM3E(
|
||||
titleText: 'Semantics',
|
||||
semanticLabel: label,
|
||||
);
|
||||
return _demoScrollBody(appBar: appBar);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue