A note about the DSL
Hello,
While looking online about Fabulous I stumbled on this fslang-suggestions - Allow dot notation after body of computation expression without need for parenthesis.
While reading the issue discussion it made me think about how Oxpecker solve a similar problem. Instead of using members after the CE, it use properties to set information inside of the "CE constructor".
This code
ContentPage(
"Dashboard",
ScrollView(
(VStack() {
Label("Hello, World!")
.textColor(Color.Red.ToFabColor())
Button("Click me!")
.backgroundColor(Color.Blue.ToFabColor())
})
.margin(Thickness(10., 0.))
)
.verticalScrollBarVisibility(ScrollBarVisibility.Never)
)
.hasNavigationBar(false)
could be something like
ContentPage(
"Dashboard",
ScrollView(
VStack(margin = Thickness(10., 0.)) {
Label("Hello, World!", textColor = Color.Red.ToFabColor())
Button("Click me!", backgroundColor = Color.Blue.ToFabColor())
},
verticalScrollBarVisibility = ScrollBarVisibility.Never
)
navigationBar = false
)
I didn't test my code out as I just wanted to mention the idea
You can see some example of working code in Oxpecker repository:
- https://github.com/Lanayx/Oxpecker/tree/main/src/Oxpecker.Htmx
- https://github.com/Lanayx/Oxpecker/tree/main/src/Oxpecker.Solid
Hey,
Thanks for the suggestion!
This is a really interesting approach - I hadn’t realized you could extend a type with properties and still use the object initialization syntax. That would indeed eliminate the issue with the extra parentheses.
That said, our current approach has a few advantages that I don’t think the properties approach can replicate.
One major benefit is that each extension member returns a new copy of the widget with the added modification. This makes it possible to have shared widgets that can be customized differently in various contexts. It’s particularly useful for "attached properties" (which affect parent layout), such as the grid example below.
type View with
static member PrimaryButton(text: string, onClicked: 'msg) =
Button(text, onClicked)
.font(...)
.textColor(...)
.backgroundColor(...)
.border(...)
Grid(...) {
PrimaryButton(...)
.height(42)
.margin(0., 0, 24, 0)
.gridRow(1)
PrimaryButton(...)
.gridRow(2)
.gridColumn(1)
}
One major benefit is that each extension member returns a new copy of the widget with the added modification.
Indeed, another advantage that I though about when writing this issue is that you can also support method overload when properties don't allow that. Could be emulated using constructor overload but the code would not be as ergonomic.