rad 0.4.0 rad: ^0.4.0 copied to clipboard
A zero-dependency frontend framework for writing web apps in plain Dart. Inspired from Flutter.
Rad #
Rad is a frontend framework for Dart. It's inspired from Flutter and shares same programming paradigm. In Rad, applications are created using widgets. A widget can describe static as well as dynamic part of user interface. Widgets can be composed together to build more widgets and complex layouts. Rad widgets are similar to Flutter widgets.
Let's take a look at an example written using Rad:
class HomePage extends StatelessWidget
{
@override
build(context) {
return Container(
child: GestureDetector(
child: Text("click me"),
onTap: () => print("received a click!"),
),
);
}
}
How about that? if you're familiar with Flutter it don't even need an explanation.
Getting started #
-
Create a demo web app:
dart create -t web-simple myapp
Having troubles? learn more from official guide
-
Add Rad as dependency:
- Open
pubspec.yaml
in newly created app folder and addrad
to your dependencies:dependencies: rad: 0.4.0
- Open
-
Import Rad widgets in your
main.dart
import 'package:rad/rad.dart';
-
Create Rad app
void main() { RadApp( // 'output' is the id of div in your web/index.html // framework will mount your app inside that div // if you don't have a div with id 'output' in web/index.html, targetId: "output", // you've to create it // e.g // <body> // <div id="output"></div> // ... child: GestureDetector( onTap: () { print("working"); }, child: Container( child: Text("click me"), ), ), ); }
-
Run
webdev serve
and follow on-screen instructions
Debugging #
For debugging a Dart web app, you've to setup a debugger for your IDE/editor. See Dart guide for debugging web apps and tools that you can use. (remember you don't need Flutter SDK/or its plugins for using Rad).
If you happen to be using VS code,
- Install VS code Dart plugin
- Create a
launch.json
inside.vscode
folder - see example - Start your app in debug mode - see this for more
Deployment #
For getting a release build run webdev build --release
. It'll generate a ready-to-deploy build of your app inside build
folder. To customize your build, read this official deployment guide. Alternatively, you can also follow webdev documentation.
Styling widgets #
Rad doesn't use a rendering engine to render a widget or anything like that. Rad widgets are mapped to HTML tags and composed together they way you describe them. This allows you to style them the way you want.
Using CSS for styling #
You can add CSS rules to widgets to style them. For example:
Container(
styles: "css-class another-class",
child: const Text("text inside a styled container"),
);
Note: Some widgets such as StatelessWidget don't have a style
property.
Size properties #
Some widgets have properties that can be used to give these widgets a predefined size. These properties are: width, height, margin and padding. These properties are directly mapped to CSS properties. If you're familer with CSS, below example will explain what we mean:
Container(
width: "10px",
height: "20px",
);
These properties allows you to pass literally anything:
Container(
width: "10%",
height: "20px",
);
There's also a less-verbose way. All widgets that has width and height properties also has a size
property:
Container(
size: "10% 20px",
// syntax :- size: "width height"
);
Position properties #
Similar to size properties there are top, right, bottom, left properties that deals with position of a widget.
Positioned(
top: "10px",
left: "20px",
);
And there's a optional position
property:
Positioned(
positon: "10px _ _ 20px",
// syntax :- position: "top right bottom left"
// underscore means ignore this
// applies to size prop as well.
);
Routing #
Rad framework comes with a in-built Router that offers
- Auto Routing
- Auto Deep linking
- Auto Single page experience (no page reloads when user hit forward/back buttons)
Everything you're seeing in above demo, works out of the box. That is, you'll be using just the Navigator widget and framework will take care of wiring things up. Even if you've Navigators nested inside other Navigators, or your Navigators are placed somewhere deep inside Pages, framework will take care of finding them and routing requests to them when needed.
Navigator widget #
Navigator(
// required
routes: [
...
],
// both are optional
onInit: (NavigatorState state) {
}
onRouteChange: (String name) {
}
)
Let's discuss these properties one by one,
routes[] #
This property takes list of Routes. A Route is kind of an isolated Page that Navigator can manage. To define a Route, there's actually a Route widget:
routes: [
Route(name: "home", page: HomePage()),
Route(name: "edit", page: SomeOtherWidget())
...
]
Above, we've defined two routes, home and edit. A Route widget simply wraps a another widget. Route widget has a name
property, that is used to give Route a name. Route's name is helpful in finding route from application side, and navigating to it when needed.
NavigatorState #
Navigator widget creates a state object. State object provides methods which you can use to jump between routes, pop routes and things like that. To access a Navigator's state object, there are two methods:
-
If widget from where you accessing NavigatorState is in child tree of Navigator then use
Navigator.of(context)
. This method will return NavigatorState of the nearest ancestor Navigator from the given context. -
For accessing state in parent widget of Navigator, use
onInit
hook of Navigator:class SomeWidget extends StatelessWidget { @override build(context) { return Navigator( onInit: _onInit, ... ) } _onInit(NavigatorState state) { // do something with state } }
Jumping to a Route #
Navigator in Rad doesn't stack duplicate pages on top of each other, instead it'll create a route page only once. To go to a route, use open
method of Navigator state. When you call open
, Navigator will create route page if it's not already created. Once ready, it'll bring it to the top.
Navigator.of(context).open(name: "home");
Going back #
To go to previously visited route, use Navigator.of(context).back()
. Make sure to check whether you can actually go back by calling canGoBack()
on state.
Passing values between routes #
Values can be passed to a route through open
method.
Navigator.of(context).open(name: "home", values: "/somevalue"); // leading slash is important
Then on homepage, value can be accessed using:
var value = Navigator.of(context).getValue("home");
// "somevalue"
Passing multiple values:
Navigator.of(context).open(name: "home", values: "/somevalue/profile/123");
On homepage,
var valueOne = Navigator.of(context).getValue("home"); // -> "somevalue"
var valueTwo = Navigator.of(context).getValue("profile"); // -> "123"
Cool thing about Navigator is that values passed to a route will presist during browser reloads. If you've pushed some values while opening a route, those will presist in browser history too. This means you don't have to parameterize your page content, instead pass values on open
:
// rather than doing this
Route(name: "profile", page: Profile(id: 123));
// do this
Route(name: "profile", page: Profile());
// and when opening profile route
Navigator.of(context).open(name: "profile", value: "/123");
// on profile page
var id = Navigator.of(context).getValue("profile");
onRouteChange hook: #
This hooks gets called when Navigator opens a route. This allows Navigator's parent to do something when Navigator that it's enclosing has changed. for example, you could've a header and you can change active tab when Navigator's route has changed.
Navigator(
onRouteChange: (name) => print("changed to $name");
...
);
That's pretty much it. Source of demo shown at top of this section can be found in example/routing folder.
Widgets Index #
Main #
Navigator #
Layout #
Boxes
Alignment
Overlays
Flex
Misc #
Abstract #
Elements #
Contribution #
Rad is a hobby project. Core(src/core) of this framework is extremely small and straightforward. Having just the basic knowledge of DOM & Dart is enough to implement widgets(src/widgets).