Skip to content

Instantly share code, notes, and snippets.

@danieljpgo
Created June 8, 2022 13:36
Show Gist options
  • Save danieljpgo/bf0b30eb5066560e3ddc8cf04b816dd8 to your computer and use it in GitHub Desktop.
Save danieljpgo/bf0b30eb5066560e3ddc8cf04b816dd8 to your computer and use it in GitHub Desktop.
Examples of documentation using .md files

Styled Components

Introdução

Tema

A construção do tema é sempre uma parte importante para o desenvolvimento de qualquer projeto, com styled-components é possível desenvolver um tema de forma dinâmica para acelerar o desenvolvimento e facilita se manter consistente durante a criação dos estilos.

Inicialmente, para se criar o arquivo de tema para a aplicação, recomendamos seguir a seguinte estrutura:

/src
└── /app
    ├── ...
    ├── ...
    └── /styles
        ├── global.ts
        ├── theme.ts
        └── /tokens
            ├── breakpoints.ts
            ├── typography.ts
            ├── spacing.ts
            ├── shapes.ts
            ├── layers.ts
            └── colors.ts   

Para múltiplos temas:

/src
└── /app
    ├── ...
    ├── ...
    └── /styles
        ├── global.ts
        ├── /theme
        |   ├── light.ts
        |   └── dark.ts
        └── /tokens
            ├── breakpoints.ts
            ├── typography.ts
            ├── spacing.ts
            ├── shapes.ts
            ├── layers.ts
            └── colors.ts   

A partir disso, dentro do arquivo de tema:

  • Importe os design tokens.
  • Crie e exporte a variavel theme.
  • Dentro do theme, defina os valores dos designs tokens a serem utilizados pelo tema como no exemplo abaixo.
import {
  breakpoints,
  typography,
  spacing,
  shapes,
  layers,
  colors,
} from './tokens';

export const theme = {
  title: 'main', // nome para auxiliar no debugging caso possua multiplos temas por meio React Devtools

  colors: { 
    primary: {
      lighter: colors.blue['200'],
      light: colors.blue['400'],
      main: colors.blue['500'],
      dark: colors.blue['600'],
      darker: colors.blue['800'],
    },
    secundary: {
      lighter: colors.purple['200'],
      light: colors.purple['400'],
      main: colors.purple['500'],
      dark: colors.purple['600'],
      darker: colors.purple['800'],
    },
    tertiary: { 
      lighter: colors.pink['200'],
      light: colors.pink['400'],
      main: colors.pink['500'],
      dark: colors.pink['600'],
      darker: colors.pink['800'],
    },
    success: {
      light: colors.green['400'],
      main: colors.green['500'],
      dark: colors.green['600'],
    },
    attention: {
      light: colors.yellow['400'],
      main: colors.yellow['500'],
      dark: colors.yellow['600'],
    },
    error: {
      light: colors.red['400'],
      main: colors.red['500'],
      dark: colors.red['600'],
    },
    surface: {
      primary: colors.blue['100'],
      secundary: colors.purple['100'],
      tertiary: colors.pink['100'],
      main: colors.white,
      constrast: colors.gray['100'],
    },
    text: {
      primary: colors.gray['800'],
      secundary: colors.gray['300'],
      tertiary: colors.gray['200'],
      main: colors.blue['100'],
      constrast: colors.gray['100'],
    },
  },
  breakpoints,
  typography,
  spacing,
  shapes,
  layers,
} as const;

Design Tokens

Os design tokens são uma forma de padronizar a estilização das interface, utilizando valores e nomes comuns, a fim de acelerar o desenvolvimento e aumentar sua consistência.

Segue o exemplo de tokens que já estão sendo utilizado em projetos, lembrando que o importante é a nomenclatura e a organização, não os valores.

