@sdcorejs/angular 19.0.6 → 19.0.8

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 (97) hide show
  1. package/README.md +8 -2
  2. package/assets/STYLE-GUIDE.md +13 -0
  3. package/components/autoid-inspector/index.d.ts +1 -7
  4. package/components/autoid-inspector/src/autoid-inspector.component.d.ts +22 -8
  5. package/components/autoid-inspector/src/models/autoid-element.model.d.ts +7 -7
  6. package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +17 -8
  7. package/components/autoid-inspector/src/models/autoid-inspector-config.model.d.ts +10 -5
  8. package/components/autoid-inspector/src/services/autoid-audit.service.d.ts +4 -4
  9. package/components/autoid-inspector/src/services/autoid-export.service.d.ts +7 -6
  10. package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +3 -3
  11. package/components/index.d.ts +1 -0
  12. package/components/upload-file/src/upload-file.component.d.ts +7 -4
  13. package/fesm2022/sdcorejs-angular-components-anchor.mjs +2 -3
  14. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  15. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +195 -25
  16. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  17. package/fesm2022/sdcorejs-angular-components-badge.mjs +2 -2
  18. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  19. package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
  20. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  21. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +5 -6
  22. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
  23. package/fesm2022/sdcorejs-angular-components-editor.mjs +4 -4
  24. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  25. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +4 -4
  26. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  27. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  28. package/fesm2022/sdcorejs-angular-components-inform.mjs +2 -2
  29. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  30. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +2 -2
  31. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-modal.mjs +2 -2
  33. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-operator.mjs +2 -2
  35. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-org-chart.mjs +2 -2
  37. package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-preview.mjs +3 -3
  39. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +8 -8
  41. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-section.mjs +2 -2
  43. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +6 -4
  45. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-splitter.mjs +16 -2
  47. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-table.mjs +8 -9
  49. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-tree.mjs +2 -2
  51. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +21 -16
  53. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components.mjs +1 -0
  55. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +4 -5
  57. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +3 -3
  59. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +4 -4
  61. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-forms-chip.mjs +4 -4
  63. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  64. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +8 -9
  65. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-forms-date.mjs +5 -6
  67. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +5 -6
  69. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +2 -2
  71. package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +5 -6
  73. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-input.mjs +3 -3
  75. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-radio.mjs +3 -4
  77. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-select.mjs +2 -2
  79. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-switch.mjs +3 -4
  81. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  82. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +5 -7
  83. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  84. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +30 -7
  85. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
  86. package/fesm2022/sdcorejs-angular-modules-layout.mjs +2 -3
  87. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-services-api.mjs +1 -2
  89. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  90. package/fesm2022/sdcorejs-angular-services-confirm.mjs +2 -2
  91. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  92. package/forms/input-number/src/input-number.component.d.ts +0 -1
  93. package/modules/keycloak/htmls/auth-keycloak-error.html +54 -0
  94. package/modules/keycloak/htmls/silent-renew.html +7 -0
  95. package/modules/keycloak/keycloak.configuration.d.ts +25 -0
  96. package/modules/keycloak/keycloak.service.d.ts +5 -0
  97. package/package.json +1 -1
package/README.md CHANGED
@@ -365,7 +365,13 @@ option: SdTableOption<Product> = {
365
365
  });
366
366
  return { items: res.data, total: res.total };
367
367
  },
