This came from some discussions with @manuhornung and others around Flutter's model vs our style model. IMO, one thing Flutter did really well in their design is their compositional component model (moving away from the uber-style grab bag of properties).
To clarify, what I mean by a compositional model, is instead of having a Style.[...] with arbitrary properties (like positioning, transform, etc), Flutter has more scoped widgets - like a Transform widget, or Positioned widget. This is nice in terms of discoverability - each of those widgets takes a relatively small and concise set of properties.
In addition, the Style.[..] model is coupled to a single layout system, whereas Flutter uses component composition to express a variety of layout models - this is very convenient for building UI apps.
The Style.[..] model has gotten us really far, but there are a few downsides I've seen so far:
- Discoverability: The use of Polymorphic Variants isn't as well supported with auto-complete (as far as I can tell), whereas specific properties would be more discoverable
- Discoverability: It's challenging to know all the potential properties, and how they interact, when using
Style.[..].
- Performance: We always have to
fold our style-list into a style-object:
|
let applyStyle = (style, styleRule) => |
- I wonder if there could be a cheaper way to handle this? Merging is always challenging:
|
let merge = (~source, ~target) => |
- Performance: Our
Node class ends up having to do a lot of different things - recompute transforms, even if there is are no extra transforms, check the overflow property, etc.
I think the compositional model could help with some of the discoverability, by having a more constrained set of properties per-component, and help with the performance by giving each component a more constrained set of responsibilities (potentially minimizing extra transform calculations, overflow calculations, etc).
If people are on-board with moving to the compositional model vs the uber-style model, I'd propose tackling it incrementally, by removing style properties and replacing them with compositional components:
In addition, this model would be amenable for future work:
The ultimate goal would be to remove the style property entirely, and represent everything it modelled via new components, instead.
Some things to think about:
- Would each of these components need a
Node in our scene-tree (aka, would they be primitive components?)? If so, they probably don't all need to generate LayoutNode's - we might need to take a look at that. Also, if we did model these as Node's - likely a lot of the 'core' behavior in the Node class could be factored across these new, smaller primitives. For example - this Overflow.render behavior would only need to be used by the new ClipRect's node.
This came from some discussions with @manuhornung and others around Flutter's model vs our
stylemodel. IMO, one thing Flutter did really well in their design is their compositional component model (moving away from the uber-stylegrab bag of properties).To clarify, what I mean by a compositional model, is instead of having a
Style.[...]with arbitrary properties (like positioning, transform, etc), Flutter has more scoped widgets - like aTransformwidget, orPositionedwidget. This is nice in terms of discoverability - each of those widgets takes a relatively small and concise set of properties.In addition, the
Style.[..]model is coupled to a single layout system, whereas Flutter uses component composition to express a variety of layout models - this is very convenient for building UI apps.The
Style.[..]model has gotten us really far, but there are a few downsides I've seen so far:Style.[..].foldour style-list into a style-object:revery/src/UI/Style.re
Line 501 in 0eb56f4
revery/src/UI/Style.re
Line 589 in 0eb56f4
Nodeclass ends up having to do a lot of different things - recompute transforms, even if there is are no extra transforms, check the overflow property, etc.I think the compositional model could help with some of the discoverability, by having a more constrained set of properties per-component, and help with the performance by giving each component a more constrained set of responsibilities (potentially minimizing extra transform calculations, overflow calculations, etc).
If people are on-board with moving to the compositional model vs the uber-style model, I'd propose tackling it incrementally, by removing style properties and replacing them with compositional components:
transformproperty could become the responsibility ofTransform.Rotate/Transform.Scale, etc components ([WIP] API: Transform composite component #488)positionandtop/left/right/bottomcould become the responsibility ofStackandPositionedcomponents (Feature - API: Some initial compositional components #483)backgroundColorproperty could become thecolorproperty of aContainercolorproperty could become thecolorproperty of aTextpaddingproperty could be moved to aPaddingcomponentRowandColumncomponentsborderproperties could be moved to aBordercomponentopacitycould be moved to anOpacitycomponentoverflowcould be moved to aClipRectcomponentboxShadowcould be moved to aBoxShadowcomponentcursorand mouse event handling could be moved to aMouseInputcomponentKeyboardInputcomponentIn addition, this model would be amenable for future work:
GestureDetectorcomponent (potentially plugging into @jordwalke 's prototype)The ultimate goal would be to remove the
styleproperty entirely, and represent everything it modelled via new components, instead.Some things to think about:
Nodein our scene-tree (aka, would they be primitive components?)? If so, they probably don't all need to generateLayoutNode's - we might need to take a look at that. Also, if we did model these asNode's - likely a lot of the 'core' behavior in theNodeclass could be factored across these new, smaller primitives. For example - thisOverflow.renderbehavior would only need to be used by the newClipRect's node.