Componentes Utilitários para Composição de Layouts
Tags: react, javascript
Published: 2024-02-17 15:13:26

É comum em bibliotecas de componentes conhecidas, a disponibilização de componentes utilitários que facilitam na composição de componentes maiores e consequentemente aumentam a produtividade na construção de interfaces. Por exemplo:

- [Mantine](https://mantine.dev/core/flex/).
- [Chakra](https://chakra-ui.com/docs/components/flex).
- [Material UI](https://mui.com/material-ui/react-stack/).

No entanto, também é comum ver projetos com a utilização de CSS-in-JS, desta forma:

```tsx
import * as S from "./styles";

() => (
  <S.Layout>
    <S.HeaderContent>
      <S.Content>
        <S.Image />
      </S.Content>

      <S.HeaderTitleContent>
        <S.PageTitle>...</S.PageTitle>
        <S.PageDescription>...</S.PageDescription>
        <S.MoreDetailsLink>...</S.MoreDetailsLink>
      </S.HeaderTitleContent>
    </S.HeaderContent>

    <S.ClassSelection>...</S.ClassSelection>

    <S.ClassesList>
      <S.ButtonBox>
        <S.Button>...</S.Button>
      </S.ButtonBox>
    </S.ClassesList>

    <Divider full position="horizontal" />

    <div>
      <S.DynamicInformation>...</S.DynamicInformation>

      <Divider full position="horizontal" />

      <div>
        <S.DynamicContent>
          <S.Data>
            <S.Day>...</S.Day>
            <S.Month>...</S.Month>
            <S.Year>...</S.Year>
          </S.Data>
          <S.Content>
            <S.ContentLastChild>
              <S.ContentTitle>...</S.ContentTitle>
              <S.ContentDescription>...</S.ContentDescription>
            </S.ContentLastChild>
          </S.Content>
        </S.DynamicContent>

        <Divider full position="horizontal" />
      </div>
    </div>

    <S.Help>...</S.Help>
  </S.Layout>
);
```

Cada componente do grupo `S` tem um arquivo que exporta um _Styled Component_. Veja abaixo:

```tsx
import { styled } from "@/stitches";

const Layout = styled("div", {
  padding: "$spacing2xl",
  maxWidth: "51.125rem", // 818px
  minWidth: "21.563rem", // 345px
});

export default Layout;
```

```tsx
import { styled } from "@/stitches";

const HeaderContent = styled("div", {
  display: "flex",
  gap: "$spacingLg",
  marginBottom: "$spacingXl",
  flexDirection: "column",

  "@md": {
    flexDirection: "row",
  },
});

export default HeaderContent;
```

```tsx
import { styled } from "@/stitches";

const Content = styled("div", {
  width: "17.813rem", // 285px
});

export default Content;
```

Enfim... (cansei, não vai rolar listar todos 😅). É possível notar que:

- Há um gasto de esforço desnecessário (dar nome, criar um arquivo, exportar/importar, tudo isso para as vezes definir APENAS um atributo CSS. Isso não me parece prático).
- Existe muito código repetido, é comum ver vários arquivos definindo tipografia, flex box, grid e espaçamento.
- Dar nome para coisas abstratas é difícil e o resultado é algo como: XxxxContent, XxxxData, XxxxBox, XxxxWrapper e XxxxInfo.
- Deduzir o que o código renderiza é bem trabalhoso, os estilos estão longes entre-si, longe do markup e com nomes não óbvios.

Veja um exemplo, de como ficaria a reescrita do código acima, utilizando componentes utilitários para isso:

```tsx
import { Box, Flex, Text } from "@foo/components";

() => (
  <Box padding="2xl" css={{ maWidth: "51.125rem", minWidth: "21.563rem" }}>
    <Flex gap="lg" direction={{ "@initial": "column", "@md": "row" }}>
      <Box css={{ width: "17.813rem" }}>
        <Box as="img" css={{ width: "100%" }} />
      </Box>

      <Flex direction="column" justify="space-between">
        <Text as="h1" font="headingLgBold">
          ...
        </Text>
        <Text as="p" font="labelRegular">
          ...
        </Text>
        <Text as="p" font="captionRegular">
          ...
        </Text>
      </Flex>
    </Flex>

    <Text as="h3" font="labelBold" gutterBottom>
      ...
    </Text>

    <Flex wrap="wrap" gap="md">
      <Box css={{ width: "3.125rem" }}>
        <Button>...</Button>
      </Box>
    </Flex>

    <Divider full position="horizontal" />

    <Box css={{ marginBottom: "$spacingLg" }}>
      <Text as="p" font="titleRegular" gutterBottom>
        ...
      </Text>

      <Divider full position="horizontal" />

      <div>
        <Flex gap="lg" align="start" css={{ padding: "$spacingMd 0" }}>
          <Flex direction="column" align="center">
            <Text font="headingLgBold">...</Text>
            <Text font="headingSmRegular" transform="capitalize">
              ...
            </Text>
            <Text font="bodyRegular">...</Text>
          </Flex>

          <Flex direction="column">
            <Text as="p" font="labelBold" gutterBottom>
              ...
            </Text>
            <Text font="captionRegular">...</Text>
          </Flex>
        </Flex>

        <Divider full position="horizontal" />
      </div>
    </Box>

    <Text font="labelRegular">...</Text>
  </Box>
);
```

Consegue perceber como reaproveitamos mais código? Além disso, fica mais rápido compor o layout e facilita em manutenções futuras, pois é mais fácil de deduzir.

Gostou? Não concorda? Deixe suas experiências e dicas nos comentários.