Flutter's widgets and layouts as plain, immutable data, with a JSON format. This is the model behind the Codelessly Editor and the Codelessly SDK: nodes, layouts, variables, conditions, actions, scripts, breakpoints and published apps.
The model, between the Editor and the SDK.
Pure Dart: no Flutter, no network, two small dependencies (collection, meta).
Looking to show Codelessly screens in a Flutter app? Use
codelessly_sdk. It exports this package. Usecodelessly_apion its own to read, build, check or transform layouts without Flutter: servers, CLIs, code generators, tests.
import 'package:codelessly_api/codelessly_api.dart';dart pub add codelessly_apiDart 3.12 or newer.
import 'dart:convert';
import 'package:codelessly_api/codelessly_api.dart';
void main() {
final document = LayoutDocument.fromJson({
'schema': 2,
'id': 'hello',
'roots': ['home'],
'nodes': {
'home': {
'type': 'canvas',
'name': 'Home',
'slots': {'body': 'column'},
'layout': {'width': 390, 'height': 844},
},
'column': {
'type': 'column',
'children': ['title'],
'layout': {'width': {'fill': 390}, 'height': {'fill': 844}, 'padding': 24},
'props': {'spacing': 12, 'crossAxisAlignment': 'start'},
},
'title': {
'type': 'text',
'props': {'text': 'Hello!', 'style': {'fontSize': 24, 'fontWeight': 700}},
},
},
});
// Typed access, with Flutter's names and defaults.
final column = document['column']!;
print(column.prop(FlexProps.spacing)); // 12.0
print(column.prop(FlexProps.mainAxisAlignment)); // MainAxisAlignment.start (Flutter's default)
// Immutable: an edit is a copy. Value equality tells what changed.
final edited = document['title']!.withProp(TextProps.text, 'Hello, world!');
print(edited == document['title']); // false
// Sparse JSON out: defaults aren't written.
print(jsonEncode(edited.toJson()));
}| Nodes | Node: a widget type, its Layout, Decoration, typed Props, bindings, reactions and behaviors. Immutable, with value equality. |
| Widgets | WidgetSpec: one declaration per widget type (66 of them), with each prop's Flutter name, type and default. Widgets.all, Widgets.of(type). |
| Documents | LayoutDocument: canvases (screens) and every node in one flat map; parents are derived, never stored. |
| Logic | Variable, Condition, Reaction / Trigger / ActionDef (one class per action), ScriptDef, binding paths. |
| Publish | PublishModel, PublishLayout, PublishBundle, Breakpoints, ThemeTokens, AppIdentity, HttpApi. |
| Values | Color, EdgeInsets, BorderRadius, Alignment, BoxConstraints, TextStyle, Paint... with Flutter's names. |
- Total decoding.
fromJsonnever throws. Unknown keys and unknown node types round-trip; a bad value falls back to its default. - Sparse encoding. A value equal to Flutter's default is not written.
- The data model
- Widgets and
WidgetSpec - The JSON format
- Building and checking a layout in code
- Logic: variables, conditions, actions, scripts
The example builds a layout with the typed classes, round-trips it through JSON and wraps it as a publish bundle.
Several value types share Flutter's names (Color, EdgeInsets, TextStyle, Alignment...). In a Flutter file,
import this package with a prefix:
import 'package:codelessly_api/codelessly_api.dart' as api;codelessly_sdk re-exports the model without those types for that reason.
BSD 3-Clause. See LICENSE.