368
- columns: [...],
368
+ columns: [
369
+ { field: 'code', type: 'string', title: 'Mã', width: '120px' },
370
+ { field: 'name', type: 'string', title: 'Tên', sortable: true },
371
+ { field: 'status', type: 'values', title: 'Trạng thái',
372
+ useBadge: (val) => ({ color: val === 'ACTIVE' ? 'success' : 'secondary', title: val })
373
+ },
374
+ ],
369
375
  command: {
370
376
  align: 'right',
371
377
  commands: [
@@ -737,4 +743,4 @@ Core UI components expose runtime state via lowercase `data-*` attributes for e2
737
743
 
738
744
  ## License
739
745
 
740
- MIT - see the LICENSE file.
746
+ MIT - see the LICENSE file.
@@ -22,6 +22,7 @@
22
22
  14. [Custom theme](#14-custom-theme)
23
23
  15. [Fonts & Images shipped](#15-fonts--images-shipped)
24
24
  16. [What is NOT shipped](#16-what-is-not-shipped) — anti-confusion cho AI
25
+ 17. [AI rendering guardrails](#17-ai-rendering-guardrails) — ưu tiên Core UI trước khi viết CSS mới
25
26
 
26
27
  ---
27
28
 
@@ -605,3 +606,15 @@ Tham chiếu qua `core/image.scss` utility hoặc trực tiếp `assets/images/<
605
606
  | `modal` | dùng `<sd-modal>` |
606
607
 
607
608
  > Lưu ý lớn nhất: **spacing scale đã đổi từ Bootstrap multiplier (1=4px, 2=8px…) sang px tuyệt đối**. `mb-3` trong Bootstrap = 16px; trong `@sdcorejs/angular` `mb-3` = **3px**. Reading code cũ cần convert (× 4) cẩn thận hoặc thay bằng `mb-16`.
609
+
610
+ ---
611
+
612
+ ## 17. AI rendering guardrails
613
+
614
+ Khi sinh UI mới, agent phải rà docs Core UI trước và ưu tiên component/utility đã có thay vì tự tạo class SCSS trong component.
615
+
616
+ - **Spacing layout dùng bội số 4px**: ưu tiên `4`, `8`, `12`, `16`, `24`, `32`... cho margin, padding, gap, gutter. Không sinh spacing lẻ như `3px`, `5px`, `7px` trừ khi có yêu cầu pixel-perfect rõ ràng.
617
+ - **Hạn chế class CSS cục bộ**: trước khi viết `.field-label`, `.status-pill`, `.detail-row`, `.cell-input`..., kiểm tra có utility class hoặc component `sd-*` phù hợp không. Chỉ thêm SCSS mới khi Core UI không có pattern tương đương.
618
+ - **View/read-only label + value**: dùng `<sd-view>` hoặc `[viewed]="true"` trên form component. Không tự dựng cặp label/value bằng class riêng cho các màn hình DETAIL.
619
+ - **Trạng thái, nhãn, counter**: dùng `<sd-badge>` hoặc `useBadge` của `<sd-table>`. Không tự viết badge/pill/status class trong component nếu chỉ để thể hiện trạng thái.
620
+ - **Input trong table hoặc vùng dense**: trong `<sd-table>`, inline filter, editable cell, toolbar/cell dày đặc, truyền `size="sm"` cho các form component hỗ trợ size như `<sd-input>`, `<sd-select>`, `<sd-autocomplete>`, `<sd-date>`, `<sd-date-range>`, `<sd-datetime>`, `<sd-input-number>`, `<sd-textarea>`, `<sd-chip>`, `<sd-chip-calendar>`, `<sd-input-color>`.
@@ -1,8 +1,2 @@
1
1
  export * from './src/autoid-inspector.component';
2
- export * from './src/models/autoid-element.model';
3
- export * from './src/models/autoid-inspector-config.model';
4
- export * from './src/models/autoid-export-format.model';
5
- export * from './src/services/autoid-scanner.service';
6
- export * from './src/services/autoid-audit.service';
7
- export * from './src/services/autoid-highlight.service';
8
- export * from './src/services/autoid-export.service';
2
+ export { SD_AUTOID_INSPECTOR_CONFIGURATION, type SdAutoidInspectorConfiguration } from './src/models/autoid-inspector-config.model';
@@ -1,32 +1,41 @@
1
1
  import { OnDestroy } from '@angular/core';
2
- import { SdAutoidElement, SdAutoidAuditResult } from './models/autoid-element.model';
3
- import { SdAutoidInspectorConfig } from './models/autoid-inspector-config.model';
2
+ import { AutoidElement, AutoidAuditResult } from './models/autoid-element.model';
3
+ import { SdAutoidInspectorConfiguration } from './models/autoid-inspector-config.model';
4
+ import { AutoidE2eTarget, AutoidRobotExportContext } from './models/autoid-export-format.model';
4
5
  import * as i0 from "@angular/core";
5
6
  type Segment = 'audit' | 'elements' | 'export';
7
+ type RobotContextField = keyof AutoidRobotExportContext;
6
8
  export declare class SdAutoidInspector implements OnDestroy {
7
9
  #private;
8
10
  enabled: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
9
- config: import("@angular/core").InputSignal<SdAutoidInspectorConfig | undefined>;
11
+ config: import("@angular/core").InputSignal<SdAutoidInspectorConfiguration | undefined>;
10
12
  open: import("@angular/core").WritableSignal<boolean>;
11
13
  segment: import("@angular/core").WritableSignal<Segment>;
12
14
  filter: import("@angular/core").WritableSignal<string>;
13
- elements: import("@angular/core").WritableSignal<SdAutoidElement[]>;
14
- audit: import("@angular/core").WritableSignal<SdAutoidAuditResult | null>;
15
+ elements: import("@angular/core").WritableSignal<AutoidElement[]>;
16
+ audit: import("@angular/core").WritableSignal<AutoidAuditResult | null>;
15
17
  copyOk: import("@angular/core").WritableSignal<boolean>;
18
+ e2eExporting: import("@angular/core").WritableSignal<AutoidE2eTarget | null>;
19
+ e2eExportOk: import("@angular/core").WritableSignal<string | null>;
20
+ e2eExportError: import("@angular/core").WritableSignal<string | null>;
21
+ robotContextOpen: import("@angular/core").WritableSignal<boolean>;
22
+ robotExportContext: import("@angular/core").WritableSignal<AutoidRobotExportContext>;
16
23
  highlightOn: import("@angular/core").WritableSignal<boolean>;
17
24
  dismissed: import("@angular/core").WritableSignal<boolean>;
18
- filteredElements: import("@angular/core").Signal<SdAutoidElement[]>;
25
+ readonly e2eGeneratorHost: import("@angular/core").Signal<string | undefined>;
26
+ readonly hasRobotExportContext: import("@angular/core").Signal<boolean>;
27
+ filteredElements: import("@angular/core").Signal<AutoidElement[]>;
19
28
  /**
20
29
  * Elements not inside any sd-table — rendered in the main "Top-level" section.
21
30
  */
22
- readonly topLevelElements: import("@angular/core").Signal<SdAutoidElement[]>;
31
+ readonly topLevelElements: import("@angular/core").Signal<AutoidElement[]>;
23
32
  /**
24
33
  * Map of `sd-table` autoid → its inner autoid elements. Tables themselves
25
34
  * stay in `topLevelElements` (the table's own autoid is top-level).
26
35
  */
27
36
  readonly tableGroups: import("@angular/core").Signal<{
28
37
  scope: string;
29
- items: SdAutoidElement[];
38
+ items: AutoidElement[];
30
39
  }[]>;
31
40
  readonly dataOpened: import("@angular/core").Signal<"true" | "false">;
32
41
  readonly dataHighlightOn: import("@angular/core").Signal<"true" | "false">;
@@ -48,6 +57,11 @@ export declare class SdAutoidInspector implements OnDestroy {
48
57
  exportJson: () => void;
49
58
  exportMdPom: () => void;
50
59
  exportMdTable: () => void;
60
+ openRobotExportContext: () => void;
61
+ closeRobotExportContext: () => void;
62
+ updateRobotExportContext: (field: RobotContextField, value: string) => void;
63
+ confirmRobotExport: () => Promise<void>;
64
+ exportE2eTest: (target: AutoidE2eTarget, context?: AutoidRobotExportContext) => Promise<boolean>;
51
65
  onEscape(): void;
52
66
  static ɵfac: i0.ɵɵFactoryDeclaration<SdAutoidInspector, never>;
53
67
  static ɵcmp: i0.ɵɵComponentDeclaration<SdAutoidInspector, "sd-autoid-inspector", never, { "enabled": { "alias": "enabled"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -3,14 +3,14 @@
3
3
  * Every field is OPTIONAL — only present when the component actually renders that attribute.
4
4
  * All values are the raw DOM string (already "true"/"false" or stringified number/value).
5
5
  */
6
- export interface SdAutoidElementState {
6
+ export interface AutoidElementState {
7
7
  disabled?: string;
8
8
  loading?: string;
9
9
  empty?: string;
10
10
  invalid?: string;
11
11
  opened?: string;
12
12
  count?: string;
13
- /** Serialized DOM `data-value` (NOT `input.value`). Distinct from `SdAutoidElement.text` field. */
13
+ /** Serialized DOM `data-value` (NOT `input.value`). Distinct from `AutoidElement.text` field. */
14
14
  dataValue?: string;
15
15
  required?: string;
16
16
  maxlength?: string;
@@ -21,7 +21,7 @@ export interface SdAutoidElementState {
21
21
  title?: string;
22
22
  message?: string;
23
23
  }
24
- export interface SdAutoidElement {
24
+ export interface AutoidElement {
25
25
  stt: number;
26
26
  name: string;
27
27
  autoid: string;
@@ -35,7 +35,7 @@ export interface SdAutoidElement {
35
35
  xpath: string;
36
36
  duplicate: boolean;
37
37
  /** Runtime state attributes read from the DOM. Always an object — may be empty `{}`. */
38
- state: SdAutoidElementState;
38
+ state: AutoidElementState;
39
39
  /**
40
40
  * `data-autoid` of the closest ancestor `<sd-table>` that contains this element,
41
41
  * or `undefined` if this element is top-level (not inside any `sd-table`).
@@ -51,16 +51,16 @@ export interface SdAutoidElement {
51
51
  /** Human-readable warning attached to a fallback element (only set when `missingAutoid`). */
52
52
  warning?: string;
53
53
  }
54
- export interface SdAutoidMissing {
54
+ export interface AutoidMissing {
55
55
  tag: string;
56
56
  selector: string;
57
57
  outerHtmlPreview: string;
58
58
  nameHint: string;
59
59
  }
60
- export interface SdAutoidAuditResult {
60
+ export interface AutoidAuditResult {
61
61
  total: number;
62
62
  duplicates: Record<string, number>;
63
63
  duplicateCount: number;
64
- missing: SdAutoidMissing[];
64
+ missing: AutoidMissing[];
65
65
  missingCount: number;
66
66
  }
@@ -1,6 +1,15 @@
1
- export type SdAutoidExportFormat = 'csv' | 'json' | 'md-pom' | 'md-table';
2
- export interface SdAutoidExportMeta {
3
- /** `location.pathname + location.search` — kept for back-compat with MD exports. */
1
+ export type AutoidE2eTarget = 'playwright' | 'robot';
2
+ export interface AutoidRobotExportContext {
3
+ requirement?: string;
4
+ testCases?: string;
5
+ testData?: string;
6
+ precondition?: string;
7
+ component?: string;
8
+ storyLinkages?: string;
9
+ qcNotes?: string;
10
+ }
11
+ export interface AutoidExportMeta {
12
+ /** `location.pathname + location.search`, kept for back-compat with MD exports. */
4
13
  pageUrl: string;
5
14
  pageTitle: string;
6
15
  timestamp: string;
@@ -10,16 +19,16 @@ export interface SdAutoidExportMeta {
10
19
  pathname: string;
11
20
  /** Raw `location.search` (incl. leading `?`), or `''`. */
12
21
  search: string;
13
- /** Parsed query string key/value map (last value wins on repeats). */
22
+ /** Parsed query string as key/value map (last value wins on repeats). */
14
23
  queryParams: Record<string, string>;
15
24
  /**
16
- * Angular route path params (`:id`, ) merged across the activated-route tree.
25
+ * Angular route path params (`:id`, etc.) merged across the activated-route tree.
17
26
  * Only present when an Angular `Router` is available at scan time; omitted otherwise.
18
27
  */
19
28
  params?: Record<string, string>;
20
29
  }
21
30
  /** JSON export envelope: page meta + the scanned elements. */
22
- export interface SdAutoidExportJson {
23
- meta: SdAutoidExportMeta;
24
- elements: import('./autoid-element.model').SdAutoidElement[];
31
+ export interface AutoidExportJson {
32
+ meta: AutoidExportMeta;
33
+ elements: import('./autoid-element.model').AutoidElement[];
25
34
  }
@@ -1,8 +1,13 @@
1
- export interface SdAutoidInspectorConfig {
2
- /** Selector phụ thêm cần audit (mặc định component đã cover sd-* form + sd-button). */
1
+ import { InjectionToken } from '@angular/core';
2
+ export interface SdAutoidInspectorConfiguration {
3
+ /** Base URL cua backend sinh E2E test, vi du `http://localhost:3012`. */
4
+ host?: string;
5
+ /** Selector phu them can audit (mac dinh component da cover sd-* form + sd-button). */
3
6
  extraRequireSelectors?: string[];
4
- /** Root scan, mặc định document.body. */
7
+ /** Root scan, mac dinh document.body. */
5
8
  root?: HTMLElement;
6
9
  }
7
- /** Selector mặc định coi phải data-autoid. */
8
- export declare const SD_AUTOID_DEFAULT_REQUIRE_SELECTORS: ReadonlyArray<string>;
10
+ /** Cau hinh global cho AutoId Inspector. `[config]` tren component co the override theo instance. */
11
+ export declare const SD_AUTOID_INSPECTOR_CONFIGURATION: InjectionToken<SdAutoidInspectorConfiguration>;
12
+ /** Selector mac dinh coi la phai co data-autoid. */
13
+ export declare const AUTOID_DEFAULT_REQUIRE_SELECTORS: readonly string[];
@@ -1,4 +1,4 @@
1
- import { SdAutoidElement, SdAutoidAuditResult } from '../models/autoid-element.model';
1
+ import { AutoidElement, AutoidAuditResult } from '../models/autoid-element.model';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SdAutoidAuditService {
4
4
  /**
@@ -6,10 +6,10 @@ export declare class SdAutoidAuditService {
6
6
  * - duplicates: map autoid → count khi count > 1
7
7
  * - missing: element khớp selector yêu cầu nhưng KHÔNG có [data-autoid]
8
8
  */
9
- audit(elements: SdAutoidElement[], options?: {
10
- requireSelectors?: ReadonlyArray<string>;
9
+ audit(elements: AutoidElement[], options?: {
10
+ requireSelectors?: readonly string[];
11
11
  root?: HTMLElement;
12
- }): SdAutoidAuditResult;
12
+ }): AutoidAuditResult;
13
13
  private findMissing;
14
14
  private buildSelectorPath;
15
15
  private shortHtml;
@@ -1,20 +1,21 @@
1
- import { SdAutoidElement } from '../models/autoid-element.model';
2
- import { SdAutoidExportMeta } from '../models/autoid-export-format.model';
1
+ import { AutoidElement } from '../models/autoid-element.model';
2
+ import { AutoidExportMeta } from '../models/autoid-export-format.model';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class SdAutoidExportService {
5
5
  /**
6
6
  * Có `meta` → bọc `{ meta, elements }` (kèm url/queryParams) để consumer biết trang/route.
7
7
  * Không `meta` → giữ mảng thuần (back-compat cho caller cũ chỉ cần elements).
8
8
  */
9
- toJson(elements: SdAutoidElement[], meta?: SdAutoidExportMeta): string;
9
+ toJson(elements: AutoidElement[], meta?: AutoidExportMeta): string;
10
10
  /** Parse a `location.search` string into a flat key/value map (last value wins). */
11
11
  parseQueryParams(search: string): Record<string, string>;
12
- toCsv(elements: SdAutoidElement[]): string;
12
+ toCsv(elements: AutoidElement[]): string;
13
13
  /** POM TypeScript skeleton — copy ngay vào file Playwright/Cypress. */
14
- toMarkdownPom(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
14
+ toMarkdownPom(elements: AutoidElement[], meta: AutoidExportMeta): string;
15
15
  /** Markdown reference table, group FIRST by tableScope (top-level first, then per table), then by tag. */
16
- toMarkdownTable(elements: SdAutoidElement[], meta: SdAutoidExportMeta): string;
16
+ toMarkdownTable(elements: AutoidElement[], meta: AutoidExportMeta): string;
17
17
  download(content: string, filename: string, mime: string): void;
18
+ downloadBlob(blob: Blob, filename: string): void;
18
19
  copyToClipboard(content: string): Promise<void>;
19
20
  /** Build a compact state summary string from defined state keys, e.g. "disabled=false; empty=true". */
20
21
  private buildStateSummary;
@@ -1,4 +1,4 @@
1
- import { SdAutoidElement } from '../models/autoid-element.model';
1
+ import { AutoidElement } from '../models/autoid-element.model';
2
2
  import * as i0 from "@angular/core";
3
3
  export declare class SdAutoidScannerService {
4
4
  /**
@@ -8,7 +8,7 @@ export declare class SdAutoidScannerService {
8
8
  * (`autoid: ''`, xpath theo vị trí thẻ + cờ `missingAutoid` + warning) — để JSON xuất ra
9
9
  * vẫn dùng được và dev biết chỗ cần bổ sung autoid.
10
10
  */
11
- scan(root?: HTMLElement, requireSelectors?: ReadonlyArray<string>): SdAutoidElement[];
11
+ scan(root?: HTMLElement, requireSelectors?: readonly string[]): AutoidElement[];
12
12
  /**
13
13
  * Tìm các node khớp `requireSelectors` nhưng thiếu data-autoid (self + mọi descendant),
14
14
  * thêm vào `result` dưới dạng phần tử fallback. Trả về `stt` kế tiếp.
@@ -17,7 +17,7 @@ export declare class SdAutoidScannerService {
17
17
  /** XPath theo vị trí thẻ trong document, vd `(//sd-button)[2]`, khi không có autoid. */
18
18
  private fallbackXpath;
19
19
  /** Group element theo autoid để consumer lấy duplicate map. */
20
- groupByAutoid(elements: SdAutoidElement[]): Record<string, SdAutoidElement[]>;
20
+ groupByAutoid(elements: AutoidElement[]): Record<string, AutoidElement[]>;
21
21
  /**
22
22
  * Read the optional `data-*` E2E state attributes off the same node.
23
23
  * Only includes fields actually present on the DOM (skipped fields stay undefined).
@@ -10,6 +10,7 @@ export * from '@sdcorejs/angular/components/quick-action';
10
10
  export * from '@sdcorejs/angular/components/query-bar';
11
11
  export * from '@sdcorejs/angular/components/upload-file';
12
12
  export * from '@sdcorejs/angular/components/section';
13
+ export * from '@sdcorejs/angular/components/inform';
13
14
  export * from '@sdcorejs/angular/components/anchor';
14
15
  export * from '@sdcorejs/angular/components/query-builder';
15
16
  export * from '@sdcorejs/angular/components/org-chart';
@@ -73,10 +73,13 @@ export declare class SdUploadFile<TArgs = any> {
73
73
  preview: () => Promise<void>;
74
74
  /**
75
75
  * Tải xuống một tệp tin dựa trên đối tượng PreviewFile.
76
- * * Ưu tiên:
77
- * 1. Tải xuống từ thuộc tính `file`.
78
- * 2. Tải xuống từ thuộc tính `src`.
79
- * 3. Gọi hàm download dựa vào `idOrKey`.
76
+ *
77
+ * Ưu tiên:
78
+ * 1. Nếu consumer implement hàm download (input `download` hoặc configuration) VÀ file có
79
+ * `idOrKey` (file đã lưu trên server) → LUÔN gọi hàm download. KHÔNG mở `src` (URL lấy từ detail).
80
+ * Dùng cho trường hợp tải file qua API có xác thực thay vì truy cập trực tiếp URL.
81
+ * 2. Ngược lại (không có hàm download, hoặc file local chưa upload nên chưa có `idOrKey`) →
82
+ * tải trực tiếp từ `file` (blob) hoặc `src` (URL).
80
83
  *
81
84
  * @param previewFile Đối tượng PreviewFile chứa thông tin tệp tin.
82
85
  */
@@ -2,8 +2,7 @@ import * as i1$1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { input, inject, ElementRef, effect, Component, computed, output, ChangeDetectionStrategy, viewChild, contentChildren, booleanAttribute, signal, afterNextRender, untracked } from '@angular/core';
5
- import { v4 } from 'uuid';
6
- import { BrowserUtilities } from '@sdcorejs/utils/fns';
5
+ import { Utilities, BrowserUtilities } from '@sdcorejs/utils/fns';
7
6
  import { Subject, Subscription, debounceTime, fromEvent, take } from 'rxjs';
8
7
  import * as i1 from '@angular/material/icon';
9
8
  import { MatIconModule } from '@angular/material/icon';
@@ -13,7 +12,7 @@ class SdAnchorItem {
13
12
  icon = input();
14
13
  // Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).
15
14
  key = input(undefined);
16
- id = v4();
15
+ id = Utilities.generateUuid();
17
16
  elementRef = inject(ElementRef);
18
17
  constructor() {
19
18
  effect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"sdcorejs-angular-components-anchor.mjs","sources":["../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.html","../../../projects/sdcorejs-angular/components/anchor/sdcorejs-angular-components-anchor.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, ElementRef, effect, inject, input } from '@angular/core';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IAnchorItem } from '../../models';\n\n@Component({\n selector: 'sd-anchor-item',\n templateUrl: './anchor-item.component.html',\n styleUrls: ['./anchor-item.component.scss'],\n imports: [CommonModule],\n standalone: true,\n})\nexport class SdAnchorItem implements IAnchorItem {\n title = input.required<string>();\n icon = input<string | undefined>();\n // Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).\n key = input<string | undefined>(undefined);\n id: string = uuidv4();\n elementRef = inject(ElementRef);\n\n constructor() {\n effect(() => {\n if (this.title()) {\n this.elementRef.nativeElement.removeAttribute('title');\n }\n });\n }\n}\n","<section>\n <ng-content></ng-content>\n</section>\n","import { ChangeDetectionStrategy, Component, OnDestroy, computed, input, output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatIconModule } from '@angular/material/icon';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'anchor-nav',\n templateUrl: './anchor-nav.component.html',\n styleUrl: './anchor-nav.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, MatIconModule],\n standalone: true,\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class AnchorNav implements OnDestroy {\n sections = input.required<readonly SdAnchorItem[]>();\n activeSectionId = input<string>('');\n ellipsis = input<boolean>(false);\n sidebarWidth = input<string>('');\n // autoId được forward từ <sd-anchor>. Derive per-item autoId theo `key` của item (nếu có).\n parentAutoId = input<string | undefined | null>(undefined);\n color = input<Color>('primary');\n\n // CSS var binding cho active state — map SdColor → global token `--sd-{color}`.\n // SCSS đọc qua `var(--anchor-active-color)` cho border + text + icon.\n cssActiveVar = computed(() => `var(--sd-${this.color()})`);\n\n itemAutoId(section: SdAnchorItem): string | undefined {\n const parent = this.parentAutoId();\n const key = section.key();\n return parent && key ? `${parent}-${key}` : undefined;\n }\n\n clickSection = output<string>();\n\n #delay = 200;\n #clickSectionSubject = new Subject<string>();\n #subscription = new Subscription();\n\n constructor() {\n this.#subscription.add(\n this.#clickSectionSubject\n .pipe(debounceTime(this.#delay))\n .subscribe((id: string) => this.clickSection.emit(id))\n );\n }\n\n onClickSection = (id: string): void => {\n this.#clickSectionSubject.next(id);\n };\n\n ngOnDestroy(): void {\n this.#subscription.unsubscribe();\n }\n}\n","<div\n class=\"c-anchor-list\"\n [style.width]=\"sidebarWidth()\"\n [style.--anchor-active-color]=\"cssActiveVar()\">\n @for (section of sections(); track section.id) {\n <div\n class=\"c-anchor-list-item\"\n [class.active]=\"section.id === activeSectionId()\"\n (click)=\"onClickSection(section.id)\"\n (keydown.enter)=\"onClickSection(section.id)\"\n [attr.data-autoId]=\"itemAutoId(section)\"\n tabindex=\"0\">\n @if (section.icon()) {\n <mat-icon class=\"c-anchor-list-item-icon\">{{ section.icon() }}</mat-icon>\n }\n <div class=\"c-anchor-list-item-text\" [class.ellipsis]=\"ellipsis()\">\n {{ section.title() }}\n </div>\n </div>\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChildren,\n effect,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BrowserUtilities } from '@sdcorejs/utils/fns';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subscription, fromEvent, take } from 'rxjs';\nimport { AnchorNav } from '../anchor-nav/anchor-nav.component';\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'sd-anchor',\n templateUrl: './anchor.component.html',\n styleUrls: ['./anchor.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, AnchorNav],\n standalone: true,\n})\nexport class SdAnchor implements OnDestroy {\n wrapper = viewChild.required<ElementRef>('wrapper');\n sections = contentChildren(SdAnchorItem);\n\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly autoId = computed(() => (this.autoIdInput() ? `components-anchor-${this.autoIdInput()}` : undefined));\n\n sidebarWidth = input<string>('200px');\n ellipsis = input(false, { transform: booleanAttribute });\n overScroll = input(false, { transform: booleanAttribute });\n // Mobile: default ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).\n // Consumer truyền `[hideNav]=\"false\"` để force hiện trên mobile.\n hideNav = input(BrowserUtilities.isMobile(), { transform: booleanAttribute });\n // Màu highlight active nav (text + icon + vertical bar). Default 'primary'.\n color = input<Color>('primary');\n\n activeSectionId = signal<string>('');\n\n #initialized = false;\n #isClickScrolling = false;\n #clickScrollSubscription: Subscription | null = null;\n #intersectionObserver: IntersectionObserver | null = null;\n #visibleSections = new Set<Element>();\n #timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n #timeoutScrollFallback = 200;\n\n constructor() {\n afterNextRender(() => {\n this.#initialized = true;\n if (!this.hideNav()) {\n this.#registerIntersectionObserver();\n }\n });\n\n // Lắng nghe thay đổi sections để đăng ký lại observe section\n effect(() => {\n this.sections();\n if (!this.hideNav() && this.#initialized) {\n untracked(() => this.#registerIntersectionObserver());\n }\n });\n }\n\n #registerIntersectionObserver(): void {\n this.#cleanIntersectionObserver();\n const wrapperEl = this.wrapper().nativeElement;\n\n // Brower API IntersectionObserver sẽ hỗ trợ khi nào 1 section được hiện ra trong wrapperEl\n this.#intersectionObserver = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n // Nếu section mới đi vào vùng nhìn thấy -> add vào set\n this.#visibleSections.add(entry.target);\n } else {\n // Nếu section đã đi ra khỏi vùng nhìn thấy -> xóa khỏi Set\n this.#visibleSections.delete(entry.target);\n }\n }\n\n // Nếu đang scroll bởi click section thì return luôn, k phải quét qua tìm vùng section được active\n if (this.#isClickScrolling) {\n return;\n }\n\n for (const section of this.sections()) {\n // Kiểm tra xem DOM của section nào đang nằm trong danh sách đang nhìn thấy để active chính xác\n if (this.#visibleSections.has(section.elementRef.nativeElement)) {\n if (this.activeSectionId() !== section.id) {\n this.activeSectionId.set(section.id);\n }\n break;\n }\n }\n },\n { root: wrapperEl, threshold: 0 }\n );\n\n // Đăng ký theo dõi từng section có trong anchor\n for (const section of this.sections()) {\n this.#intersectionObserver.observe(section.elementRef.nativeElement);\n }\n }\n\n scrollSectionByClick(idSectionTarget: string): void {\n this.activeSectionId.set(idSectionTarget);\n const targetSection = this.sections().find(s => s.id === idSectionTarget)?.elementRef;\n if (!targetSection) {\n return;\n }\n this.#cleanScrollSectionByClickObserver();\n this.#isClickScrolling = true;\n\n const wrapperEl = this.wrapper().nativeElement;\n const targetElement = targetSection.nativeElement;\n\n const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container\n const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới\n\n // Đăng ký sự kiện nếu đã được scroll xong\n this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')\n .pipe(take(1))\n .subscribe(() => {\n this.#isClickScrolling = false;\n });\n\n // Nếu sectionTarget đã ở đúng vị trí (click nhưng không scroll) thì sau #timeoutScrollFallback kích hoạt lại IntersectionObserver\n this.#timeoutId = setTimeout(() => {\n if (wrapperEl.scrollTop === prevScrollTop) {\n this.#isClickScrolling = false;\n this.#clickScrollSubscription?.unsubscribe();\n }\n }, this.#timeoutScrollFallback);\n\n wrapperEl.scrollTo({ top: scrollTop, behavior: 'smooth' });\n }\n\n #cleanScrollSectionByClickObserver = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId);\n }\n this.#clickScrollSubscription?.unsubscribe();\n };\n\n #cleanIntersectionObserver = (): void => {\n this.#intersectionObserver?.disconnect();\n this.#visibleSections.clear();\n };\n\n ngOnDestroy(): void {\n this.#cleanScrollSectionByClickObserver();\n this.#cleanIntersectionObserver();\n }\n}\n","<div class=\"c-anchor-vertical\" [ngClass]=\"{ 'c-stop-scroll-propagation': !overScroll() }\" #wrapper>\n <div class=\"c-anchor-content\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideNav()) {\n <div class=\"c-anchor-list\" [style.flex-basis]=\"sidebarWidth()\">\n <anchor-nav\n [sections]=\"sections()\"\n [ellipsis]=\"ellipsis()\"\n [sidebarWidth]=\"sidebarWidth()\"\n [activeSectionId]=\"activeSectionId()\"\n [parentAutoId]=\"autoId()\"\n [color]=\"color()\"\n (clickSection)=\"scrollSectionByClick($event)\">\n </anchor-nav>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["uuidv4"],"mappings":"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"}
1
+ {"version":3,"file":"sdcorejs-angular-components-anchor.mjs","sources":["../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-item/anchor-item.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor-nav/anchor-nav.component.html","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.ts","../../../projects/sdcorejs-angular/components/anchor/src/components/anchor/anchor.component.html","../../../projects/sdcorejs-angular/components/anchor/sdcorejs-angular-components-anchor.ts"],"sourcesContent":["import { CommonModule } from '@angular/common';\nimport { Component, ElementRef, effect, inject, input } from '@angular/core';\nimport { IAnchorItem } from '../../models';\nimport { Utilities } from '@sdcorejs/utils/fns';\n\n@Component({\n selector: 'sd-anchor-item',\n templateUrl: './anchor-item.component.html',\n styleUrls: ['./anchor-item.component.scss'],\n imports: [CommonModule],\n standalone: true,\n})\nexport class SdAnchorItem implements IAnchorItem {\n title = input.required<string>();\n icon = input<string | undefined>();\n // Stable key dùng cho data-autoId. Nếu không truyền thì fallback về uuid (không stable giữa các lần render).\n key = input<string | undefined>(undefined);\n id: string = Utilities.generateUuid();\n elementRef = inject(ElementRef);\n\n constructor() {\n effect(() => {\n if (this.title()) {\n this.elementRef.nativeElement.removeAttribute('title');\n }\n });\n }\n}\n","<section>\n <ng-content></ng-content>\n</section>\n","import { ChangeDetectionStrategy, Component, OnDestroy, computed, input, output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatIconModule } from '@angular/material/icon';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subject, Subscription, debounceTime } from 'rxjs';\n\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'anchor-nav',\n templateUrl: './anchor-nav.component.html',\n styleUrl: './anchor-nav.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, MatIconModule],\n standalone: true,\n})\n// eslint-disable-next-line @angular-eslint/component-class-suffix\nexport class AnchorNav implements OnDestroy {\n sections = input.required<readonly SdAnchorItem[]>();\n activeSectionId = input<string>('');\n ellipsis = input<boolean>(false);\n sidebarWidth = input<string>('');\n // autoId được forward từ <sd-anchor>. Derive per-item autoId theo `key` của item (nếu có).\n parentAutoId = input<string | undefined | null>(undefined);\n color = input<Color>('primary');\n\n // CSS var binding cho active state — map SdColor → global token `--sd-{color}`.\n // SCSS đọc qua `var(--anchor-active-color)` cho border + text + icon.\n cssActiveVar = computed(() => `var(--sd-${this.color()})`);\n\n itemAutoId(section: SdAnchorItem): string | undefined {\n const parent = this.parentAutoId();\n const key = section.key();\n return parent && key ? `${parent}-${key}` : undefined;\n }\n\n clickSection = output<string>();\n\n #delay = 200;\n #clickSectionSubject = new Subject<string>();\n #subscription = new Subscription();\n\n constructor() {\n this.#subscription.add(\n this.#clickSectionSubject\n .pipe(debounceTime(this.#delay))\n .subscribe((id: string) => this.clickSection.emit(id))\n );\n }\n\n onClickSection = (id: string): void => {\n this.#clickSectionSubject.next(id);\n };\n\n ngOnDestroy(): void {\n this.#subscription.unsubscribe();\n }\n}\n","<div\n class=\"c-anchor-list\"\n [style.width]=\"sidebarWidth()\"\n [style.--anchor-active-color]=\"cssActiveVar()\">\n @for (section of sections(); track section.id) {\n <div\n class=\"c-anchor-list-item\"\n [class.active]=\"section.id === activeSectionId()\"\n (click)=\"onClickSection(section.id)\"\n (keydown.enter)=\"onClickSection(section.id)\"\n [attr.data-autoId]=\"itemAutoId(section)\"\n tabindex=\"0\">\n @if (section.icon()) {\n <mat-icon class=\"c-anchor-list-item-icon\">{{ section.icon() }}</mat-icon>\n }\n <div class=\"c-anchor-list-item-text\" [class.ellipsis]=\"ellipsis()\">\n {{ section.title() }}\n </div>\n </div>\n }\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n OnDestroy,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChildren,\n effect,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BrowserUtilities } from '@sdcorejs/utils/fns';\nimport { Color } from '@sdcorejs/utils/models';\nimport { Subscription, fromEvent, take } from 'rxjs';\nimport { AnchorNav } from '../anchor-nav/anchor-nav.component';\nimport { SdAnchorItem } from '../anchor-item/anchor-item.component';\n\n@Component({\n selector: 'sd-anchor',\n templateUrl: './anchor.component.html',\n styleUrls: ['./anchor.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [CommonModule, AnchorNav],\n standalone: true,\n})\nexport class SdAnchor implements OnDestroy {\n wrapper = viewChild.required<ElementRef>('wrapper');\n sections = contentChildren(SdAnchorItem);\n\n readonly autoIdInput = input<string | undefined | null>(undefined, { alias: 'autoId' });\n readonly autoId = computed(() => (this.autoIdInput() ? `components-anchor-${this.autoIdInput()}` : undefined));\n\n sidebarWidth = input<string>('200px');\n ellipsis = input(false, { transform: booleanAttribute });\n overScroll = input(false, { transform: booleanAttribute });\n // Mobile: default ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).\n // Consumer truyền `[hideNav]=\"false\"` để force hiện trên mobile.\n hideNav = input(BrowserUtilities.isMobile(), { transform: booleanAttribute });\n // Màu highlight active nav (text + icon + vertical bar). Default 'primary'.\n color = input<Color>('primary');\n\n activeSectionId = signal<string>('');\n\n #initialized = false;\n #isClickScrolling = false;\n #clickScrollSubscription: Subscription | null = null;\n #intersectionObserver: IntersectionObserver | null = null;\n #visibleSections = new Set<Element>();\n #timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n #timeoutScrollFallback = 200;\n\n constructor() {\n afterNextRender(() => {\n this.#initialized = true;\n if (!this.hideNav()) {\n this.#registerIntersectionObserver();\n }\n });\n\n // Lắng nghe thay đổi sections để đăng ký lại observe section\n effect(() => {\n this.sections();\n if (!this.hideNav() && this.#initialized) {\n untracked(() => this.#registerIntersectionObserver());\n }\n });\n }\n\n #registerIntersectionObserver(): void {\n this.#cleanIntersectionObserver();\n const wrapperEl = this.wrapper().nativeElement;\n\n // Brower API IntersectionObserver sẽ hỗ trợ khi nào 1 section được hiện ra trong wrapperEl\n this.#intersectionObserver = new IntersectionObserver(\n entries => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n // Nếu section mới đi vào vùng nhìn thấy -> add vào set\n this.#visibleSections.add(entry.target);\n } else {\n // Nếu section đã đi ra khỏi vùng nhìn thấy -> xóa khỏi Set\n this.#visibleSections.delete(entry.target);\n }\n }\n\n // Nếu đang scroll bởi click section thì return luôn, k phải quét qua tìm vùng section được active\n if (this.#isClickScrolling) {\n return;\n }\n\n for (const section of this.sections()) {\n // Kiểm tra xem DOM của section nào đang nằm trong danh sách đang nhìn thấy để active chính xác\n if (this.#visibleSections.has(section.elementRef.nativeElement)) {\n if (this.activeSectionId() !== section.id) {\n this.activeSectionId.set(section.id);\n }\n break;\n }\n }\n },\n { root: wrapperEl, threshold: 0 }\n );\n\n // Đăng ký theo dõi từng section có trong anchor\n for (const section of this.sections()) {\n this.#intersectionObserver.observe(section.elementRef.nativeElement);\n }\n }\n\n scrollSectionByClick(idSectionTarget: string): void {\n this.activeSectionId.set(idSectionTarget);\n const targetSection = this.sections().find(s => s.id === idSectionTarget)?.elementRef;\n if (!targetSection) {\n return;\n }\n this.#cleanScrollSectionByClickObserver();\n this.#isClickScrolling = true;\n\n const wrapperEl = this.wrapper().nativeElement;\n const targetElement = targetSection.nativeElement;\n\n const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container\n const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới\n\n // Đăng ký sự kiện nếu đã được scroll xong\n this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')\n .pipe(take(1))\n .subscribe(() => {\n this.#isClickScrolling = false;\n });\n\n // Nếu sectionTarget đã ở đúng vị trí (click nhưng không scroll) thì sau #timeoutScrollFallback kích hoạt lại IntersectionObserver\n this.#timeoutId = setTimeout(() => {\n if (wrapperEl.scrollTop === prevScrollTop) {\n this.#isClickScrolling = false;\n this.#clickScrollSubscription?.unsubscribe();\n }\n }, this.#timeoutScrollFallback);\n\n wrapperEl.scrollTo({ top: scrollTop, behavior: 'smooth' });\n }\n\n #cleanScrollSectionByClickObserver = (): void => {\n if (this.#timeoutId) {\n clearTimeout(this.#timeoutId);\n }\n this.#clickScrollSubscription?.unsubscribe();\n };\n\n #cleanIntersectionObserver = (): void => {\n this.#intersectionObserver?.disconnect();\n this.#visibleSections.clear();\n };\n\n ngOnDestroy(): void {\n this.#cleanScrollSectionByClickObserver();\n this.#cleanIntersectionObserver();\n }\n}\n","<div class=\"c-anchor-vertical\" [ngClass]=\"{ 'c-stop-scroll-propagation': !overScroll() }\" #wrapper>\n <div class=\"c-anchor-content\">\n <ng-content></ng-content>\n </div>\n\n @if (!hideNav()) {\n <div class=\"c-anchor-list\" [style.flex-basis]=\"sidebarWidth()\">\n <anchor-nav\n [sections]=\"sections()\"\n [ellipsis]=\"ellipsis()\"\n [sidebarWidth]=\"sidebarWidth()\"\n [activeSectionId]=\"activeSectionId()\"\n [parentAutoId]=\"autoId()\"\n [color]=\"color()\"\n (clickSection)=\"scrollSectionByClick($event)\">\n </anchor-nav>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}