Files
twenty/docs/docs/developer/frontend/style-guide.mdx
2023-08-30 14:28:34 +02:00

223 lines
5.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sidebar_position: 3
sidebar_custom_props:
icon: TbPencil
---
# Style guide
We define here the rules to follow when writing code.
Our goal is to have a consistent codebase, easy to read and easy to maintain.
For this we prefer to tend towards being a bit more verbose than being too concise.
Always keep in mind that code is read more often than it is written, especially on an open source project, where anyone can contribute.
There are a lot of rules that are not defined here, but that are automatically checked by our linters.
## React
### Use functional components
Always use TSX functional components.
Do not use default import with const, because it's harder to read and harder to import with code completion.
```tsx
// ❌ Bad, harder to read, harder to import with code completion
const MyComponent = () => {
return <div>Hello World</div>;
};
export default MyComponent;
// ✅ Good, easy to read, easy to import with code completion
export function MyComponent() {
return <div>Hello World</div>;
};
```
### Props
Create the type of the props and call it `OwnProps` if there's no need to export it.
Use props destructuring.
```tsx
// ❌ Bad, no type
export function MyComponent(props) {
return <div>Hello {props.name}</div>;
};
// ✅ Good, type
type OwnProps = {
name: string;
};
export function MyComponent({ name }: OwnProps) {
return <div>Hello {name}</div>;
};
```
#### Refrain from using `React.FC` or `React.FunctionComponent` to define prop types.
```tsx
/* ❌ - Bad, defines the component type annotations with `FC`
* - With `React.FC`, the component implicitly accepts a `children` prop
* even if it's not defined in the prop type. This might not always be
* desirable, especially if the component doesn't intend to render
* children.
*/
const EmailField: React.FC<{
value: string;
}> = ({ value }) => <TextInput value={value} disabled fullWidth />;
```
```tsx
/* ✅ - Good, a separate type (OwnProps) is explicitly defined for the
* component's props
* - This method doesn't automatically include the children prop. If
* you want to include it, you have to specify it in OwnProps.
*/
type OwnProps = {
value: string;
};
function EmailField({ value }: OwnProps) {
return <TextInput value={value} disabled fullWidth />;
}
```
## JavaScript
### Use nullish-coalescing operator `??`
```tsx
// ❌ Bad, can return 'default' even if value is 0 or ''
const value = process.env.MY_VALUE || 'default';
// ✅ Good, will return 'default' only if value is null or undefined
const value = process.env.MY_VALUE ?? 'default';
```
### Use optional chaining `?.`
```tsx
// ❌ Bad
onClick && onClick();
// ✅ Good
onClick?.();
```
## TypeScript
### Use type instead of Interface
We decided to always use type instead of interface, because they almost always overlap, and type is more flexible.
```tsx
// ❌ Bad
interface MyInterface {
name: string;
}
// ✅ Good
type MyType = {
name: string;
};
```
### Use string literals instead of enums
[String literals](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types) are the go-to way to handle enum-like values in TypeScript. They are easier to extend with Pick and Omit, and offer a better developer experience, especially with code completion.
You can see why TypeScript recommend avoiding enums here : https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#enums
However, GraphQL codegen will generate enums, so you can't avoid them completely, but avoid creating new ones.
```tsx
// ❌ Bad, utilizes an enum
enum Color {
Red = "red",
Green = "green",
Blue = "blue",
}
let color = Color.Red;
```
```tsx
// ✅ Good, utilizes a string literal
let color: "red" | "green" | "blue" = "red";
```
## Styling
### Use StyledComponents
Components should be styled with [styled-components](https://emotion.sh/docs/styled).
```tsx
// ❌ Bad
<div className="my-class">Hello World</div>
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
Styled components should be prefixed with "Styled" to differentiate them from "real" components.
```tsx
// ❌ Bad
const Title = styled.div`
color: red;
`;
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
### Theming
Utilizing the theme for the majority of component styling is the preferred approach.
#### Units of measurement
Avoid using `px` or `rem` values directly within the styled components. The necessary values are generally already defined in the theme, so its recommended to make use of the theme for these purposes.
#### Colors
Refrain from introducing additional colors; instead, utilize the existing palette from the theme. Should there be a situation where the palette does not align, kindly leave a comment so that it can be rectified.
```tsx
// ❌ Bad, directly specifies style values without utilizing the theme
const StyledButton = styled.button`
color: #333333;
font-size: 1rem;
font-weight: 400;
margin-left: 4px;
border-radius: 50px;
`;
```
```tsx
// ✅ Good, utilizes the theme
const StyledButton = styled.button`
color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.regular};
margin-left: ${({ theme }) => theme.spacing(1)};
border-radius: ${({ theme }) => theme.border.rounded};
`;