shoutem/theme

Add ability pass an array of styles

lughino opened this issue · 6 comments

Sometimes I need to change the style of a component in inline mode by setting the prop style. This works, but it is not possible to pass an array of objects to prop style, as you can with the normal components of react native.

Can you add this possibility?
Thanks

I made a simple workaround to resolve the problem:

// src/StyleNormalizer/normalizeStyle.js
// ..
export default function normalizeStyle(style) {
  let styleFlatten = style;
  if(Array.isArray(style)) {
    styleFlatten = Object.assign({}, ...style);
  }
  return _.reduce(styleFlatten, (normalizedStyle, val, prop) => {
    /* eslint-disable no-param-reassign */
    if (_.isPlainObject(val)) {
      normalizedStyle[prop] = normalizeStyle(val);
    } else if (styleNormalizer.canNormalize(prop)) {
      normalizedStyle = {
        ...normalizedStyle,
        ...styleNormalizer.normalize(prop, val),
      };
    } else {
      normalizedStyle[prop] = val;
    }
    /* eslint-enable no-param-reassign */

    return normalizedStyle;
  }, {});
}

Surely there is a better way to handle it ..

MrBr commented

I am not sure that we are going to support array as value for nested style, it adds additional complexity.

I understand that it is expected for component style prop to accept an array, we might cover that case, but it is unexpected for nested style to have array values.

Why do you have to pass arrays? Can you not merge that style before it is passed?

I understand that I can merge style before pass to the component, but considering that any other react native component accept array in the style property, so for reason of convention and integrity with other component I think that style property should accept array.
Otherwise I need to handle every Shoutem component in a different way, merging a style prop directly or creating a HOC that wrap a Shoutem component and merge style prop.
I think that this create a bit of complexity left to the developer, when you can handle it internally, as I did in the previous post.

MrBr commented

As I mentioned in comment above, we were/are thinking about handling component style with an array value.

Your code have nested style with array values in depth. You are recursively normalizing style searching for an arrays, that case we will not cover most likely.

I would suggest that you take another approach to the styling. Wouldn't advise mixing both pure React Native and our style in the same time. You can use styleNames to "activate" certain component style.

We've implemented mapPropsToStyleNames for the purpose of dynamic style resolving, it is third argument of the connectStyle function. This is case when component wants to dynamically change it own style.

Do not forget, we have provided our own styled components as well. Check out UI Toolkit, there is almost every RN Component connected to the style in our ui toolkit (and more).

Last thing, if you really need this feature, our code is open source and I invite you to contribute to our project. Feel free to open a pull request.

A less intrusive way to support arrays of styles would be to add this support in connectStyle HOC.

The style is resolved in resolveStyle function of that component (see https://github.com/shoutem/theme/blob/develop/src/connectStyle.js#L188). You can transform an array into an object there before passing it to normalizeStyle and resolveComponentStyle.

This shouldn't be difficult to implement, a PR is welcome.

Closing due to inactivity.