@foxeltech/angular-ui 0.7.44 → 0.7.75

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/components.css +320 -18
  2. package/familjen-grotesk/familjen-grotesk-400-latin-ext.woff2 +0 -0
  3. package/familjen-grotesk/familjen-grotesk-400-latin.woff2 +0 -0
  4. package/familjen-grotesk/familjen-grotesk-400-vietnamese.woff2 +0 -0
  5. package/familjen-grotesk/familjen-grotesk-500-latin-ext.woff2 +0 -0
  6. package/familjen-grotesk/familjen-grotesk-500-latin.woff2 +0 -0
  7. package/familjen-grotesk/familjen-grotesk-500-vietnamese.woff2 +0 -0
  8. package/familjen-grotesk/familjen-grotesk-600-latin-ext.woff2 +0 -0
  9. package/familjen-grotesk/familjen-grotesk-600-latin.woff2 +0 -0
  10. package/familjen-grotesk/familjen-grotesk-600-vietnamese.woff2 +0 -0
  11. package/familjen-grotesk/familjen-grotesk-700-latin-ext.woff2 +0 -0
  12. package/familjen-grotesk/familjen-grotesk-700-latin.woff2 +0 -0
  13. package/familjen-grotesk/familjen-grotesk-700-vietnamese.woff2 +0 -0
  14. package/fesm2022/foxeltech-angular-ui-chart.mjs +197 -24
  15. package/fesm2022/foxeltech-angular-ui-chart.mjs.map +1 -1
  16. package/fesm2022/foxeltech-angular-ui.mjs +504 -108
  17. package/fesm2022/foxeltech-angular-ui.mjs.map +1 -1
  18. package/fonts.css +104 -3
  19. package/package.json +1 -1
  20. package/src/lib/styles/components.css +320 -18
  21. package/src/lib/styles/fonts.css +104 -3
  22. package/src/lib/styles/tailwind.css +12 -0
  23. package/src/lib/styles/theme.css +160 -114
  24. package/src/lib/styles/tokens.css +25 -0
  25. package/src/lib/styles/utilities.css +12 -0
  26. package/src/lib/ui/components/button/button.component.html +2 -0
  27. package/src/lib/ui/components/drawer/drawer.component.scss +3 -1
  28. package/src/lib/ui/components/facets-rail/facets-rail.component.html +1 -6
  29. package/src/lib/ui/components/master-detail/master-detail.component.css +65 -13
  30. package/src/lib/ui/components/master-detail/master-detail.component.html +26 -8
  31. package/src/lib/ui/components/route-skeleton/route-skeleton.component.css +38 -0
  32. package/src/lib/ui/components/route-skeleton/route-skeleton.component.html +184 -0
  33. package/src/lib/ui/components/section-card/section-card.component.html +1 -5
  34. package/src/lib/ui/components/skeleton-dashboard/skeleton-dashboard.component.html +24 -0
  35. package/src/lib/ui/components/skeleton-detail/skeleton-detail.component.html +8 -8
  36. package/src/lib/ui/components/skeleton-facets/skeleton-facets.component.html +15 -0
  37. package/src/lib/ui/components/skeleton-frame/skeleton-frame.component.html +59 -0
  38. package/src/lib/ui/components/skeleton-list/skeleton-list.component.html +6 -6
  39. package/src/lib/ui/components/switch/switch.component.html +1 -1
  40. package/src/lib/ui/components/toast/toast.component.html +6 -6
  41. package/tailwind.css +12 -0
  42. package/theme.css +160 -114
  43. package/tokens.css +25 -0
  44. package/types/foxeltech-angular-ui-chart.d.ts +76 -1
  45. package/types/foxeltech-angular-ui.d.ts +278 -33
  46. package/utilities.css +12 -0
  47. package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.html +0 -21
  48. package/src/lib/ui/components/skeleton-table-loading/skeleton-table-loading.component.scss +0 -0
  49. package/src/lib/ui/components/tab-component/tab.component.html +0 -1
@@ -261,22 +261,135 @@ declare class BaseDialogComponent<T = any> extends BaseComponent implements Afte
261
261
  static ɵdir: _angular_core.ɵɵDirectiveDeclaration<BaseDialogComponent<any>, never, never, {}, {}, never, never, true, never>;
262
262
  }
263
263
 
264
+ /**
265
+ * Overlay chặn màn cho HÀNH ĐỘNG của người dùng (bấm nút, đổi trạng thái,
266
+ * xuất báo cáo…). `app.html` của host bind `fx-ui-loading-panel` vào
267
+ * `listenerAction`.
268
+ *
269
+ * ⚠️ **KHÔNG dùng cho điều hướng.** Channel `listener` + `start()`/`stop()` đã
270
+ * bị XOÁ ở 0.7.70 (Pha 3). Điều hướng dùng skeleton: `FxRouteSkeletonService`
271
+ * đọc `data.skeleton` của route đích và shell dựng `fx-ui-route-skeleton`.
272
+ *
273
+ * Vì sao xoá thay vì để lại: trước đó cả 46 call site đổ chung MỘT channel, lẫn
274
+ * hai ngữ nghĩa (điều hướng vs hành động). Sau khi skeleton thay phần điều
275
+ * hướng, `listener` không còn ai nghe — để lại là một cái bẫy: gọi `start()`
276
+ * tưởng có overlay mà thực tế không có gì hiện.
277
+ */
264
278
  declare class FxLoadingService {
265
- listener: EventEmitter<boolean>;
266
279
  listenerAction: EventEmitter<boolean>;
267
- start(): void;
268
- stop(): void;
269
280
  startAction(): void;
270
281
  stopAction(): void;
271
282
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FxLoadingService, never>;
272
283
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<FxLoadingService>;
273
284
  }
