constructor(parent) {
      super(parent)
      this.isFlexNode = true
      this.needsFlexLayout = true

      // Object holding all input styles for this node in the flex tree; see the style object
      // format in troika-flex-layout
      this._flexStyles = {
        id: this.$facadeId
      }

      // Look for the nearest flex layout ancestor; if there is one, add to its layout children,
      // otherwise we're a flex layout root.
      let parentFlexFacade = parent
      while (parentFlexFacade && !parentFlexFacade.isFlexNode) {parentFlexFacade = parentFlexFacade.parent}
      if (parentFlexFacade) {
        this.parentFlexNode = parentFlexFacade
        this.flexNodeDepth = parentFlexFacade.flexNodeDepth + 1
      } else {
        this.flexNodeDepth = 0
      }
    }
Extends a given Facade class to become a `FlexNode`, giving it the ability to participate
in flexbox layout. The resulting class behaves just like the original facade class, except:

- It now accepts a full set of flexbox-related input properties, defined below
- Those input properties get evaluated by a flexbox layout algorithm in the background
- The resulting layout metrics get written to the object as properties that the extended
  facade class can use in its `afterUpdate` method to affect its position/size/styling.

The flexbox layout algorithm is performed asynchronously within a web worker, so the result
metrics will probably not be available the first time `afterUpdate` is called. This can
sometimes cause issues with rendering due to NaNs, so it's good to check first that the
object has a nonzero `offsetWidth` and `offsetHeight` before displaying the node's object(s).

Currently the flexbox algorithm implementation is Facebook's Yoga. (https://yogalayout.com/)

*Supported input flexbox style properties:*
- width (number, string percentage, or 'auto')
- height (number, string percentage, or 'auto')
- minWidth (number, string percentage, or 'auto')
- minHeight (number, string percentage, or 'auto')
- maxWidth (number, string percentage, or 'auto')
- maxHeight (number, string percentage, or 'auto')
- aspectRatio (number, as width divided by height, or 'auto')
- flexDirection ('column', 'column-reverse', 'row', or 'row-reverse')
- flexWrap ('wrap' or 'nowrap')
- flex (number, where positive becomes flexGrow and negative becomes flexShrink)
- flexGrow (number)
- flexShrink (number)
- flexBasis (number, string percentage, or 'auto')
- alignContent ('auto', 'baseline', 'center', 'flex-end', 'flex-start', or 'stretch')
- alignItems ('auto', 'baseline', 'center', 'flex-end', 'flex-start', or 'stretch')
- alignSelf ('auto', 'baseline', 'center', 'flex-end', 'flex-start', or 'stretch')
- justifyContent ('center', 'flex-end', 'flex-start', 'space-around', or 'space-between')
- position ('relative' or 'absolute')
- top (number, string percentage, or 'auto')
- right (number, string percentage, or 'auto')
- bottom (number, string percentage, or 'auto')
- left (number, string percentage, or 'auto')
- margin (number, or array of up to four numbers in t-r-b-l order)
- padding (number, or array of up to four numbers in t-r-b-l order)
- borderWidth (number, or array of up to four numbers in t-r-b-l order)
- overflow ('visible', 'hidden', or 'scroll')

*Computed layout result properties:*
- offsetLeft
- offsetTop
- offsetWidth
- offsetHeight
- clientLeft
- clientTop
- clientWidth
- clientHeight
- scrollLeft
- scrollTop
- scrollWidth
- scrollHeight
- clipLeft
- clipTop
- clipRight
- clipBottom
(All of these are `null` initially and then numbers after the layout completes, except
scrollLeft and scrollTop which are `0` initially.)

*Additional FlexNode-specific properties:*
- isFlexNode (`true`, can be used to find FlexNodes in the facade tree)
- flexNodeDepth (number, where topmost FlexNode's depth is `0` and children increase by 1)
- parentFlexNode (the nearest parent FlexNode instance, or `null` if this is the root FlexNode)
- needsFlexLayout (boolean, can be set to force a recalculation of the full flexbox layout)

If the base class implements an `onAfterFlexLayoutApplied`, that will be invoked after the
results of a flex layout pass have been written to the object. This is a good place to put
custom logic that depends on a completed layout, rather than in `afterUpdate` which may have
layout properties queued but not yet evaluated.

@param {class} BaseFacadeClass
@return {FlexNode} a new class that extends the BaseFacadeClass