样式系统|解决组件中的主题样式功能

问题描述

我试图弄清楚认情况下如何解析组件中的样式系统功能。这个想法是要有一个容器元素,该容器元素可以立即使用主题来提供主要的响应性中断。

现在我在下面做的事情是为样式系统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对象并返回包装在媒体查询中的宽度的函数的想法,但是我想知道样式化系统是否开箱即用?

解决方法

我在文档中找不到任何可以立即进行类似工作的东西,因此我已经手动实现了。

//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]}`
      )};
    `;
  }
);