Skip to content

Angular ​

すべてのコンポーネントは standalone で、signal inputs / models を使い、zoneless の変更検知で動作します。

セットアップ ​

ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideZonelessChangeDetection } from '@angular/core';
import { provideThlUI } from '@thl-ui/angular';

bootstrapApplication(AppComponent, {
  providers: [
    provideZonelessChangeDetection(),
    provideThlUI({ locale: 'ja', theme: 'green', persist: true, components: { Table: { pageSize: 25 } } }),
  ],
});

CSS は angular.json → styles: ["node_modules/@thl-ui/styles/dist/thl-ui.css"] に追加します。

コンポーネントの import ​

使うものだけを import するか、THL_UI ですべてをまとめて import します。

ts
import { ThlButtonComponent, ThlCardComponent, ThlTranslatePipe, THL_UI } from '@thl-ui/angular';

@Component({
  selector: 'app-demo',
  imports: [ThlButtonComponent, ThlCardComponent, ThlTranslatePipe], // または: imports: [THL_UI]
  template: `
    <thl-card [title]="'menu.dashboard' | thlT">
      <button thl-button variant="primary" icon="download">ダウンロード</button>
    </thl-card>`,
})
export class DemoComponent {}

ボタンと入力欄はネイティブ要素に付ける属性コンポーネント(button[thl-button]、a[thl-button]、input[thlInput]、table[thlTable])なので、ネイティブのセマンティクス、フォーム、a11y が保たれます。

サービス ​

サービス用途
ThlConfigServiceconfig() signal、set(patch)、prefix()、defaults(name, props)
ThlI18nServicet()、n()、d()、locale() signal、setLocale()
ThlToastServicesuccess/info/warning/error/show/dismiss
ThlModalServiceconfirm(options): Promise<boolean>

パイプ: {{ 'common.save' | thlT }} · {{ 'pagination.total' | thlT: { count: n } }}。

双方向バインディングとフォーム ​

すべてのコントロールは ControlValueAccessor を実装し、さらに signal の model を公開しているため、3 つのスタイルすべてが使えます。

html
<thl-select [(value)]="country" [options]="countries" />
<thl-select [(ngModel)]="country" [options]="countries" />
<thl-select formControlName="country" [options]="countries" />

Reactive Forms のバリデーションは同じコアのルールを使い、i18n メッセージは thl-field がレンダリングします。

ts
import { thlValidators, rules } from '@thl-ui/angular';

form = new FormGroup({
  email: new FormControl('', thlValidators(rules.required(), rules.email())),
});
html
<thl-field [label]="'pages.login.email' | thlT" for="email" required [control]="form.controls.email">
  <input thlInput id="email" formControlName="email" />
</thl-field>

コンテンツプロジェクション ​

React の render props / Vue のスコープ付きスロットの代わりにテンプレートを使います。

html
<thl-tabs [items]="tabs" [(active)]="tab">
  <ng-template thlTab="home"><p>ホーム</p></ng-template>
  <ng-template thlTab="profile"><p>プロフィール</p></ng-template>
</thl-tabs>

<thl-data-table [data]="rows" [columns]="cols" rowKey="id">
  <ng-template thlCell="salary" let-row>{{ row.salary | currency }}</ng-template>
</thl-data-table>

ルーティング(AppLayout) ​

html
<thl-app-layout [menu]="menu" [currentPath]="path()" [user]="user">
  <ng-template thlMenuLink let-item let-cls="cls" let-content="content">
    <a [routerLink]="item.href" [class]="cls"><ng-container [ngTemplateOutlet]="content" /></a>
  </ng-template>
  <router-outlet />
</thl-app-layout>