274
285
 
275
- declare class BaseResolver {
276
- loadingService: FxLoadingService;
277
- injector: Injector;
278
- constructor(loadingService: FxLoadingService, injector: Injector);
279
- baseResolverInit(): void;
286
+ /**
287
+ * Một KHỐI trong skeleton của màn. Ghép các khối này theo đúng thứ tự của màn
288
+ * thật thì skeleton mới khớp layout — bảng ra bảng, chart ra chart.
289
+ *
290
+ * - `heading` H1 + subline + `count` nút hành động (mặc định 2, 0 = không có)
291
+ * - `toolbar` search bar + `count` filter pill (mặc định 2)
292
+ * - `table` bảng, skeleton theo TỪNG Ô (`columns` / `rows`)
293
+ * - `cards` lưới card (catalog) — `count` / `cols`
294
+ * - `stat-cards` hàng stat tile rời — `count`
295
+ * - `kpi-strip` MỘT card chia cột, số to (kiểu `app-dash-kpi-row`) — `count`
296
+ * - `panels` lưới section-card có vùng chart — `count` / `cols`
297
+ * - `card` một section-card đơn
298
+ * - `tabs` dải tab
299
+ * - `facets` 3 cụm facets/list/detail
300
+ * - `detail` cụm card detail
301
+ * - `form` card form
302
+ */
303
+ type FxSkeletonBlockKind = 'heading' | 'toolbar' | 'table' | 'cards' | 'stat-cards' | 'kpi-strip' | 'panels' | 'card' | 'tabs' | 'facets' | 'detail' | 'form';
304
+ interface FxSkeletonBlockSpec {
305
+ kind: FxSkeletonBlockKind;
306
+ /**
307
+ * Số phần tử con:
308
+ * - `heading`: số nút hành động (0 = màn không có CTA)
309
+ * - `toolbar`: số filter pill
310
+ * - `panels` `cards` `stat-cards` `kpi-strip` `tabs`: số khối
311
+ */
312
+ count?: number;
313
+ /** `panels` `cards`: số cột ở breakpoint lớn. */
314
+ cols?: number;
315
+ /** `table`: số cột và số hàng. */
316
+ columns?: number;
317
+ rows?: number;
318
+ }
319
+ type FxSkeletonBlock = FxSkeletonBlockKind | FxSkeletonBlockSpec;
320
+ /**
321
+ * Tên gọn cho các layout dùng lại được. Route nên khai thẳng mảng block khi
322
+ * layout của nó khác preset — chính app biết layout của mình, không phải lib.
323
+ */
324
+ type FxSkeletonHint = 'table' | 'panels' | 'dashboard' | 'tabs-facets' | 'facets' | 'detail' | 'form';
325
+ /**
326
+ * Skeleton cho vùng NỘI DUNG trong lúc resolver của route đang chạy.
327
+ *
328
+ * ⚠️ Vì sao skeleton phải nằm ở shell chứ không ở từng màn: Angular **không
329
+ * tạo component cho tới khi resolver xong**, nên một màn không thể tự vẽ
330
+ * skeleton của chính nó trong lúc resolver của nó chạy. Thứ vẽ được phải tồn
331
+ * tại TRƯỚC component đó → shell + router event. Xem `FxRouteSkeletonService`.
332
+ */
333
+ declare class RouteSkeletonComponent {
334
+ /** Tên preset, hoặc mảng block mô tả đúng layout của màn. */
335
+ readonly hint: _angular_core.InputSignal<FxSkeletonHint | FxSkeletonBlock[] | null>;
336
+ readonly blocks: _angular_core.Signal<FxSkeletonBlockSpec[]>;
337
+ cols(b: FxSkeletonBlockSpec): number[];
338
+ rows(b: FxSkeletonBlockSpec): number[];
339
+ items(b: FxSkeletonBlockSpec, fallback: number): number[];
340
+ /** Lớp lưới cho `panels`/`cards` — Tailwind v4 không có safelist nên phải
341
+ * là chuỗi tĩnh, không ghép động. */
342
+ gridClass(b: FxSkeletonBlockSpec): string;
343
+ /** Header ngắn hơn ô dữ liệu, cột đầu rộng nhất (thường là tên). */
344
+ headWidth(c: number): number;
345
+ /**
346
+ * Bề rộng đổi theo cả hàng và cột — cùng bề rộng thì khối skeleton trông
347
+ * như một hình chữ nhật đặc, mất cảm giác "từng field".
348
+ */
349
+ cellWidth(r: number, c: number): number;
350
+ barHeight(i: number): number;
351
+ readonly bars: number[];
352
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RouteSkeletonComponent, never>;
353
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RouteSkeletonComponent, "fx-ui-route-skeleton", never, { "hint": { "alias": "hint"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
354
+ }
355
+
356
+ /**
357
+ * Khai trên route: `data: { skeleton: 'table' }` (tên preset) hoặc
358
+ * `data: { skeleton: ['heading', 'toolbar', 'table'] }` (mảng block, mô tả
359
+ * ĐÚNG layout của màn — bảng ra bảng, chart ra chart).
360
+ */
361
+ declare const FX_SKELETON_DATA_KEY = "skeleton";
362
+ /**
363
+ * Đọc `data.skeleton` của route đích rồi bật/tắt skeleton cho vùng nội dung.
364
+ *
365
+ * ⚠️ Vì sao phải nghe router event chứ không để từng màn tự lo: Angular
366
+ * **không tạo component cho tới khi resolver xong**, nên trong lúc resolver
367
+ * của một màn chạy thì component đó chưa tồn tại — không có gì để vẽ
368
+ * skeleton. Chỉ shell (tồn tại trước) làm được.
369
+ *
370
+ * Mốc dùng là `RoutesRecognized` — event ĐẦU TIÊN mang `RouterStateSnapshot`,
371
+ * và nó xảy ra TRƯỚC `ResolveStart`. `NavigationStart` thì chưa biết route
372
+ * đích nên không đọc được hint.
373
+ */
374
+ declare class FxRouteSkeletonService {
375
+ private readonly router;
376
+ private readonly _hint;
377
+ /** Hint đang hiển thị, `null` = không vẽ skeleton. */
378
+ readonly hint: _angular_core.Signal<FxSkeletonHint | FxSkeletonBlock[] | null>;
379
+ readonly active: _angular_core.Signal<boolean>;
380
+ /**
381
+ * Điều hướng nhanh hơn mốc này thì KHÔNG vẽ skeleton — tránh nháy một
382
+ * nhịp khi resolver trả về gần như tức thì (dữ liệu đã cache).
383
+ */
384
+ private readonly graceMs;
385
+ private timer?;
386
+ private started;
387
+ constructor();
388
+ /** Gọi một lần từ shell (host và mỗi remote standalone). */
389
+ start(): void;
390
+ private clearTimer;
391
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FxRouteSkeletonService, never>;
392
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<FxRouteSkeletonService>;
280
393
  }
281
394
 
282
395
  interface FxListRequest {
@@ -292,11 +405,12 @@ interface FxListResolverContext {
292
405
  pageSize: number;
293
406
  }
294
407
  /**
295
- * Functional replacement for the copy-pasted list-resolver class:
296
- * starts the loading overlay, runs one API request, and on failure stops the
297
- * overlay and shows a parsed error toast the exact convention every
298
- * BaseResolver subclass hand-rolls today. BaseResolver stays for existing
299
- * classes; new routes should use this factory.
408
+ * Chạy MỘT request cho list resolver, lỗi thì hiện toast đã parse.
409
+ *
410
+ * ⚠️ KHÔNG còn bật overlay chặn màn: điều hướng dùng skeleton
411
+ * (`FxRouteSkeletonService` + `data.skeleton` trên route). `BaseResolver` đã bị
412
+ * xoá 0.7.70 mọi resolver giờ là `@Injectable()` thuần hoặc dùng factory
413
+ * này.
300
414
  *
301
415
  * Usage:
302
416
  * resolve: { histories: fxListResolver(ScanManagementApi, (route, state, ctx) =>
@@ -555,9 +669,16 @@ declare class FxUtils {
555
669
  * helpers return `null` for "no meaningful value" and the `toneText` /
556
670
  * `toneBg` / `toneBadge` wrappers fall back to a neutral class.
557
671
  *
558
- * Every emitted utility must appear below as a WHOLE literal string — the
559
- * Tailwind content scanner (v4 has no safelist) only sees complete class
560
- * names. Never rebuild these with string interpolation.
672
+ * Every emitted Tailwind UTILITY must appear below as a WHOLE literal string —
673
+ * the Tailwind content scanner (v4 has no safelist) only sees complete class
674
+ * names. Never rebuild those with string interpolation.
675
+ *
676
+ * ⚠️ Ngoại lệ có chủ đích: `tone-tint-*`, `tone-fg-*`, `tone-dot-*` và
677
+ * `tone-dot-chart-*` là CLASS CSS THẬT khai trong components.css, KHÔNG phải
678
+ * utility Tailwind — chúng luôn tồn tại trong stylesheet nên ghép chuỗi
679
+ * `tone-fg-${tone}` là an toàn. Đó chính là lý do chọn class thay vì utility:
680
+ * ngoài việc tránh xung đột tên (`warning` trong theme Tailwind trỏ vào bộ
681
+ * LEGACY `--og-tone-*`), nó còn xoá hẳn bẫy "class ghép chuỗi bị vô hình".
561
682
  */
562
683
  type Tone = 'critical' | 'danger' | 'warning' | 'success' | 'information';
563
684
  /** Severity / risk-level string → tone (Critical & High → danger, Medium → warning, Low → success). */
@@ -580,7 +701,50 @@ declare function toneText(tone: Tone | null): string;
580
701
  /** Tone → background colour class, with a neutral fallback when there is no value. */
581
702
  declare function toneBg(tone: Tone | null): string;
582
703
  /** Tone → soft pill/badge classes (tinted bg + matching text), neutral fallback. */
583
- declare function toneBadge(tone: Tone | null): string;
704
+ /**
705
+ * Badge severity MẶC ĐỊNH — nền MỀM theo thang đo, Critical ra **đỏ sẫm**.
706
+ *
707
+ * ⚠️ Trước đây hàm này trả nền ĐẶC (`tone-tint-*`, Critical = đen `--og-text`)
708
+ * vì demo có biến thể `.og-badge--solid`. Nhưng demo chỉ dùng biến thể đó ở
709
+ * ĐÚNG MỘT chỗ — badge severity trong danh sách findings — còn app mình gọi
710
+ * `toneBadge()` ở khắp nơi (`project-card`, `score-badge`, `list-row`,
711
+ * `severity-badges`, `tab-group`, badge trong hàng…). Kết quả: pill đen tràn
712
+ * ra mọi màn, anh Tú báo 3 lần (03/09). Nên MẶC ĐỊNH đảo về nền mềm; muốn
713
+ * pill đen thì gọi `toneBadgeSolid()` một cách tường minh.
714
+ */
715
+ declare function toneBadge(tone: Tone | string | null | undefined): string;
716
+ /**
717
+ * Badge severity nền ĐẶC (Critical = `--og-text`, chữ `--og-surface`) — đúng
718
+ * `.og-badge--solid` của demo. CHỈ dùng cho badge severity đứng một mình ở
719
+ * nơi cần nhấn mạnh nhất; đừng dùng cho badge có chấm bên trong (chấm sẽ chìm).
720
+ */
721
+ declare function toneBadgeSolid(tone: Tone | string | null | undefined): string;
722
+ /** Chỉ MÀU của tông, không kèm hình dạng pill — cho ô icon, chip, ô nền. */
723
+ declare function toneTint(tone: Tone | string | null | undefined): string;
724
+ /**
725
+ * CHỮ theo tông — dùng thành viên dễ đọc nhất của mỗi họ severity, KHÔNG phải
726
+ * ramp chart (ramp có `warning #f59e0b` chỉ 2.15:1 trên nền trắng). Xem
727
+ * `.tone-fg-*` trong components.css.
728
+ */
729
+ declare function toneFg(tone: Tone | string | null | undefined): string;
730
+ /**
731
+ * Tông THANG ĐO — cho filter chip severity. Critical ra ĐỎ SẪM (nền mềm pha
732
+ * từ ramp `--og-sev-*`) thay vì pill đen đặc của `toneTint()`: chip filter là
733
+ * một thang đo, không phải badge severity của một finding. Xem `.tone-scale-*`.
734
+ */
735
+ declare function toneScale(tone: Tone | string | null | undefined): string;
736
+ /** Viền theo tông — cho panel trạng thái (dropzone upload…). */
737
+ declare function toneBorder(tone: Tone | string | null | undefined): string;
738
+ /**
739
+ * CHẤM trạng thái trong hàng (`● Confirmed`) — demo dùng màu SEMANTIC
740
+ * (`.og-statusdot--*`), không phải ramp chart.
741
+ */
742
+ declare function toneDot(tone: Tone | string | null | undefined): string;
743
+ /**
744
+ * CHẤM LEGEND của chart — phải TRÙNG màu cung donut nên dùng ramp
745
+ * `--og-sev-*`. Đừng dùng cho chấm trạng thái trong hàng.
746
+ */
747
+ declare function toneDotChart(tone: Tone | string | null | undefined): string;
584
748
  /**
585
749
  * Tone → resolved CSS colour string for ECharts / canvas where a Tailwind
586
750
  * class can't be used (e.g. per-slice pie `itemStyle.color`). Emits the
@@ -1040,7 +1204,7 @@ declare class DndUploadComponent {
1040
1204
  declare class ButtonComponent {
1041
1205
  label: string;
1042
1206
  readonly disabled: _angular_core.InputSignal<boolean>;
1043
- readonly buttonVariant: _angular_core.InputSignal<"default" | "success" | "primary" | "alternative">;
1207
+ readonly buttonVariant: _angular_core.InputSignal<"default" | "success" | "primary" | "cta" | "alternative">;
1044
1208
  icon?: any;
1045
1209
  readonly class: _angular_core.InputSignal<any>;
1046
1210
  readonly loading: _angular_core.InputSignal<boolean>;
@@ -1138,6 +1302,32 @@ declare class SearchBarComponent extends FxComponent<string> implements AfterVie
1138
1302
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SearchBarComponent, "fx-ui-search-bar", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; }, { "search": "search"; "valueChange": "valueChange"; }, never, never, true, never>;
1139
1303
  }
1140
1304
 
1305
+ /**
1306
+ * Một tab của `fx-ui-tab-group`.
1307
+ *
1308
+ * ⚠️ Nội dung tab PHẢI bọc trong `<ng-template>`:
1309
+ *
1310
+ * ```html
1311
+ * <fx-ui-tab [label]="'Components'">
1312
+ * <ng-template>
1313
+ * <app-info-components … />
1314
+ * </ng-template>
1315
+ * </fx-ui-tab>
1316
+ * ```
1317
+ *
1318
+ * Vì sao bắt buộc: trước đây tab dùng `<ng-content>` bọc trong `<ng-template>`
1319
+ * của CHÍNH nó. Cách đó **không hoãn được gì** — `<ng-content>` chỉ CHIẾU node,
1320
+ * còn node do view khai báo (component cha) tạo **eager**. Kết quả: mọi tab đều
1321
+ * khởi tạo và gọi API ngay khi vào màn, dù người dùng chưa mở (đo được trên
1322
+ * scan-info: cả 8 cụm cùng fetch). Nhận `TemplateRef` từ cha thì nội dung chỉ
1323
+ * được dựng khi tab-group stamp template đó.
1324
+ *
1325
+ * Hệ quả cần biết: đổi tab sẽ **huỷ** nội dung tab cũ và dựng lại khi quay lại
1326
+ * — đúng bản chất lazy, giống `matTabContent` của Material.
1327
+ *
1328
+ * `descendants: false` để chỉ bắt `<ng-template>` là con TRỰC TIẾP, tránh nuốt
1329
+ * nhầm template lồng sâu bên trong nội dung tab.
1330
+ */
1141
1331
  declare class TabComponent {
1142
1332
  readonly label: _angular_core.InputSignal<string>;
1143
1333
  icon?: string;
@@ -1147,7 +1337,7 @@ declare class TabComponent {
1147
1337
  readonly tone: _angular_core.InputSignal<Tone | null>;
1148
1338
  readonly content: _angular_core.Signal<TemplateRef<any>>;
1149
1339
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TabComponent, never>;
1150
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TabComponent, "fx-ui-tab", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
1340
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TabComponent, "fx-ui-tab", never, { "label": { "alias": "label"; "required": true; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; "tone": { "alias": "tone"; "required": false; "isSignal": true; }; }, {}, ["content"], never, true, never>;
1151
1341
  }
1152
1342
 
1153
1343
  declare class TabGroupComponent implements AfterContentInit, AfterViewChecked, OnChanges {
@@ -1305,13 +1495,6 @@ declare class SwitchComponent extends FxComponent<any> implements AfterViewInit
1305
1495
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SwitchComponent, "fx-ui-switch", never, { "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "onSwitch": "onSwitch"; }, never, never, true, never>;
1306
1496
  }
1307
1497
 
1308
- declare class SkeletonTableLoadingComponent {
1309
- readonly columns: _angular_core.InputSignal<number>;
1310
- readonly rows: _angular_core.InputSignal<number>;
1311
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonTableLoadingComponent, never>;
1312
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonTableLoadingComponent, "fx-ui-skeleton-table-loading", never, { "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1313
- }
1314
-
1315
1498
  declare class CircleProgressBar {
1316
1499
  readonly percent: _angular_core.InputSignal<number>;
1317
1500
  readonly showPercent: _angular_core.InputSignal<boolean>;
@@ -1437,7 +1620,8 @@ declare class DrawerComponent implements OnInit, OnDestroy {
1437
1620
  /** Row-card skeleton placeholder for master-detail list panes. */
1438
1621
  declare class SkeletonListComponent {
1439
1622
  readonly rows: _angular_core.InputSignal<number>;
1440
- range(n: number): number[];
1623
+ /** computed, không phải method: method trả mảng MỚI mỗi lần render. */
1624
+ readonly rowList: _angular_core.Signal<number[]>;
1441
1625
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonListComponent, never>;
1442
1626
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonListComponent, "fx-ui-skeleton-list", never, { "rows": { "alias": "rows"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
1443
1627
  }
@@ -1448,7 +1632,9 @@ declare class SkeletonDetailComponent {
1448
1632
  readonly cards: _angular_core.InputSignal<number>;
1449
1633
  /** Rows per content card. */
1450
1634
  readonly rows: _angular_core.InputSignal<number>;
1451
- range(n: number): number[];
1635
+ /** computed, không phải method: method trả mảng MỚI mỗi lần render. */
1636
+ readonly cardList: _angular_core.Signal<number[]>;
1637
+ readonly rowList: _angular_core.Signal<number[]>;
1452
1638
  rowWidth(i: number): number;
1453
1639
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonDetailComponent, never>;
1454
1640
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonDetailComponent, "fx-ui-skeleton-detail", never, { "cards": { "alias": "cards"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -1557,6 +1743,12 @@ declare class FilterPillsComponent {
1557
1743
  readonly value: _angular_core.InputSignal<string | undefined>;
1558
1744
  readonly valueChange: _angular_core.OutputEmitterRef<string>;
1559
1745
  isActive(option: FxFilterPillOption): boolean;
1746
+ /**
1747
+ * Pill ĐANG CHỌN dùng **accent** (xanh), không phải nền đen — khớp demo:
1748
+ * design ref 11 vẽ pill "All 40" là pill accent. Nền đen `--og-text` chỉ
1749
+ * dành cho badge severity Critical (`.og-badge--solid`), không dùng cho
1750
+ * trạng thái chọn của filter (anh Tú chốt 03/09).
1751
+ */
1560
1752
  pillClass(option: FxFilterPillOption): string;
1561
1753
  countClass(option: FxFilterPillOption): string;
1562
1754
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FilterPillsComponent, never>;
@@ -1735,7 +1927,13 @@ declare class MasterDetailComponent implements AfterViewInit, AfterContentInit {
1735
1927
  table: BaseMasterDetailComponent<any>;
1736
1928
  /** Fixed list-pane width on lg+ viewports (stacked full-width below). */
1737
1929
  readonly listWidth: _angular_core.InputSignal<string>;
1738
- readonly maxListHeight: _angular_core.InputSignal<string>;
1930
+ /**
1931
+ * Chiều cao CHUNG của cả ba cụm (facets / list / detail). Mặc định trừ phần
1932
+ * chrome phía trên (topbar + tab strip + context line) khỏi viewport để
1933
+ * bảng ba cột vừa đúng một màn, không kéo trang cuộn theo.
1934
+ * Chỉ có tác dụng từ 1080px — xem `.fx-md-row` trong CSS.
1935
+ */
1936
+ readonly paneHeight: _angular_core.InputSignal<string>;
1739
1937
  readonly pageSizeOptions: _angular_core.InputSignal<number[]>;
1740
1938
  /** Labels come in via inputs — the lib carries no i18n. */
1741
1939
  readonly emptyMessage: _angular_core.InputSignal<string>;
@@ -1760,7 +1958,7 @@ declare class MasterDetailComponent implements AfterViewInit, AfterContentInit {
1760
1958
  optionId(index: number): string;
1761
1959
  onKeydown(event: KeyboardEvent, index: number): void;
1762
1960
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MasterDetailComponent, never>;
1763
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<MasterDetailComponent, "fx-ui-master-detail", never, { "table": { "alias": "table"; "required": false; }; "listWidth": { "alias": "listWidth"; "required": false; "isSignal": true; }; "maxListHeight": { "alias": "maxListHeight"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "listLabel": { "alias": "listLabel"; "required": false; "isSignal": true; }; "skeletonCards": { "alias": "skeletonCards"; "required": false; "isSignal": true; }; "paginationStyle": { "alias": "paginationStyle"; "required": false; "isSignal": true; }; "prevLabel": { "alias": "prevLabel"; "required": false; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; }, {}, ["rowTemplate", "detailTemplate"], ["[mdFacets]", "[mdHeader]", "[mdFilters]"], true, never>;
1961
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<MasterDetailComponent, "fx-ui-master-detail", never, { "table": { "alias": "table"; "required": false; }; "listWidth": { "alias": "listWidth"; "required": false; "isSignal": true; }; "paneHeight": { "alias": "paneHeight"; "required": false; "isSignal": true; }; "pageSizeOptions": { "alias": "pageSizeOptions"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "listLabel": { "alias": "listLabel"; "required": false; "isSignal": true; }; "skeletonCards": { "alias": "skeletonCards"; "required": false; "isSignal": true; }; "paginationStyle": { "alias": "paginationStyle"; "required": false; "isSignal": true; }; "prevLabel": { "alias": "prevLabel"; "required": false; "isSignal": true; }; "nextLabel": { "alias": "nextLabel"; "required": false; "isSignal": true; }; }, {}, ["rowTemplate", "detailTemplate"], ["[mdFacets]", "[mdHeader]", "[mdFilters]"], true, never>;
1764
1962
  }
1765
1963
 
1766
1964
  interface FxMenuItem {
@@ -2173,6 +2371,53 @@ declare class PipelineStepperComponent {
2173
2371
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<PipelineStepperComponent, "fx-ui-pipeline-stepper", never, { "stages": { "alias": "stages"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "stageClick": "stageClick"; }, never, ["*"], true, never>;
2174
2372
  }
2175
2373
 
2374
+ /** Facets-rail skeleton: N nhóm, mỗi nhóm một eyebrow + vài dòng lựa chọn. */
2375
+ declare class SkeletonFacetsComponent {
2376
+ readonly groups: _angular_core.InputSignal<number>;
2377
+ readonly rows: _angular_core.InputSignal<number>;
2378
+ readonly groupList: _angular_core.Signal<number[]>;
2379
+ readonly rowList: _angular_core.Signal<number[]>;
2380
+ rowWidth(i: number): number;
2381
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonFacetsComponent, never>;
2382
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonFacetsComponent, "fx-ui-skeleton-facets", never, { "groups": { "alias": "groups"; "required": false; "isSignal": true; }; "rows": { "alias": "rows"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2383
+ }
2384
+
2385
+ /** Dashboard skeleton: một hàng KPI + N panel có vùng chart. */
2386
+ declare class SkeletonDashboardComponent {
2387
+ readonly kpis: _angular_core.InputSignal<number>;
2388
+ readonly panels: _angular_core.InputSignal<number>;
2389
+ readonly kpiList: _angular_core.Signal<number[]>;
2390
+ readonly panelList: _angular_core.Signal<number[]>;
2391
+ readonly barList: _angular_core.Signal<number[]>;
2392
+ /** Chiều cao cột giả — dựng hình chart mà không cần dữ liệu. */
2393
+ barHeight(i: number): number;
2394
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonDashboardComponent, never>;
2395
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonDashboardComponent, "fx-ui-skeleton-dashboard", never, { "kpis": { "alias": "kpis"; "required": false; "isSignal": true; }; "panels": { "alias": "panels"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2396
+ }
2397
+
2398
+ /**
2399
+ * Skeleton của cả AppFrame (drawer + topbar + vùng nội dung).
2400
+ *
2401
+ * Chỉ dùng cho giai đoạn **bootstrap**, khi shell của host còn CHƯA tồn tại
2402
+ * (App.ngOnInit đang kiểm tenant + session, router chưa initialNavigation).
2403
+ * Mọi điều hướng SAU đó đã có shell thật → dùng `fx-ui-route-skeleton` bên
2404
+ * trong vùng nội dung, đừng vẽ lại cả frame.
2405
+ *
2406
+ * ⚠️ `contentHint` là thứ làm F5 không còn vẽ hình generic. Lần điều hướng ĐẦU
2407
+ * tạo ra chính `HomeComponent` — nơi chứa `fx-ui-route-skeleton` — nên vùng nội
2408
+ * dung không thể tự vẽ skeleton của route ở lần đó. Truyền hint vào đây để
2409
+ * frame dựng đúng composition của màn đích ngay từ F5.
2410
+ */
2411
+ declare class SkeletonFrameComponent {
2412
+ readonly navItems: _angular_core.InputSignal<number>;
2413
+ /** Composition của route đích; null thì vẽ khối generic. */
2414
+ readonly contentHint: _angular_core.InputSignal<FxSkeletonHint | FxSkeletonBlock[] | null>;
2415
+ readonly navList: _angular_core.Signal<number[]>;
2416
+ navWidth(i: number): number;
2417
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkeletonFrameComponent, never>;
2418
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkeletonFrameComponent, "fx-ui-skeleton-frame", never, { "navItems": { "alias": "navItems"; "required": false; "isSignal": true; }; "contentHint": { "alias": "contentHint"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2419
+ }
2420
+
2176
2421
  declare class ConfirmationDialogComponent {
2177
2422
  private ref;
2178
2423
  bindings: any;
@@ -2201,9 +2446,9 @@ declare class ConfirmationDialogComponent {
2201
2446
  */
2202
2447
  declare class UiModule {
2203
2448
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<UiModule, never>;
2204
- static ɵmod: _angular_core.ɵɵNgModuleDeclaration<UiModule, never, [typeof i1$1.FormsModule, typeof i1$1.ReactiveFormsModule, typeof i2.RouterModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective, typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof SliderComponent, typeof SwitchComponent, typeof SkeletonTableLoadingComponent, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof FilterPillsComponent, typeof StageDotsComponent, typeof CodeBlockComponent, typeof ScreenshotFrameComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof MenuComponent, typeof ThemePickerComponent, typeof PendingBadgeComponent, typeof SampleFrameComponent, typeof ScoreBadgeComponent, typeof StatusDotComponent, typeof SparkbarComponent, typeof SegmentedComponent, typeof ListRowComponent, typeof BarListComponent, typeof FacetsRailComponent, typeof ProjectCardComponent, typeof PipelineStepperComponent, typeof ConfirmationDialogComponent], [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof SliderComponent, typeof SwitchComponent, typeof SkeletonTableLoadingComponent, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof FilterPillsComponent, typeof StageDotsComponent, typeof CodeBlockComponent, typeof ScreenshotFrameComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof MenuComponent, typeof ThemePickerComponent, typeof PendingBadgeComponent, typeof SampleFrameComponent, typeof ScoreBadgeComponent, typeof StatusDotComponent, typeof SparkbarComponent, typeof SegmentedComponent, typeof ListRowComponent, typeof BarListComponent, typeof FacetsRailComponent, typeof ProjectCardComponent, typeof PipelineStepperComponent, typeof ConfirmationDialogComponent, typeof i1$1.FormsModule, typeof i1$1.ReactiveFormsModule, typeof i2.RouterModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective]>;
2449
+ static ɵmod: _angular_core.ɵɵNgModuleDeclaration<UiModule, never, [typeof i1$1.FormsModule, typeof i1$1.ReactiveFormsModule, typeof i2.RouterModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective, typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof SliderComponent, typeof SwitchComponent, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof FilterPillsComponent, typeof StageDotsComponent, typeof CodeBlockComponent, typeof ScreenshotFrameComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof MenuComponent, typeof ThemePickerComponent, typeof PendingBadgeComponent, typeof SampleFrameComponent, typeof ScoreBadgeComponent, typeof StatusDotComponent, typeof SparkbarComponent, typeof SegmentedComponent, typeof ListRowComponent, typeof BarListComponent, typeof FacetsRailComponent, typeof ProjectCardComponent, typeof PipelineStepperComponent, typeof SkeletonFacetsComponent, typeof SkeletonDashboardComponent, typeof SkeletonFrameComponent, typeof RouteSkeletonComponent, typeof ConfirmationDialogComponent], [typeof InputComponent, typeof SelectComponent, typeof RadioButtonComponent, typeof CheckboxComponent, typeof DndUploadComponent, typeof ButtonComponent, typeof RadioButtonToggleComponent, typeof DatetimePicker, typeof LoadingPanel, typeof SearchBarComponent, typeof TabGroupComponent, typeof TabComponent, typeof HeroIconComponent, typeof ToastComponent, typeof ToastContainerComponent, typeof TagComponent, typeof SliderComponent, typeof SwitchComponent, typeof CircleProgressBar, typeof TreeDiagram, typeof TableCell, typeof KanbanBoardComponent, typeof DrawerComponent, typeof SkeletonListComponent, typeof SkeletonDetailComponent, typeof StatCardsComponent, typeof EmptyStateComponent, typeof FilterChipsComponent, typeof FilterPillsComponent, typeof StageDotsComponent, typeof CodeBlockComponent, typeof ScreenshotFrameComponent, typeof MeterComponent, typeof SectionCardComponent, typeof InfoFieldComponent, typeof SeverityBadgesComponent, typeof MasterDetailComponent, typeof MenuComponent, typeof ThemePickerComponent, typeof PendingBadgeComponent, typeof SampleFrameComponent, typeof ScoreBadgeComponent, typeof StatusDotComponent, typeof SparkbarComponent, typeof SegmentedComponent, typeof ListRowComponent, typeof BarListComponent, typeof FacetsRailComponent, typeof ProjectCardComponent, typeof PipelineStepperComponent, typeof SkeletonFacetsComponent, typeof SkeletonDashboardComponent, typeof SkeletonFrameComponent, typeof RouteSkeletonComponent, typeof ConfirmationDialogComponent, typeof i1$1.FormsModule, typeof i1$1.ReactiveFormsModule, typeof i2.RouterModule, typeof HasPermissionDirective, typeof TrimOnBlurDirective]>;
2205
2450
  static ɵinj: _angular_core.ɵɵInjectorDeclaration<UiModule>;
2206
2451
  }
2207
2452
 
2208
- export { AuthInterceptor, AuthStateService, BarListComponent, BaseComponent, BaseDialogComponent, BaseMasterDetailComponent, BaseResolver, BaseTableComponent, BreadcrumbService, ButtonComponent, CheckboxComponent, CircleProgressBar, CodeBlockComponent, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FX_ICON_SPRITE_URL, FacetsRailComponent, FilterChipsComponent, FilterPillsComponent, FxComponent, FxDialogService, FxLoadingService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, ListRowComponent, LoadingPanel, MasterDetailComponent, MenuComponent, MeterComponent, NotificationService, OG_LIGHT_THEMES, OG_PICKER_THEMES, OG_PICKER_THEME_META, OG_THEMES, OG_THEME_META, PendingBadgeComponent, PermissionGuard, PermissionService, PipelineStepperComponent, ProjectCardComponent, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, SampleFrameComponent, ScoreBadgeComponent, ScreenshotFrameComponent, SearchBarComponent, SectionCardComponent, SegmentedComponent, SelectComponent, SeverityBadgesComponent, SkeletonDetailComponent, SkeletonListComponent, SkeletonTableLoadingComponent, SliderComponent, SparkbarComponent, StageDotsComponent, StatCardsComponent, StatusDotComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemePickerComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule, anyFeatureEnabled, countTone, createApi, featureEnabled, fxListResolver, scoreTone, severityTone, toneBadge, toneBg, toneColor, toneText };
2209
- export type { Breadcrumb, ColumnChangedEvent, DrawerItem, ErrorMessages, FxApiClass, FxBarListItem, FxConfirmOptions, FxFacetGroup, FxFacetOption, FxFacetSelection, FxFeatureFlags, FxFilterChipOption, FxFilterPillOption, FxListRequest, FxListResolverContext, FxListRowBadge, FxMenuItem, FxPipelineStage, FxPipelineStageState, FxProjectCard, FxProjectCardChip, FxProjectCardMetric, FxSegmentedOption, FxSeverityBadge, FxStatCard, FxStatCardDelta, FxTableFilters, IRadioButton, KanbanColumn, NotificationCallback, NotificationConnectOptions, OgTheme, OgThemeMeta, RealtimeTableEvent, RealtimeTableSyncOptions, TableResult, TagType, ToastData, Tone, TreeNode, UploadResult };
2453
+ export { AuthInterceptor, AuthStateService, BarListComponent, BaseComponent, BaseDialogComponent, BaseMasterDetailComponent, BaseTableComponent, BreadcrumbService, ButtonComponent, CheckboxComponent, CircleProgressBar, CodeBlockComponent, ConfirmationDialogComponent, DatetimePicker, DndUploadComponent, DrawerComponent, EmptyStateComponent, FX_ICON_SPRITE_URL, FX_SKELETON_DATA_KEY, FacetsRailComponent, FilterChipsComponent, FilterPillsComponent, FxComponent, FxDialogService, FxLoadingService, FxRouteSkeletonService, FxStorageService, FxToastrService, FxUtils, FxValidators, HasPermissionDirective, HeroIconComponent, HttpLoaderFactory, HttpWrapper, InfoFieldComponent, InputComponent, KanbanBoardComponent, ListRowComponent, LoadingPanel, MasterDetailComponent, MenuComponent, MeterComponent, NotificationService, OG_LIGHT_THEMES, OG_PICKER_THEMES, OG_PICKER_THEME_META, OG_THEMES, OG_THEME_META, PendingBadgeComponent, PermissionGuard, PermissionService, PipelineStepperComponent, ProjectCardComponent, RadioButtonComponent, RadioButtonToggleComponent, RealtimeTableSync, RouteSkeletonComponent, SampleFrameComponent, ScoreBadgeComponent, ScreenshotFrameComponent, SearchBarComponent, SectionCardComponent, SegmentedComponent, SelectComponent, SeverityBadgesComponent, SkeletonDashboardComponent, SkeletonDetailComponent, SkeletonFacetsComponent, SkeletonFrameComponent, SkeletonListComponent, SliderComponent, SparkbarComponent, StageDotsComponent, StatCardsComponent, StatusDotComponent, SwitchComponent, TabComponent, TabGroupComponent, TableCell, TagComponent, ThemePickerComponent, ThemeService, ToastComponent, ToastContainerComponent, TranslationModule, TranslationService, TreeDiagram, TrimOnBlurDirective, UiModule, anyFeatureEnabled, countTone, createApi, featureEnabled, fxListResolver, scoreTone, severityTone, toneBadge, toneBadgeSolid, toneBg, toneBorder, toneColor, toneDot, toneDotChart, toneFg, toneScale, toneText, toneTint };
2454
+ export type { Breadcrumb, ColumnChangedEvent, DrawerItem, ErrorMessages, FxApiClass, FxBarListItem, FxConfirmOptions, FxFacetGroup, FxFacetOption, FxFacetSelection, FxFeatureFlags, FxFilterChipOption, FxFilterPillOption, FxListRequest, FxListResolverContext, FxListRowBadge, FxMenuItem, FxPipelineStage, FxPipelineStageState, FxProjectCard, FxProjectCardChip, FxProjectCardMetric, FxSegmentedOption, FxSeverityBadge, FxSkeletonBlock, FxSkeletonBlockKind, FxSkeletonBlockSpec, FxSkeletonHint, FxStatCard, FxStatCardDelta, FxTableFilters, IRadioButton, KanbanColumn, NotificationCallback, NotificationConnectOptions, OgTheme, OgThemeMeta, RealtimeTableEvent, RealtimeTableSyncOptions, TableResult, TagType, ToastData, Tone, TreeNode, UploadResult };
package/utilities.css CHANGED
@@ -18,6 +18,18 @@
18
18
  @apply flex flex-row items-center px-semi;
19
19
  }
20
20
 
21
+ /* Nhãn "eyebrow" (tiêu đề panel, nhóm facet) — spec CUỐI của demo sau khi
22
+ lớp override đè lên base: font MONO, 11.5px, weight 600, letter-spacing
23
+ 0.02em và KHÔNG viết hoa. Base DS viết hoa + tracking 0.08em, nhưng
24
+ override đặt `text-transform: none` nên demo hiển thị chữ thường. */
25
+ @utility txt-eyebrow {
26
+ font-family: var(--og-font-mono);
27
+ font-size: var(--og-fs-xs);
28
+ font-weight: 600;
29
+ letter-spacing: 0.02em;
30
+ color: rgb(var(--og-text-muted));
31
+ }
32
+
21
33
  @utility card-common {
22
34
  @apply text-left px-xl py-large border border-border-default rounded-lg shadow-sm transition-colors duration-500 ease-in-out;
23
35
  }
@@ -1,21 +0,0 @@
1
- <div class="w-full animate-pulse space-y-normal">
2
- <div
3
- class="grid gap-small"
4
- [ngStyle]="{ 'grid-template-columns': 'repeat(' + columns() + ', minmax(0, 1fr))' }"
5
- >
6
- @for(col of [].constructor(columns()); track col) {
7
- <div class="h-6 bg-bg-hover rounded"></div>
8
- }
9
- </div>
10
-
11
- @for(row of [].constructor(rows()); track row) {
12
- <div
13
- class="grid gap-small"
14
- [ngStyle]="{ 'grid-template-columns': 'repeat(' + columns() + ', minmax(0, 1fr))' }"
15
- >
16
- @for(col of [].constructor(columns()); track col) {
17
- <div class="h-7 bg-bg-hover rounded"></div>
18
- }
19
- </div>
20
- }
21
- </div>
@@ -1 +0,0 @@
1
- <ng-template><ng-content></ng-content></ng-template>