constelation / monorepo

Mono repo for constelation's Components, functions, and CONSTANTS
https://constelation.github.io/monorepo/
MIT License
12 stars 3 forks source link

Responsive Media Queries #15

Open mikehobi opened 7 years ago

mikehobi commented 7 years ago

A discussion to improve best practice for responsive media query breakpoints.

Current implementation uses react-media No support for multiple breakpoints.

<Media query=`(min-width: ${BREAKPOINT.MEDIUM})``>
  {
    isMediumLayout => (
      <View
        width={isMediumLayout ? 300 : 200}
      />
    )
  }
</Media>

Implementation similar to ResponsiveImage's

<View
  width={200}
  breakpoint={{
    [BREAKPOINT.MEDIUM]: {
      width: 300,
    },
    [BREAKPOINT.LARGE]: {
      width: 500,
    },
  }}
/>

Separate component?

<Media_
  medium={{ width: 300 }}
  large={{ width: 500 }}
>
  <View
    width={200}
  />
</Media_>

How do we separate style from layout?

<Style_
  medium={{ backgroundColor: 'red' }}
  large={{ backgroundColor: 'blue' }}
>
  <View
    backgroundColor='tomato'
  />
</Style_>
kylpo commented 7 years ago

More to consider:

      <Media
        lg={`
          width: '100%',
          paddingTop: 0,
          paddingBottom: 0,
          color: 'red',
        `}
      >
        <View
          width='100%'
          paddingHorizontal={UIState.isMobile ? 0 : 60}
        />
      </Media>

      <View
        media={`
          lg: {
            width: '100%',
            paddingTop: 0,
            paddingBottom: 0,
          }
        `}
        width='100%'
        paddingHorizontal={UIState.isMobile ? 0 : 60}
      />

      <View
        width={`
          100%,
          lg: {
            width: '100%',
          }
        `}
        paddingTop={`
          lg: 0,
        `}
        paddingBottom={`
          lg: 0,
        `}
        paddingHorizontal={UIState.isMobile ? 0 : 60}
      />

      <View
        width='100%'
        lgWidth='100%'
        lgPaddingTop={0}
        lgPaddingBottom={0}
        paddingHorizontal={UIState.isMobile ? 0 : 60}
      />

      <View
        width='100%'
        widthLg='100%'
        paddingTopLg={0}
        paddingBottomLg={0}
        paddingHorizontal={UIState.isMobile ? 0 : 60}
      />

      <View
        width={['100%', {[BREAKPOINT.LARGE]: '50%'}]}
        width={`'100%', {[${BREAKPOINT.LARGE}]: '50%'}`}
        width={`'100%', [${BREAKPOINT.LARGE}]: '50%'`}
        width={`
          '100%',
          [${BREAKPOINT.LARGE}]: '50%',
          [${BREAKPOINT.SMALL}]: '25%',
        `}
        width={`
          '100%',
          LARGE: '50%',
          SMALL: '25%',
        `}
        width={`
          DEFAULT: '100%',
          LARGE: '50%',
          SMALL: '25%',
        `}
        width={`
          DEFAULT: '100%',
          [${BREAKPOINT.LARGE}]: '50%',
          [${BREAKPOINT.SMALL}]: '25%',
        `}
        width={`{
          DEFAULT: '100%',
          [${BREAKPOINT.LARGE}]: '50%',
          [${BREAKPOINT.SMALL}]: '25%',
        }`}
        width={{
          DEFAULT: '100%',
          [BREAKPOINT.LARGE]: '50%',
          [BREAKPOINT.SMALL]: '25%',
        }}
      />
kylpo commented 7 years ago

And more

      <View
        width={{
          DEFAULT: '100%',
          [BREAKPOINT.LARGE]: '50%',
        }}
        paddingTop={{
          [BREAKPOINT.LARGE]: 0,
        }}
        paddingBottom={{
          [BREAKPOINT.LARGE]: 0,
        }}
        paddingHorizontal={{
          DEFAULT: 60,
          [BREAKPOINT.LARGE]: 0,
        }}
      />

      <View
        width={`
          DEFAULT: '100%',
          [${BREAKPOINT.LARGE}]: '50%',
        `}
        paddingTop={`
          [${BREAKPOINT.LARGE}]: 0,
        `}
        paddingBottom={`
          [${BREAKPOINT.LARGE}]: 0,
        `}
        paddingHorizontal={`
          DEFAULT: 60,
          [${BREAKPOINT.LARGE}]: 0,
        `}
      />

      <View
        width={`
          DEFAULT: '100%',
          ${BREAKPOINT.LARGE}: '50%',
        `}
        paddingTop={`${BREAKPOINT.LARGE}: 0`}
        paddingBottom={`${BREAKPOINT.LARGE}: 0`}
        paddingHorizontal={`
          DEFAULT: 60,
          ${BREAKPOINT.LARGE}: 0,
        `}
      />

      <View
        width={`
          DEFAULT: '100%',
          LARGE: '50%',
        `}
        paddingTop={`LARGE: 0`}
        paddingBottom={`LARGE: 0`}
        paddingHorizontal={`
          DEFAULT: 60,
          LARGE: 0,
        `}
      />

      <View
        width={`{
          DEFAULT: '100%',
          LARGE: '50%',
        }`}
        paddingTop={`{LARGE: 0}`}
        paddingBottom={`{LARGE: 0}`}
        paddingHorizontal={`{
          DEFAULT: 60,
          LARGE: 0,
        }`}
      />

      <View
        width={responsive('100%', `LARGE: '50%'`)}
        paddingTop={responsive(undefined, `LARGE: 0`)}
        paddingBottom={responsive(undefined, `LARGE: 0`)}
        paddingHorizontal={responsive(60, `LARGE: 0`)}
      />
kylpo commented 7 years ago

array in string form, like transition's value:

      <View
        width='100%, LARGE 50%'
        paddingTop='LARGE 0px'
        paddingBottom='LARGE 0px'
        paddingHorizontal='60px, LARGE 0px'
      />
mikehobi commented 7 years ago

I think like the per prop idea more than a separate media prop.

<View
  width={{
    DEFAULT: 100,
    LARGE: 200,
    "(min-width: 2800px)": this.state.isExpanded ? 400 : 300,
  }}
  height={200}
/>

Passing arguments is nice too, maybe a default as the first arg, and a media object as the second?

<View
  width={responsive(100, {
    LARGE: 200,
    XLARGE: 300,
  }}
/>

this would be wild if it was real:

<View
  width(100, {LARGE: 200})
/>
kylpo commented 7 years ago

Maybe adding something like mediaWidth could handle non-default values?

<View
  width={100}
  widthMedia={`
    LARGE: 200,
    XLARGE: 300,
  `}
  heightMedia={`LARGE: 200`}
/>

Oooh, is width@ a valid prop name?

<View
  width={100}
  width@={`
    LARGE: 200,
    XLARGE: 300,
  `}
  height@={`LARGE: 200`}
/>
kylpo commented 7 years ago

Nope, not a valid syntax.

maybe width_ or width$ or just widthAt?

<View
  width={100}
  $width={`
    LARGE: 200,
    XLARGE: 300,
  `}
  $height={`LARGE: 200`}
/>
<View
  width={100}
  _width={`
    LARGE: 200,
    XLARGE: 300,
  `}
  _height={`LARGE: 200`}
/>
kylpo commented 7 years ago

https://github.com/smyte/jsxstyle/issues/3

mosesoak commented 7 years ago

Beefy design topic! I'm not well-versed with using media queries, so my question is a bit meta:

are there actually two (or more) patterns that need to be solved for, in that in some cases you need variably-styled content on a per-element basis, and in others you want to be able to declare an entirely different content structure?

Or are you only trying to solve for the first case, which is what I mostly see in the ideas tossed around above. In contrast to react-media which seems to primarily solve for the 2nd case, where you'd actually declare one piece of content multiple times.

My guess is that both cases are probably valid and needed, that perhaps the 1st case is more common and could provide a cleaner syntactic solution, but that the 2nd case might also be common enough to consider solving for as well?

kylpo commented 7 years ago

Syntax should also support things like :hover?

<View
  width={100}
  $width={`
    LARGE: 200,
    XLARGE: 300,
    ':hover': 1000,
  `}
/>

see https://www.npmjs.com/package/glamor 's syntax

Use some sort of Provider wrapper to define breakpoints? fela/packages/fela-plugin-named-media-query at master · rofrischmann/fela

kylpo commented 7 years ago

Consider shorthands for hiding, like https://github.com/idibidiart/react-native-responsive-grid#hidden-props smHidden prop.