# vanila-extract

## with Typescript

### CSSProperties

> 표준 CSS 속성들의 정확한 타입들을 제공

```typescript
import { CSSProperties } from '@vanila-extract/css'

export type StyleProps = {
  align?: CSSProperties['textAlign'],
  decoration?: CSSProperties['textDecoration'],
  ...,
}
```

* CSS 속성에 어떤 값이 들어갈 수 있는지를 TypeScript 수준에서 정확하게 보장해주는 타입들을 제공

## Packages

> `vanilla-extract`는 기본적으로 정적 빌드이지만, \
> emotion의 style props처럼 런타임에 동적으로 스타일 값을 바꿀 수있는 기능들을 제공

{% hint style="info" %}
[clsx](https://www.npmjs.com/package/clsx)

* 여러 className들을 조합해서 사용할 수 있도록 도와주는 라이브러리
  {% endhint %}

#### 동적? 정적?

* css-in-js는 런타임에 스타일을 계산하기 때문에, 스타일을 자유롭게 확장하거나 오버라이드하기에 유연함
  * 보통 스타일을 자유롭게 설정할 수 있는 라이브러리(Chakra나 MUI)들을 보면 내부적으로 `emotion` 같은 css-in-js를 사용하는 경우가 많음
  * 런타임 스타일 계산 방식때문에 유연하게 스타일을 확장가능한 것
* 반면, vanilla-extract는 정적 CSS를 생성하는 방식이라 미리 정의된 조합 안에서만 스타일을 제어할 수 있고, 확장이나 오버라이드는 클래스네임 단위로 제한됨
  * 모든 경우의 수를 **사전에 클래스 형태로 변환해 정적으로 생성**하기 때문
  * 이런 상황에서 확장성 있게 자유롭게 스타일을 커스텀하려면 결국 `style` 속성을 사용할 수밖에 없음
  * 다만, `style`은 인라인 스타일이기 때문에 `className`으로 적용한 스타일보다 우선순위가 높음
  * 즉, 예상치 못한 스타일 덮어쓰기가 생길 수 있으니 주의해야함

### Sprinkles

> 스타일 값들을 미리 선언해서 생성해두고 css의 클래스를 바꿔서 동적으로 처리되는것처럼 동작

```bash
npm install @vanilla-extract/sprinkles
```

#### depineProperties

> 사용하고자하는 스타일 값(**properties**)들을 미리 선언

* 프로퍼티에 허용되는 값들을 미리 정의해 두고, 스타일 작성 시 어떤 값들이 가능한지 타입과 함께 명확하게 관리 가능
* 조건에 따른 값들을 분기 가능 (반응형, 다크모드 등)
* **`shorthands` :** 정의해둔 값들을 하나의 축약 키워드로 묶어서 간결하게  사용하게 해줄 수 있는 기능

```typescript
import { defineProperties, createSprinkles } from '@vanila-extract/sprinkles';

const responsiveProperties = defineProperties({
  // 반응형 조건
  conditions: {
    mobile: {},
    tablet: { '@media': 'screen and (min-width: 768px)' },
    desktop: { '@media': 'screen and (min-width: 1024px)' },
  },
  defaultCondition: 'mobile',
  
  /* ex: 다크모드
  conditions: {
    lightMode: {},
    darkMode: { '@media': '(prefers-color-scheme: dark)' }
  }
  defaultCondition: 'lightMode'
  */

  
  properties: {
    paddingTop: {
      none: 0,
      xs: '4px',
      sm: '6px',
      md: '8px',
    },
    ...
  },
  shorthands: {
    padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight']
  }
})

export const sprinkles = createSprinkles(
  responsiveProperties,
  //...etc,
);

// It's a good idea to export the Sprinkles type too
export type Sprinkles = Parameters<typeof sprinkles>[0];
```

#### Usage

```typescript
className: clsx(sprinkles(props), props.className) 
```

### Recipes

> 여러 스타일 **변형(variants)**&#xC744; 체계적으로 구성할 때 유용한 기능

```bash
npm install @vanilla-extract/recipes
```

* 버튼처럼 다양한 상태 (color, size, variants)를 조합해서 관리해야할 때 유용
* props를 받아 자동으로 대응되는 스타일을 적용할 수 있게 해줌
* 빌드 단계에서 스타일 조합의 경우의 수를 미리 계산해 CSS 클래스로 변환
* 런타임에서는 props에 따라 해당 클래스만 교체해 적용는식으로, 마치 동적으로 스타일이 적용되는 것처럼 동작

```typescript
import { recipes } from '@vanila-extract/recipes';

export const styles = recipes({
  variants: {
    size: {
      xs: {},
      sm: {},
      md: {},
    },
  },
  defaultVariants: {
    size: 'xs',
  } 
})
```
