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
| Service | Dùng cho |
|---|---|
ThlConfigService | signal config(), set(patch), defaults() |
ThlI18nService | t(), n(), d(), signal locale(), setLocale() |
ThlToastService | success/info/warning/error |
ThlModalService | confirm(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>