// spacings.ts
export const spacing = {
  '2xs': '2px',
  xs: '4px',
  sm: '8px',
  md: '16px',
  lg: '32px',
  xl: '56px',
  '2xl': '64px',
} as const;
// shapes.ts
export const shapes = {
  borderRadius: { 
    sm: '4px',
    md: '8px',
    lg: '16px',
    full: '999999px'
  },
  borderWidth: {
    sm: '1px',
    md: '2px',
    lg: '4px',
  }
} as const;
// breakpoints.ts
export const breakpoints = {
  '2xs': '360px',            
  xs: '480px',
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
  '2xl': '1536px',
} as const;
// typography.ts
export const typography = {
  family: { // @TODO adicionar exemplo
    primary: '',
    secondary: '',
  },
  weight: {
    sm: '400',
    md: '500',
    lg: '600',
    xl: '700',
  },
  sizes: {
    xs: '12px',
    sm: '14px',
    md: '16px',
    lg: '24px',
    xl: '32px',
    '2xl': '48px',
  },
  lineHeight: { // @TODO adicionar exemplo
    sm: '',
    md: '',
    lg: '',
    xl: '',
  },
} as const;
// effects.ts
export const effects = {
  opacity: {
    xs: '0.1',
    sm: '0.3',
    md: '0.5',
    lg: '0.7',
    full: '1',
  },
  boxShadow: { // @TODO adicionar exemplo
    sm: '',
    md: '',
    lg: '',
  }
} as const;
// layers.ts
export const layers = {
  base: 10,
  menu: 20,
  overlay: 30,
  modal: 40,
  alwaysOnTop: 50,
} as const;

TypeScript

Utilizando o styled-components com TypeScript, é possível garantir a execução correta do tema desenvolvido para a aplicação, de forma segura e com developer experience incrível.

Segue um exemplo:

styled components com typescript

Para isso:

  • Crie o tema e defina os seus valores de forma esttica.
  • Utilize o as const para garantir que todos os valores sejam read only e assim o TypeScript conseguir inferir os tipos e os próprios valores
// theme.ts
export const theme = {
  colors: {
    // ...
  },
  breakpoints,
  typography,
  spacing,
  shapes,
  layers,
} as const;

Após a criação do arquivo de tema:

  • Crie um arquivo de tipagem chamado styled.d.ts.
  • Importe o arquivo de tema e crie um tipo a partir dele utilizando o typeof.
  • Declare um module do styled-components.
  • Exporte o DefaultTheme do styled-components estendendo o seu tema.
// styled.d.ts
import { theme } from '../theme';

type Theme = typeof theme;

declare module 'styled-components' {
  export interface DefaultTheme extends Theme {}
}

Estilizando componentes

Preferências

TODO: - Adicionar algo como ordem. padrões de css/estilizacao em geral

Tema e Props

Utilizando styled-components, existem diversas formas de acessar suas props, a fim de padronizar esse acesso, criamos esses dois padrões:

  • Em casos onde só será utilizado uma única vez as props, utilize da seguinte forma:

Bom - 😃

export const Button = styled.button`
  border-radius: ${({ theme }) => theme.shapes.borderRadius.xs};
`;

Ruim - ☹️

export const Button = styled.button`
  ${({ theme }) => css`
    border-radius: ${theme.shapes.borderRadius.xs};
  `}
`;
  • Em casos onde só será necessário utilizar várias vezes as props, utilize da seguinte forma:

Bom - 😃

export const Button = styled.button`
  ${({ theme }) => css`
    color: ${theme.colors.text.contrast};
    padding: ${theme.spacing.xs} ${theme.spacing.md};
    border-radius: ${theme.shapes.borderRadius.xs};
    background-color: ${theme.colors.primary.main};
    :hover {
      background-color: ${theme.colors.primary.dark};
    }
    :active {
      background-color: ${theme.colors.primary.darker};
    }
    :disabled {
      background-color: ${theme.colors.primary.lighter};
    }
  `}
`;

Ruim - ☹️

export const Button = styled.button`
  color: ${({ theme }) => colors.text.contrast};
  padding: ${({ theme }) => theme.spacing.xs} ${theme.spacing.md};
  border-radius: ${({ theme }) => theme.shapes.borderRadius.xs};
  background-color: ${({ theme }) => theme.colors.primary.main};
  :hover {
    background-color: ${({ theme }) => theme.colors.primary.dark};
  }
  :active {
    background-color: ${({ theme }) => theme.colors.primary.darker};
  }
  :disabled {
    background-color: ${({ theme }) => theme.colors.primary.lighter};
  }
`;

