vitalets / react-native-extended-stylesheet

Extended StyleSheets for React Native
MIT License
2.93k stars 132 forks source link

Support shorthands #69

Closed krizzu closed 3 years ago

krizzu commented 6 years ago

Hey!

Thanks for this cool tool. I was wondering if you'd like to support css shorthands (like, padding: 5 10 5 8), which consequently changes that to paddingTop: 5, paddingRight: 10, paddingBottom: 5, paddingRight: 8.

I'd happy to help with that.

vitalets commented 6 years ago

Hey @Krizzu ! I think it makes sense. There are some more cases that should be considered:

  1. Variables:
    padding: '$a 1 2 3'
  2. Calculations:
    padding: '$a + 10 1 2 3'

    I think we should deny calculations in shorthand props as it is impossible to parse normally.

So, you are welcome to take leadership on this 👍 Also the following project could help: https://github.com/styled-components/css-to-react-native

krizzu commented 6 years ago

Great!

I'll dive in on the weekend

krizzu commented 6 years ago

Hey @vitalets 👋 Need suggestion here: using css-to-react-native requires styles to have px unit to be parsed. I'm going to add units, for the sake of getting the outcome. Or maybe you can think of a different way? Also, my suggestion here is to limit of supported shorthands to few: margin, padding, borderRadius, borderWidth, shadowOffset.

WDYT?

vitalets commented 6 years ago

Need suggestion here: using css-to-react-native requires styles to have px unit to be parsed. I'm going to add units, for the sake of getting the outcome. Or maybe you can think of a different way?

Could you add some tests to see how adding px will work with different cases? Will not it break variables and percents?

  1. padding: '$a 1 2 3'
  2. padding: '10% 1 2 3'

Also, my suggestion here is to limit of supported shorthands to few: margin, padding, borderRadius, borderWidth, shadowOffset.

Why can not we support all?

krizzu commented 6 years ago

Could you add some tests to see how adding px will work with different cases? Will not it break variables and percents?

Yeah, I still have to add functionality for it, will add test to prove it's working.

Why can not we support all? Some of them are background which just evals to backgroundColor, or borderWidth, which already defines all borders in RN.

Here's a list that I believe is supported by css-to-react-native, we can choose which make sense and add them

https://github.com/styled-components/css-to-react-native/blob/master/src/transforms/index.js#L54-L71

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

gurs1kh commented 5 years ago


1. Calculations:

padding: '$a + 10 1 2 3'

I think we should deny calculations in shorthand props as it is impossible to parse normally.

One way to get around this is to allow for arrays to be used. ie:

padding: ['$a + 10', 1, 2, 3]

This also is a good stylistic alternative to using a space-separated string.

Here's how I've accomplished this before:

//modified/simplified for use in react-native (and some other reasons) from https://github.com/ActionIQ-OSS/style-builder/blob/master/StyleBuilder.js
function expandShorthand(values) {
  if (typeof values == 'string') {
    values = values.split(" ").map(v => isNaN(v) ? v : Number(v));
  }
  let results = [...Array(4)];
  switch(values.length) {
    case 1:
      return results.fill(values[0]);
    case 2:
      return results.map((v, i) => values[i % 2]);
    case 3:
      return results.map((v, i) => values[i % 3 + Math.floor(i / 3)]);
    default:
      return values;
  }
}

function parseShorthand(prefix, values) {
  if (typeof values == 'number') return values;
  let directions = ['Top', 'Right', 'Bottom', 'Left'];
  values = expandShorthand(values);

  return values.reduce((styles, value, i) => ({
    ...styles,
    [`${prefix}${directions[i]}`]: value,
  }), {});
}

function margin(values) {
  return parseShorthand('margin', values);
}

function padding(values) {
  return parseShorthand('padding', values);
}

function ignoreValue(value) {
  const type = typeof value;
  return type == 'number' || (type == 'string' && value.split(' ').length == 1);
}

function shorthand(styles) {
  let newStyles = Array.isArray(styles) ? [] : {};

  Object.keys(styles).forEach((key) => {
    const value = styles[key];
    const type = typeof value;

    if (!ignoreValue(value) && key == 'margin') {
      Object.assign(newStyles, margin(value));
    } else if (!ignoreValue(value) && key == 'padding') {
      Object.assign(newStyles, padding(value));
    } else if (Array.isArray(value)) {
      newStyles[key] = value.map(v => shorthand(v));
    } else if (type == "object") {
      newStyles[key] = shorthand(value);
    } else {
      newStyles[key] = value;
    }
  });

  return newStyles;
}

EStyleSheet._create = EStyleSheet.create;
EStyleSheet.create = (styles) => EStyleSheet._create(shorthand(styles));

Though I only really did margin and padding, this could easily be refactored to work with some other shorthands

vitalets commented 5 years ago

One way to get around this is to allow for arrays to be used.

Agree. Looks as nice solution! 👍

hustcer commented 4 years ago

+1

vitalets commented 3 years ago

So finally I think there will be more problems than profit from that feature.