tabris-js icon indicating copy to clipboard operation
tabris-js copied to clipboard

Support FlexBox Layout

Open tbuschto opened this issue 3 years ago • 3 comments

Original discussion: https://github.com/eclipsesource/tabris-js/issues/2101

tbuschto avatar May 20 '21 09:05 tbuschto

API draft:

Adjusting the CSS API to our Tabris API and the yoga feature set.

Parent/Container

Things are pretty straight-forward for the container. For the property names we convert kebab-case to camelCase. We could omit the "flex" prefix, though that makes it potentially inconsistent with the layoutData properties, as discussed below. The values stay as-is, but enums can be provided as well. Only oddity are the values which contain a space, here some error tolerance may be needed in the JS code.

new FlexBox({
  direction: 'row', // | 'row-reverse' | 'column' | 'column-reverse'
  wrap: 'nowrap', // | 'wrap' | 'wrap-reverse'
  flow: 'row nowrap', // | 'column-reverse' | 'column-wrap' | 'row-reverse wrap-reverse'
  justifyContent: 'flex-start', // | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'
  alignItems: 'stretch', // | 'flex-start' | 'flex-end' | 'center' | 'baseline'
  alignContent: 'flex-start' // | 'flex-end' | 'center' | 'stretch' | 'space-between' | 'space-arond'
})

All optional and read-only of course, first value is the default.

The above is JS-only shorthand for:

new Composite({
  layout: new FlexBoxLayout(...) // same props as above
})

This is closer to what the native client will get, a Composte, Page, TabItem, etc with a layout property set either not at all (let's say it's equivalent to {display: 'constraint'}), or to {display: 'flex', direction: 'row', ...}. It's always the complete set of properties, fallback to default. The padding property will continue to be set separately and not as part of layout.

Item/Child

Flexbox respects various item layout (for us: layoutData) properties that aren't exclusive to it, and we already established that some layoutData properties work differently or not at all depending on the parent layout. Also, having a completely different set of layoutData properties for flexbox would cause sever backwards compatibility issues in TypeScript. I therefore propose to just extend the existing set of layoutData properties.

The existing properties are used as follows:

Property Type Usage
left constraint or number flex only respects 'auto', number and percent.
top constraint or number "
right constraint or number "
bottom constraint or number "
width number or percent or 'auto' percent is only respected by flex
heigh number or percent or 'auto' "
centerX number not respected by flex, but could be re-directed in JS to set alignSelf
centerY number "
baseline sibling "

For the new properties we will use a flex prefix to minimize the risk of clashing with existing properties of custom components (since the inherit from Composite and therefore Widget, which will get the new flex properties). They are ignored (with warning) if the parent doesn't use flexbox. The native client won't receive them either.

The following new properties would match 1:1 with their CSS counterpart:

{
  flexBasis: 'auto', // | number | percent
  flexGrow: 0, // number,
  flexShrink: 1, // number
}

The following new properties do not have the "flex" prefix in CSS, but would have for us to avoid collision. (We can invent a shorthand syntax for the JS side to make it shorter to express.)

{
  flexAlignSelf: 'auto', // | 'stretch' | 'flex-start' | 'flex-end' | 'center' | 'baseline',
  flexPositionType: 'relative', // | ' absolute'
  flexMaxWidth: null, // | number | percent
  flexMinWidth: null, // | number | percent
  flexMaxHeight: null, // | number | percent
  flexMinHeight: null, // | number | percent
  flexMarginLeft: 0, // | number | percent
  flexMarginTop: 0, // | number | percent
  flexMarginRight: 0, // | number | percent
  flexMarginBottom: 0, // | number | percent
}

The positionType property is acually just position in CSS, but in yoga it's positionType. I find that more precise.

Yoga supports a border property, but as far as I can tell it's no use to us.

Finally there is a order property is in the flexbox standard, but it don't seem to be supported by yoga. We could possibly support it on a JS level, by re-ordering them when sending the client the children ids.

Since we now have mixed types which can be number or percent (width, height, flexBasis) we need to render them differently for the percent value. I suggest [fraction, 0] to be aligned with left/top/width/height.

References used

https://yogalayout.com/docs (note https://github.com/facebook/yoga/issues/993) https://www.w3.org/TR/css-flexbox-1 https://yoksel.github.io/flex-cheatsheet/#section-display https://css-tricks.com/snippets/css/a-guide-to-flexbox/

tbuschto avatar May 20 '21 12:05 tbuschto

We will not remove the flex prefixes for the container properties after all.

tbuschto avatar May 25 '21 08:05 tbuschto

width, height and flexBasis will be rendered as tuple [percent, 0] only if it's percent in layoutData, otherwise still number or 'auto'.

tbuschto avatar May 25 '21 10:05 tbuschto