Variações

Durante o desenvolvimento, se torna necessário criar variações de estilos para o mesmo componente, que variam dependendo do valor recebidos em suas props, exemplo:

<Button color="primary" size="md">
  Submit
</Button>

A partir disso, é interessante encapsular essas estilizações, pois facilitar o entendimento do código, auxilia na manutenção e na adição de novas estilizações:

const sizes = {
  sm: css`
    padding: ${({ theme }) => theme.spacing['2xs']} ${({ theme }) => theme.spacing.sm};
  `,
  md: css`
    padding: ${({ theme }) => theme.spacing.xs} ${({ theme }) => theme.spacing.md};
  `,
  lg: css`
    padding: ${({ theme }) => theme.spacing.sm} ${({ theme }) => theme.spacing.lg};
  `,
};

const colors = {
  primary: css`
    ${({ theme }) => css`
      color: ${theme.colors.primary.light};
      background-color: ${theme.colors.primary.main};
      :hover {
        background-color: ${theme.colors.primary.dark};
      }
      :active {
        background-color: ${theme.colors.primary.darker};
      }
      :disabled {
        background-color: ${theme.colors.primary.lighter};
      }
    `};
  `,
  secondary: css`
    ${({ theme }) => css`
      color: ${theme.colors.secondary.light};
      background-color: ${theme.colors.secondary.main};
      :hover {
        background-color: ${theme.colors.secondary.dark};
      }
      :active {
        background-color: ${theme.colors.secondary.darker};
      }
      :disabled {
        background-color: ${theme.colors.secondary.lighter};
      }
    `};
  `,
};

type ButtonProps = {
  size: keyof typeof sizes;
  color: keyof typeof colors;
};

export const Button = styled.button<ButtonProps>`
  ${({ theme, color }) => css`
    border-radius: ${theme.shapes.borderRadius.xs};

    // ...

    ${sizes[size]}
    ${colors[color]}
  `}
`;

Por fim, não esqueça de utilizar keyof typeof para extrair os possíveis valores de cada variação e utilizar na tipagem das props;

Referências

Typescript

Table of Contents

General

todo

Compiler Options

todo

Standards

todo

Naming

Generics

With generics, you can write dynamic and reusable generic blocks of code. Furthermore, you can apply generics in TypeScript to classes, interfaces, and functions. However, you can write anything in the type definition, so follow a list of conventions for generics type:

  • K and V are reserved for key-value generic data structures, K for key types and V for value types;
  • T and U are reserved for generic data types;

Other generic parameters should have meaningful names:

Bad 😦

function foo<A, S>(attributes: Array<A>, state: S): void {
  // ...
}

Good 😃

function foo<Attribute, State>(attributes: Array<Attribute>, state: State): void {
  // ...
}

Typing

Don't use any type

Let's start with the main point, we cannot trust TypeScript types if we allow any type in the codebase.

From Handbook, any type should only be used to migrate a javascript codebase.

Bad 😦

const a: any = 4;
const b: string = a; // no compile time errors

b.toLowerCase(); // runtime error!

If you do not know which type will be received, use the unknown.

todo

Avoid Type Assertions

Type assertion in TypeScript is the as syntax and angle-bracket syntax made available by TypeScript to "assert" any TypeScript identifier to a type of the implementer’s choosing, this can easily be misused and lead to anti-patterns.

Type assertion allows any object to receive any typing.

interface Person {
  name: string;
  age: number;
  occupation: "marketing" | "engineer"; // occupation is a mandatory attribute
}

Bad 😦

const john = {
  name: "John",
  age: 25,
} as Person; // occupation was not required

// or

const william = <Person>{
  name: "William",
  age: 25,
}; // occupation was not required

Good 😃

const william: Person = {
  name: "William",
  age: 25,
  occupation: "engineer",
};

see more.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment