{"id":13471363,"url":"https://github.com/rrousselGit/functional_widget","last_synced_at":"2025-03-26T13:31:01.045Z","repository":{"id":39423935,"uuid":"159969665","full_name":"rrousselGit/functional_widget","owner":"rrousselGit","description":"A code generator to write widgets as function without loosing the benefits of classes.","archived":false,"fork":false,"pushed_at":"2025-03-24T12:27:52.000Z","size":225,"stargazers_count":604,"open_issues_count":7,"forks_count":48,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-25T15:19:25.674Z","etag":null,"topics":["code-generator","dart","flutter","function","widget"],"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/rrousselGit.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":"2018-12-01T17:28:50.000Z","updated_at":"2025-03-24T12:27:56.000Z","dependencies_parsed_at":"2024-06-18T15:23:25.555Z","dependency_job_id":"f604e562-a51e-48a2-bd27-e5bbc346d978","html_url":"https://github.com/rrousselGit/functional_widget","commit_stats":null,"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrousselGit%2Ffunctional_widget","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrousselGit%2Ffunctional_widget/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrousselGit%2Ffunctional_widget/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rrousselGit%2Ffunctional_widget/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rrousselGit","download_url":"https://codeload.github.com/rrousselGit/functional_widget/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245486358,"owners_count":20623244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["code-generator","dart","flutter","function","widget"],"created_at":"2024-07-31T16:00:43.685Z","updated_at":"2025-03-26T13:31:01.019Z","avatar_url":"https://github.com/rrousselGit.png","language":"Dart","readme":"[![Build](https://github.com/rrousselGit/functional_widget/actions/workflows/build.yml/badge.svg)](https://github.com/rrousselGit/functional_widget/actions/workflows/build.yml)\n[![pub package](https://img.shields.io/pub/v/functional_widget.svg)](https://pub.dartlang.org/packages/functional_widget) [![pub package](https://img.shields.io/badge/Awesome-Flutter-blue.svg?longCache=true\u0026style=flat-square)](https://github.com/Solido/awesome-flutter)\n\nWidgets are cool. But classes are quite verbose:\n\n```dart\nclass Foo extends StatelessWidget {\n  final int value;\n  final int value2;\n\n  const Foo({Key key, this.value, this.value2}) : super(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    return Text('$value $value2');\n  }\n}\n```\n\nSo much code for something that could be done much better using a plain function:\n\n```dart\nWidget foo(BuildContext context, { int value, int value2 }) {\n  return Text('$value $value2');\n}\n```\n\nThe problem is, using functions instead of classes is not recommended:\n\n- https://stackoverflow.com/questions/53234825/what-is-the-difference-between-functions-and-classes-to-create-widgets/53234826#53234826\n- https://github.com/flutter/flutter/issues/19269\n\n... Or is it?\n\n---\n\n_functional_widgets_, is an attempt to solve this issue, using a code generator.\n\nSimply write your widget as a function, decorate it with a `@swidget`, and then\nthis library will generate a class for you to use.\n\nAs the added benefit, you also get for free the ability to inspect the parameters\npassed to your widgets in the devtool\n\n## Example\n\nYou write:\n\n```dart\n@swidget\nWidget foo(BuildContext context, int value) {\n  return Text('$value');\n}\n```\n\nIt generates:\n\n```dart\nclass Foo extends StatelessWidget {\n  const Foo(this.value, {Key key}) : super(key: key);\n\n  final int value;\n\n  @override\n  Widget build(BuildContext context) {\n    return foo(context, value);\n  }\n\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties.add(IntProperty('value', value));\n  }\n}\n```\n\nAnd then you use it:\n\n```dart\nrunApp(\n  Foo(42)\n);\n```\n\n## How to use\n\n### Install (builder)\n\nThere are a few separate packages you need to install:\n\n- `functional_widget_annotation`, a package containing decorators. You must\n  install it as `dependencies`.\n- `functional_widget`, a code-generator that uses the decorators from the previous\n  packages to generate your widget.\n- `build_runner`, a dependency that all applications using code-generation should have\n\nYour `pubspec.yaml` should look like:\n\n```yaml\ndependencies:\n  functional_widget_annotation: ^0.8.0\n\ndev_dependencies:\n  functional_widget: ^0.8.0\n  build_runner: ^1.9.0\n```\n\nThat's it!\n\nYou can then start the code-generator with:\n\n```sh\nflutter pub run build_runner watch\n```\n\n## Customize the output\n\nIt is possible to customize the output of the generator by using different decorators or configuring default values in `build.yaml` file.\n\n`build.yaml` change the default behavior of a configuration.\n\n```yaml\n# build.yaml\ntargets:\n  $default:\n    builders:\n      functional_widget:\n        options:\n          # Default values:\n          debugFillProperties: false\n          widgetType: stateless # or 'hook'\n```\n\n`FunctionalWidget` decorator will override the default behavior for one specific widget.\n\n```dart\n@FunctionalWidget(\n  debugFillProperties: true,\n  widgetType: FunctionalWidgetType.hook,\n)\nWidget foo() =\u003e Container();\n```\n\n### debugFillProperties override\n\nWidgets can be override `debugFillProperties` to display custom fields on the widget inspector. `functional_widget` offer to generate these bits for your, by enabling `debugFillProperties` option.\n\nFor this to work, it is required to add the following import:\n\n```dart\nimport 'package:flutter/foundation.dart';\n```\n\nExample:\n\n(You write)\n\n```dart\nimport 'package:flutter/foundation.dart';\n\npart 'example.g.dart';\n\n@swidget\nWidget example(int foo, String bar) =\u003e Container();\n```\n\n(It generates)\n\n```dart\nclass Example extends StatelessWidget {\n  const Example(this.foo, this.bar, {Key key}) : super(key: key);\n\n  final int foo;\n\n  final String bar;\n\n  @override\n  Widget build(BuildContext _context) =\u003e example(foo, bar);\n  @override\n  void debugFillProperties(DiagnosticPropertiesBuilder properties) {\n    super.debugFillProperties(properties);\n    properties.add(IntProperty('foo', foo));\n    properties.add(StringProperty('bar', bar));\n  }\n}\n```\n\n### Generate different type of widgets\n\nBy default, the generated widget by `@FunctionalWidget()` is a `StatelessWidget`.\n\nIt is possible to generate:\n\n- a `HookWidget` (from https://github.com/rrousselGit/flutter_hooks)\n- a `HookConsumerWidget` (from [hooks_riverpod](https://pub.dev/packages/hooks_riverpod))\n- a `ConsumerWidget` (from [flutter_riverpod](https://pub.dev/packages/flutter_riverpod))\n\nThere are a few ways to do so:\n\n- With the shorthand `@hwidget` decorator:\n\n  ```dart\n  @hwidget // Creates a HookWidget\n  Widget example(int foo, String bar) =\u003e Container();\n\n  @hcwidget // Creates a HookConsumerWidget\n  Widget example(WidgetRef ref, int foo, String bar) =\u003e Container();\n\n  @cwidget // Creates a ConsumerWidget\n  Widget example(WidgetRef ref, int foo, String bar) =\u003e Container();\n  ```\n\n- Through `build.yaml`:\n\n  ```yaml\n  # build.yaml\n  targets:\n    $default:\n      builders:\n        functional_widget:\n          options:\n            widgetType: hook\n  ```\n\n  then used as:\n\n  ```dart\n  @FunctionalWidget()\n  Widget example(int foo, String bar) =\u003e Container();\n  ```\n\n- With parameters on the `@FunctionalWidget` decorator:\n\n  ```dart\n  @FunctionalWidget(widgetType: FunctionalWidgetType.hook)\n  Widget example(int foo, String bar) =\u003e Container();\n  ```\n\nIn any cases, you will need to install the corresponding package separately, by\nadding either `flutter_hooks`/`flutter_riverpod` or `hooks_riverpod` to your `pubspec.yaml`\n\n```yaml\ndependencies:\n  flutter_hooks: # some version number\n```\n\n### All the potential function prototypes\n\n_functional_widget_ will inject widget specific parameters if you ask for them.\nYou can potentially write any of the following:\n\n```dart\nWidget foo();\nWidget foo(BuildContext context);\nWidget foo(Key key);\nWidget foo(BuildContext context, Key key);\nWidget foo(Key key, BuildContext context);\n```\n\nYou can then add however many arguments you like **after** the previously defined arguments. They will then be added to the class constructor and as a widget field:\n\n- positional\n\n```dart\n@swidget\nWidget foo(int value) =\u003e Text(value.toString());\n\n// USAGE\n\nFoo(42);\n```\n\n- named:\n\n```dart\n@swidget\nWidget foo({int value}) =\u003e Text(value.toString());\n\n// USAGE\n\nFoo(value: 42);\n```\n\n- A bit of everything:\n\n```dart\n@swidget\nWidget foo(BuildContext context, int value, { int value2 }) {\n  return Text('$value $value2');\n}\n\n// USAGE\n\nFoo(42, value2: 24);\n```\n\n### Private vs public widgets\n\nIn order to allow for private function definitions but exported widgets, all\ndecorated widget functions with a single underscore will generate an exported widget.\n\n```dart\n@swidget\nWidget _foo(BuildContext context, int value, { int value2 }) {\n  return Text('$value $value2');\n}\n\n// USAGE\n\nFoo(42, value2: 24);\n```\n\nIn order to keep generated widget private, do use two underscores:\n\n```dart\n@swidget\nWidget __foo(BuildContext context, int value, { int value2 }) {\n  return Text('$value $value2');\n}\n\n// USAGE\n\n_Foo(42, value2: 24);\n```\n\n## Sponsors\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://raw.githubusercontent.com/rrousselGit/freezed/master/sponsorkit/sponsors.svg\"\u003e\n    \u003cimg src='https://raw.githubusercontent.com/rrousselGit/freezed/master/sponsorkit/sponsors.svg'/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","funding_links":[],"categories":["Dart","框架","Widgets [🔝](#readme)","Frameworks"],"sub_categories":["Widgets"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FrrousselGit%2Ffunctional_widget","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FrrousselGit%2Ffunctional_widget","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FrrousselGit%2Ffunctional_widget/lists"}