{"id":13549570,"url":"https://github.com/rodydavis/flutter_json_widgets","last_synced_at":"2025-04-23T13:41:49.296Z","repository":{"id":101928594,"uuid":"583402173","full_name":"rodydavis/flutter_json_widgets","owner":"rodydavis","description":"Build flutter widgets with pure dart classes","archived":false,"fork":false,"pushed_at":"2023-01-06T09:06:22.000Z","size":35650,"stargazers_count":73,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-23T13:41:42.573Z","etag":null,"topics":["dart","dynamic-widget","flutter","widget-builder","widgets"],"latest_commit_sha":null,"homepage":"https://rodydavis.github.io/flutter_json_widgets/docs/","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rodydavis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2022-12-29T17:09:14.000Z","updated_at":"2025-04-20T10:19:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"847070b6-153b-44b6-80fa-3a17eb6944f9","html_url":"https://github.com/rodydavis/flutter_json_widgets","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rodydavis%2Fflutter_json_widgets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rodydavis%2Fflutter_json_widgets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rodydavis%2Fflutter_json_widgets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rodydavis%2Fflutter_json_widgets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rodydavis","download_url":"https://codeload.github.com/rodydavis/flutter_json_widgets/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250440761,"owners_count":21431051,"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":["dart","dynamic-widget","flutter","widget-builder","widgets"],"created_at":"2024-08-01T12:01:23.116Z","updated_at":"2025-04-23T13:41:49.275Z","avatar_url":"https://github.com/rodydavis.png","language":"Dart","funding_links":[],"categories":["Dart"],"sub_categories":[],"readme":"# Flutter Json Widgets\n\n[![github pages](https://github.com/rodydavis/flutter_json_widgets/actions/workflows/main.yml/badge.svg)](https://github.com/rodydavis/flutter_json_widgets/actions/workflows/main.yml)\n\nThis goal of this project is to provide a way to create Flutter widgets with JSON. \n\n\u003e This includes reading and writing to JSON from classes that represent widgets or other helper classes and enums.\n\nThis does not depend on the flutter sdk for the core classes and can be used in places like the server, command line and dart2js.\n\n[Online Editor](https://rodydavis.github.io/flutter_json_widgets/)\n\n[Documentation](https://rodydavis.github.io/flutter_json_widgets/docs/)\n\n## Implementation\n\nThis package relies on another package called [freezed](https://pub.dev/packages/freezed) to generate the classes, enums and especially the unions that make it very helpful for parsing.\n\nWhile it is possible to match the Flutter SDK api for widget creation in most cases, there are times where this will differ.\n\n### Named Constructors\n\nSince the widget class is a sealed union things like `ElevatedButton.icon` will be `ElevatedButtonIcon` instead.\n\nThe class will still map to the correct widget at runtime.\n\n### Functions\n\nSince this is JSON ultimatly, then logic will not work here. However, there are multiple types of intents that can be used with a class `Callback` and various actions (navigation, messages, empty, ...).\n\nAlso planning on expanding it to include form submission and http requests too.\n\n### Builder Methods\n\nSince there is no logic things like `LayoutBuilder` are difficult to achieve. The `MaterialApp` has a routes property that you can provide a static map to without depending on context.\n\n## Supported Widgets\n\nThere are a lot, and more coming soon. List of widgets [here](https://rodydavis.github.io/flutter_json_widgets/docs/widget/widget-library.html).\n\n### SSR Example\n\n#### Server (dart)\n\n```dart\n// ignore_for_file: depend_on_referenced_packages\n\nimport 'dart:convert';\nimport 'dart:async';\n\nimport 'package:flutter_json_widgets/flutter_json_widgets.dart';\n\nimport 'package:shelf_router/shelf_router.dart';\nimport 'package:shelf/shelf.dart';\nimport 'package:shelf/shelf_io.dart' as io;\nimport 'package:shelf_cors_headers/shelf_cors_headers.dart';\n\nint _counter = 0;\n\nFuture main() async {\n  final app = Router();\n\n  const host = 'localhost';\n  const port = 8080;\n  const url = 'http://$host:$port';\n\n  app.post('/api/counter', (Request request) async {\n    final content = await request.readAsString();\n    final map = jsonDecode(content) as Map\u003cString, Object?\u003e;\n    _counter = map['counter'] as int;\n    return Response.ok(\n      jsonEncode({'counter': _counter}),\n      headers: {\n        'Content-Type': 'application/json',\n      },\n    );\n  });\n\n  app.get(\n    '/',\n    (Request request) =\u003e _ui(const MaterialApp(\n      debugShowCheckedModeBanner: false,\n      initialRoute: '/counter',\n      routes: {\n        '/counter': NetworkWidget(\n          request: NetworkHttpRequest(\n            url: '$url/counter',\n          ),\n        ),\n      },\n    )),\n  );\n\n  app.get(\n    '/counter',\n    (Request request) =\u003e _ui(Scaffold(\n      appBar: const AppBar(\n        title: Text('Flutter Demo Home Page'),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            const Text(\n              'You have pushed the button this many times:',\n            ),\n            Text(\n              '$_counter',\n              style: const TextStyle.headlineMedium(),\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: Callback.networkRequest(\n          NetworkHttpRequest(\n            url: '$url/api/counter',\n            method: 'POST',\n            bodyMap: {'counter': _counter + 1},\n          ),\n          callback: const Callback.reload(),\n        ),\n        tooltip: 'Increment',\n        child: const Icon(Icons.add),\n      ),\n    )),\n  );\n\n  // Set CORS headers with every request\n  final handler = const Pipeline().addMiddleware(corsHeaders()).addHandler(app);\n\n  // ignore: avoid_print\n  print('Starting server on $url');\n  await io.serve(handler, host, port);\n}\n\nResponse _ui(Widget widget) {\n  const encoder = JsonEncoder.withIndent('  ');\n  final jsonString = encoder.convert(widget.toJson());\n  return Response.ok(\n    jsonString,\n    headers: {\n      'Content-Type': 'application/json',\n    },\n  );\n}\n\n```\n\n#### Client (flutter)\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:flutter_json_widgets/flutter.dart';\n\nvoid main() {\n  runApp(const MyApp());\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n   return FlutterWidget.network(\n     url: Uri.parse('http://localhost:8080/'),\n    );\n  }\n}\n\n```\n\n\n### JSON\n\nHere is an example for the dart API:\n\n```dart\nimport 'package:flutter_json_widgets/material.dart';\n\nclass Example {\n  int _counter = 0;\n\n  Widget build() {\n    return Scaffold(\n      appBar: const AppBar(\n        title: Text('Flutter Demo Home Page'),\n      ),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            const Text(\n              'You have pushed the button this many times:',\n            ),\n            Text(\n              '$_counter',\n              style: const TextStyle.headlineMedium(),\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: Callback.networkRequest(\n          NetworkHttpRequest(\n            url: '$url/api/counter',\n            method: 'POST',\n            bodyMap: {'counter': _counter + 1},\n          ),\n          callback: const Callback.reload(),\n        ),\n        tooltip: 'Increment',\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}\n```\n\nAnd the backing JSON:\n\n```json\n{\n  \"appBar\": {\n    \"automaticallyImplyLeading\": true,\n    \"title\": {\n      \"data\": \"Flutter Demo Home Page\",\n      \"runtimeType\": \"text\"\n    },\n    \"primary\": true,\n    \"excludeHeaderSemantics\": false,\n    \"toolbarOpacity\": 1.0,\n    \"bottomOpacity\": 1.0,\n    \"forceMaterialTransparency\": false,\n    \"runtimeType\": \"appBar\"\n  },\n  \"body\": {\n    \"child\": {\n      \"mainAxisAlignment\": \"center\",\n      \"mainAxisSize\": \"max\",\n      \"crossAxisAlignment\": \"center\",\n      \"verticalDirection\": \"down\",\n      \"children\": [\n        {\n          \"data\": \"You have pushed the button this many times:\",\n          \"runtimeType\": \"text\"\n        },\n        {\n          \"data\": \"0\",\n          \"style\": {\n            \"runtimeType\": \"headlineMedium\"\n          },\n          \"runtimeType\": \"text\"\n        }\n      ],\n      \"runtimeType\": \"column\"\n    },\n    \"runtimeType\": \"center\"\n  },\n  \"floatingActionButton\": {\n    \"child\": {\n      \"icon\": {\n        \"codePoint\": 57415,\n        \"fontFamily\": \"MaterialIcons\",\n        \"matchTextDirection\": false\n      },\n      \"runtimeType\": \"icon\"\n    },\n    \"tooltip\": \"Increment\",\n    \"onPressed\": {\n      \"request\": {\n        \"url\": \"http://localhost:8080/api/counter\",\n        \"headers\": {},\n        \"method\": \"POST\",\n        \"bodyMap\": {\n          \"counter\": 1\n        }\n      },\n      \"callback\": {\n        \"runtimeType\": \"reload\"\n      },\n      \"runtimeType\": \"networkRequest\"\n    },\n    \"mini\": false,\n    \"clipBehavior\": \"none\",\n    \"autofocus\": false,\n    \"isExtended\": false,\n    \"runtimeType\": \"floatingActionButton\"\n  },\n  \"persistentFooterAlignment\": {\n    \"x\": 1.0,\n    \"y\": 0.0\n  },\n  \"primary\": true,\n  \"extendBody\": false,\n  \"extendBodyBehindAppBar\": false,\n  \"drawerEnableOpenDragGesture\": true,\n  \"endDrawerEnableOpenDragGesture\": true,\n  \"runtimeType\": \"scaffold\"\n}\n```\n\n## Troubleshooting\n\nFor web you need to pass the flag `--no-tree-shake-icons` to keep the icons.\n\n## Related projects\n\n- [rfw](https://github.com/flutter/flutter/issues/90218)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frodydavis%2Fflutter_json_widgets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frodydavis%2Fflutter_json_widgets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frodydavis%2Fflutter_json_widgets/lists"}