[Angular] さくっとCarbon Design Systemを使ってみる

## 概要
最近WebアプリでかっこいいUIをさくっと作りたいときは、[Carbon Design System](https://carbondesignsystem.com/)をよく使っています。
この記事では、AngularでCarbon Design Systemを使って、テキストボックスに値を入力し、ボタンを押すとモーダルが表示されるだけのシンプルなUIの作り方をご紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/5f5c839e-8f6f-88d5-f0db-3df8be4a697a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/5d9612ef-b6f8-f84f-5b6e-0b10b7078ccb.png)

## Carbon Design Systemとは？
Carbon Design Systemは、IBMが提供しているオープンソースのデザインシステムです。
IBMの公式サイトやIBM Cloudのコンソールなどで利用されており、AngularやReact、Vue.jsなどのメジャーなフレームワークで利用できるようになっています。
青を差し色にした角張ったデザインがクールで個人的にお気に入りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/b69851a9-57c5-5f89-4851-eba90d883c98.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/be52d5af-319a-7801-b35c-9cd8edef6d3d.png)

## 前提
この記事は、以下のパッケージがインストールされていることを前提としています。
|  パッケージ名  |  バージョン  |
| ---- | ---- |
|  Node.js  |  18.10.0  |
|  npm  |  8.19.2  |
|  Angular CLI  |  16.1.4  |

## 手順
### Angularプロジェクトを作成する
以下のコマンドを実行し、Angularプロジェクトを作成します。

```
ng new my-carbon-tutorial
```

ルーティングは有効、スタイルのフォーマットはCSSで作成します。Carbon Design Systemの公式チュートリアルでは、SCSSを使っていますが、あえてCSSを選択しています（特に理由はないです）

```
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
```

### Carbon Design Systemをインストールする
作成したAngularプロジェクトのディレクトリ配下に移動し、以下のコマンドを実行します。

```
npm i --save carbon-components-angular @carbon/styles
```

インストールが完了したら、`styles.css`を開き、コードを以下の通り修正します。
`margin-top-10`と`margin-top-20`は、Carbon Design Systemとは直接関係ありませんが、レイアウトの調整用に後で使いたいため、今のうちに追加しておきます。

```styles.css
@import '~@carbon/styles/css/styles.min.css';

.margin-top-10 {
  margin-top: 10px;
}
.margin-top-20 {
  margin-top: 20px;
}
```

`styles.css`の修正が完了したら、`app.module.ts`を開き、コードを以下の通り修正します。

```app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';
import { 
  ButtonModule,
  InputModule,
  ModalModule,
  ThemeModule,
  UIShellModule
} from 'carbon-components-angular';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    ButtonModule,
    InputModule,
    ModalModule,
    ThemeModule,
    UIShellModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

### ヘッダーを作成する

appディレクトリ配下で以下のコマンドを実行し、ヘッダーのコンポーネントを作成します。
```
ng g component components/header
```

`header.component.ts`を開き、コードを以下の通り修正します。
追加するのは、class内の`@HostBinding`の部分です。この記述がないと、ヘッダーがコンテンツの上に被さってしまうため、ヘッダーを表示する場合は忘れずに記述するようにしましょう。
```header.component.ts
import { Component, HostBinding } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent {
  @HostBinding('class.cds--header') headerClass = true;
}
```

`header.component.html`を開き、コードを以下の通り修正します。
`cdsTheme`の部分で、ヘッダーのテーマを指定しています。`g100`を指定した場合は、ヘッダーの背景色が黒、文字色が白で表示されます。ここは`white` `g10` `g90` `g100`のいずれかで指定する必要があります。ちなみに、gはgrayのgです。
`cds-header`の部分がヘッダーの本体です。ロゴの部分に表示したい文字列を`name`に指定しています。`brand`は指定しなくてもよいのですが、指定しない場合デフォルトで`name`で指定している文字列の頭に`IBM`をつけてくる（今回の場合、`brand`を指定しないと`IBM My Carbon Tutorial`になる）ため、今回は空文字を指定しています。

```header.component.html
<div cdsTheme="g100">
  <cds-header name="My Carbon Tutorial" brand="" />
</div>
```

`header.component.ts`と`header.component.html`を修正したら、`app.component.html`を開き、コードを以下の通り修正します。
```app.component.html
<app-header></app-header>
```

ここまでの修正が完了したら、`ng serve`でローカルサーバを起動させ、http://localhost:4200/ にアクセスしてみます。
以下の画像のように、画面上部にヘッダーが表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/ae8dedb0-9061-077d-7e04-38d2561e4bde.png)


### メインページを作成する

appディレクトリ配下で以下のコマンドを実行し、メインページのコンポーネントを作成します。
```
ng g component components/main
```

`main.component.ts`を開き、コードを以下の通り修正します。
テキストボックスに入力された文字列を保持するフィールドとモーダルの開閉を制御するフィールドを定義しておきます。
```main.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.css']
})
export class MainComponent {
  public name = '';
  public isOpen = false;
}
```

`main.component.html`を開き、コードを以下の通り修正します。
inputタグに`cdsText`、buttonタグに`cdsButton`をdirectiveとして指定することで、テキストボックスとボタンがCarbon Design Systemのスタイルになります。
`cds-modal`の部分は名前の通り、モーダルの表示に使用しています。
```main.component.html
<h2>Welcome to Carbon Tutorial!</h2>

<div class="margin-top-20">
  <input cdsText placeholder="Your name please" [(ngModel)]="name"/>
</div>
<div class="margin-top-10">
  <button 
    cdsButton="primary" 
    [disabled]="!name.length" 
    (click)="isOpen = !isOpen"
  >
    Hello!
  </button>
</div>

<cds-modal [open]="isOpen" (closeSelect)="isOpen = !isOpen">
  <cds-modal-header (closeSelect)="isOpen = !isOpen">
    <p class="cds--modal-header__heading">Success!!</p>
  </cds-modal-header>
  <div class="cds--modal-content">
    <p>Hello, {{name}}!!</p>
  </div>
  <cds-modal-footer>
    <ng-container>
      <button
        cdsButton="primary"
        (click)="isOpen = !isOpen"
      >
        Close
      </button>
    </ng-container>
  </cds-modal-footer>
</cds-modal>
```

`main.component.ts`と`main.component.html`を修正したら、`app-routing.module.ts`を開き、コードを以下の通り修正します。
```app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { MainComponent } from './components/main/main.component';

const routes: Routes = [
  {
    path: '',
    component: MainComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```

`app-routing.module.ts`を修正したら、`app.component.html`を開き、コードを以下の通り修正します。
コンテンツは、mainタグやdivタグで囲ったうえで、`cds--content`をclassとして指定しておくと、paddingなどをよろしくやってくれます。逆に指定しないと、ヘッダーがコンテンツの上に被さってしまいます。
```app.component.html
<app-header></app-header>
<main class="cds--content">
  <router-outlet></router-outlet>
</main>
```

ここまでの修正が完了したら、再度 http://localhost:4200/ にアクセスしてみます。
以下の画像のような画面が表示されたら、テキストボックスに適当な文字を入力し、「Hello!」ボタンをクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/e1b4bd37-3717-719c-5b11-5473106fa4d8.png)
モーダルが表示され、「Hello, [テキストボックスに入力した文字]!!」と表示されればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134250/5d9612ef-b6f8-f84f-5b6e-0b10b7078ccb.png)

## 参考文献
https://carbondesignsystem.com/developing/angular-tutorial/overview/