css-modulesをstyled-styleでstyled-componentsライクに扱う


styled-componentsは素晴らしいCSSinJSライブラリであり多くのプロジェクトが使っていると思いますが、既存のプロジェクトにすぐに導入するのは難しいです。
しかし、styled-styleを使うことでステップ・バイ・ステップにstyled-componentsなあのリーダブルなコンポーネントに変更していけます。

[akameco/styled-style: css modules like styled-components](https://github.com/akameco/styled-style)

## インストール

```
$ yarn add styled-style
```

## 使い方

CreateReactAppのコードをstyledStyleで書き直すと以下のようになります。

```jsx
// @flow
import * as React from 'react'
import { styledStyle } from 'styled-style'
import styles from './App.module.css'
import logo from './logo.svg'

const { div, header, h1, p, img } = styledStyle(styles)

const Wrapper = div('wrapper')
const Header = header('header')
const Title = h1('title')
const Intro = p('intro')
const Logo = img('logo')

function App() {
  return (
    <Wrapper>
      <Header>
        <Logo src={logo} alt="logo" />
        <Title>Welcome to React</Title>
      </Header>
      <Intro>
        To get started, edit <code>src/App.js</code> and save to reload.
      </Intro>
    </Wrapper>
  )
}

export default App
```

`styledStyle`にcssオブジェクトを渡し、`div`や`h1`といったタグを取り出します。あとは、クラスを指定します。
`render`内に`className`が出てこないので、非常に読みやすくなります。
副産物としてはcssに未定義なクラスにアクセスすると開発時のみエラーを表示します。
なので、タイポの検知にも活用できます。

以下、サンプルレポジトリです。

[akameco/styled-style-example](https://github.com/akameco/styled-style-example)

### TypeSciprtサポート

nju33さんからPRをいただき、TypeScriptをサポートしています🎉
以下のように書けます。
ちょっと`call-time generic parameters`が便利すぎる。

```typescript
import {styledStyle} from 'styled-style'
import styles from './style.module.css'

const { div, button } = styledStyle(styles)
const Center = div('center')
const Button = button('btn')
const PrimaryButton = button<{color: string}>([
  'btn',
  'primary',
  p => p.color === 'primary' && 'primary',
])

// button('foo')
// Argument of type '"foo"' is not assignable to parameter of type 'Selector<"center" | "btn" | "primary", {}>'

// <PrimaryButton />
// => Property 'color' is missing in type '{}'
```

## 気持ち

styled-componentsの作者のMax Stoiberさんにnice言われたのでハッピーです😳

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Haha nice, I like it!</p>&mdash; Max Stoiber (@mxstbr) <a href="https://twitter.com/mxstbr/status/960151468035715073?ref_src=twsrc%5Etfw">February 4, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


よかったら是非スターお願いします🤩

何かあればTwitterまたはコメント欄までフィードバックお願いします。

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="ja" dir="ltr">styled-styleをpublishしました🎉<br>css-modulesからCSSinJSへ橋渡し。classNameにさよならしてstyled-componentsのようなreadableなコンポーネントに<a href="https://t.co/DVtbOErvik">https://t.co/DVtbOErvik</a> <a href="https://t.co/GQX0tf6gkw">pic.twitter.com/GQX0tf6gkw</a></p>&mdash; 𝔸𝕂𝔸𝕄𝔼@アルバイト.js (@akameco) <a href="https://twitter.com/akameco/status/960093807260844032?ref_src=twsrc%5Etfw">February 4, 2018</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## フルサンプル

```css:styles.module.css
.center {
  display: flex;
  justify-content: center;
  align-items: center;
}

.btn {
  border-radius: 3px;
  padding: 0.25em 1em;
  margin: 0 1em;
  background: transparent;
  color: palevioletred;
  border: 2px solid palevioletred;
}

.primary {
  background: palevioletred;
  color: white;
}
```

```jsx
import { styledStyle } from 'styled-style'
import styles from './styles.module.css'

const { div, button } = styledStyle(styles)

const Center = div('center')
const Button = button('btn')
const PrimaryButton = button(['btn', 'primary'])

render(
  <Center>
    <Button>Normal Button</Button>
    <PrimaryButton>Primary Button</PrimaryButton>
  </Center>
)
```

### Passed props

```jsx
const Button = button(['btn', p => p.color === 'primary' && 'primary'])

render(
  <div>
    <Button>Normal Button</Button>
    <Button color="primary">Primary Button</Button>
  </div>
)
```