💭

emotionのメディアクエリにTailwind風の名前を付ける

2022/03/25に公開

背景

https://emotion.sh/docs/media-queries#reusable-media-queries

import { jsx, css } from '@emotion/react'

const breakpoints = [576, 768, 992, 1200]

const mq = breakpoints.map(
  bp => `@media (min-width: ${bp}px)`
)

render(
  <div>
    <div
      css={{
        color: 'green',
        [mq[0]]: {
          color: 'gray'
        },
        [mq[1]]: {
          color: 'hotpink'
        }
      }}
    >
      Some text!
    </div>
    (中略)
  </div>
)

これではどのサイズ向けにCSSを書いているのかパット見で分かりません。

解決

mq.ts
export const breakpoints = {
  sm: 640,
  md: 768,
  lg: 1024,
  xl: 1280,
  '2xl': 1536,
} as const;

export const mq = (key: keyof typeof breakpoints) => `@media (min-width: ${breakpoints[key]}px)`;

const assertionで再帰的にreadonlyにしています。

https://tailwindcss.com/docs/responsive-design

各ブレークポイントの値はここから拝借しています。

使用例

<div
  css={{
    color: 'green',
    ${mq('sm')}: {
      color: 'gray'
    },
    ${mq('md')}: {
      color: 'hotpink'
    }
  }}
>
  Some text!
</div>

enumじゃありませんがkeyof typeofのおかげでキーは推測され、予期しない値を指定することも出来ません。

参考

https://typescriptbook.jp/reference/values-types-variables/const-assertion

https://stackoverflow.com/questions/53662208/types-from-both-keys-and-values-of-object-in-typescript/53662389#53662389

Discussion