Skip to content

Angular ​

Mọi component là standalone, dùng signal input / model và chạy được với change detection zoneless.

Thiết lập ​

ts
bootstrapApplication(AppComponent, {
  providers: [
    provideZonelessChangeDetection(),
    provideThlUI({ locale: 'vi', theme: 'green', persist: true }),
  ],
});

Thêm CSS vào angular.json: "styles": ["node_modules/@thl-ui/styles/dist/thl-ui.css"].

Import component ​

ts
@Component({
  imports: [ThlButtonComponent, ThlCardComponent, ThlTranslatePipe], // hoặc imports: [THL_UI]
  template: `<thl-card [title]="'menu.dashboard' | thlT"><button thl-button variant="primary">Tải xuống</button></thl-card>`,
})

Button / input là attribute component trên phần tử native (button[thl-button], input[thlInput], table[thlTable]) nên giữ nguyên ngữ nghĩa HTML, form và a11y.

Service ​

ServiceDùng cho
ThlConfigServicesignal config(), set(patch), defaults()
ThlI18nServicet(), n(), d(), signal locale(), setLocale()
ThlToastServicesuccess/info/warning/error
ThlModalServiceconfirm(options): Promise<boolean>

Binding & form ​

Mọi control vừa implement ControlValueAccessor vừa có signal model:

html
<thl-select [(value)]="country" [options]="countries" />
<thl-select [(ngModel)]="country" [options]="countries" />
<thl-select formControlName="country" [options]="countries" />
ts
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>

Content projection ​

html
<thl-tabs [items]="tabs" [(active)]="tab">
  <ng-template thlTab="home"><p>Trang chủ</p></ng-template>
</thl-tabs>
<thl-data-table [data]="rows" [columns]="cols">
  <ng-template thlCell="salary" let-row>{{ row.salary | currency }}</ng-template>
</thl-data-table>