стилизованная система | Разрешить функцию стиля темы в компоненте

Я пытаюсь понять, как разрешить функцию стилизованной системы в компоненте по умолчанию. Идея состоит в том, чтобы иметь элемент контейнера, который использует тему из коробки для предоставления основных адаптивных разрывов.

Прямо сейчас то, что я делаю ниже, - это создание системы стилей. width функцию с таким объектом:

//theme.js
const CONTAINERS = {
  xs: "100%",
  sm: "55rem",
  md: "74rem",
  lg: "100rem",
  xl: "131rem",
};
export default {
 containers: CONTAINERS,
//other items
}
//Container.js
export default (props) => {
  const { containers, grid } = useContext(ThemeContext);
  return (
    <Container px={grid.margin} width={containers} {...props}>
      {props.children}
    </Container>
  );
};

const Container = styled("div")(
  css`
    margin-right: auto;
    margin-left: auto;
    padding-right: 1rem;
    padding-left: 1rem;
  `,
  compose
);

Это ДЕЙСТВИТЕЛЬНО работает, но не так чисто, как хотелось бы. Я бы хотел иметь возможность просто

const Container = styled("div")(
  css`
    margin-right: auto;
    margin-left: auto;
    padding-right: 1rem;
    padding-left: 1rem;
    ${//maybe resolve the responsive widths here}
  `,
  compose //<- a group of styled-system functions supplied in one object
  //or resolve responsive widths here
);

export default Container

Это было бы намного чище, так как я мог бы затем объединить и экспортировать компоненты макета в один файл без необходимости выполнять const Container... + const StyledContainer... формальности.

Я играю с идеей написать функцию, которая зацикливает containers объект и возвращает ширину, обернутую в медиа-запросы, но мне интересно, делает ли styled-system это из коробки?

1 ответ

Решение

Я не могу найти ничего в документации, чтобы сделать что-то подобное из коробки, поэтому я реализовал это вручную.

//theme.js
const BREAKPOINTS = {
  xs: "0em",
  sm: "37em",
  md: "48em",
  lg: "64.625em",
  xl: "84em",
};

const CONTAINERS = {
  xs: "100%",
  sm: "55rem",
  md: "74rem",
  lg: "100rem",
  xl: "131rem",
};

Приведенный ниже сценарий берет объекты выше и помещает значения точек останова в оболочку. @media затем вставляет значения контейнеров как width:внутри этого. Затем возвращает весь лот как css.

const Container = styled("div")(
  css`
    margin-right: auto;
    margin-left: auto;
    padding-right: 1rem;
    padding-left: 1rem;

    &::after,
    &::before {
      content: "";
      display: block;
      min-height: 2rem;
      height: 4vw;
      max-height: 6rem;
    }
  `,
  compose,
  (props) => {
    const breakpoints = props.theme.breakpoints;
    const containers = props.theme.containers;

    const makeMedia = (media) => {
      return (...args) => css`
        @media ${media} {
          ${css(...args)}
        }
      `;
    };

    const getMedia = Object.keys(breakpoints).reduce((media, breakpoint) => {
      const breakpointWidth = breakpoints[breakpoint];
      media[breakpoint] = makeMedia(
        [breakpoint !== 0 && `(min-width: ${breakpointWidth})`]
          .filter(Boolean)
          .join(" and ")
      );
      return media;
    }, {});

    return css`
      ${Object.keys(breakpoints).map(
        (key) => containers[key] && getMedia[key]`width: ${containers[key]}`
      )};
    `;
  }
);
Другие вопросы по тегам