Continuing from last week our effort to find an implementation for SwiftUI modifiers that is comprehensive but also enjoyable to write may have been solved!
Thanks to Keith Gautreaux for proposing to just rely on Elixir’s own composition tool: the pipeline. I really like this approach and I think it will nicely solve the modifiers problem while also keeping the implementation as Elixir-like as we can.
Here is an example of how this may work. Let’s take the nested modifier I showed last week:
.background(LinearGradient(gradient: Gradient(colors: [Color.red, Color.blue]), startPoint: .top, endPoint: .bottom))
Here is how we may represent this with the proposal:
<text modifiers={&text_modifiers/1} >Hello, world!</text>
def text_modifiers(context) do
background(context,
gradient: Gradient(colors: [Color.(:red), Color(:blue)])
startPoint: :top,
endPoint: :bottom
)
end
This would then be serialized onto the modifiers
attribute on the element. Let’s take a more complex example. I’ll borrow this one from Coding with Jeff:
struct RainbowBackground: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color.purple)
.padding()
.background(Color.blue)
.padding()
.background(Color.green)
.padding()
.background(Color.yellow)
.padding()
.background(Color.orange)
.padding()
.background(Color.red)
}
}
This would become:
def content_modifiers(context) do
context
|> padding()
|> background(Color.(:purple))
|> padding()
|> background(Color.(:blue))
|> padding()
|> background(Color.(:green))
|> padding()
|> background(Color.(:yellow))
|> padding()
|> background(Color.(:orange))
|> padding()
|> background(Color.(:red))
end
If you need to add complex nesting as values being passed to any modifiers function you can break that out into your own functions as you normally would in Elixir.
This is at the proposal stage right now, but so far this is the best approach. We’ll have to figure out how best to implement, as within any given LiveView controller we want to support every desired hardware target which means we risk name collision amongst SwiftUI, Jetpack Compose, WindUI3, etc. So we’ll have to develop some conventions on how access is provided to these functions and where best to break out the function definitions to keep the code clean.
Outside of the modifiers work continues on LiveView Native Core which is our common library that will contain all of the DOM patch/diff logic so each LiveView Native client can get a head start. No code is pushed to the repo yet but that should be coming soon.