@sdcorejs/angular 20.0.8 → 20.0.10

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 (149) hide show
  1. package/README.md +270 -140
  2. package/assets/scss/core/utilities/_grid.scss +25 -19
  3. package/components/document-builder/index.d.ts +2 -2
  4. package/components/form-generic/index.d.ts +45 -23
  5. package/components/import-excel/index.d.ts +2 -2
  6. package/components/mini-editor/index.d.ts +4 -4
  7. package/components/modal/index.d.ts +1 -1
  8. package/components/query-builder/index.d.ts +4 -4
  9. package/components/tab-router/index.d.ts +3 -3
  10. package/components/table/index.d.ts +8 -11
  11. package/components/view/index.d.ts +1 -1
  12. package/fesm2022/sdcorejs-angular-components-anchor.mjs +15 -18
  13. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  14. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  15. package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -1
  16. package/fesm2022/sdcorejs-angular-components-badge.mjs +0 -1
  17. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  18. package/fesm2022/sdcorejs-angular-components-button.mjs +11 -12
  19. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  20. package/fesm2022/sdcorejs-angular-components-chart.mjs.map +1 -1
  21. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
  22. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +1 -1
  23. package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
  24. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +17 -26
  25. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-editor.mjs +7 -2
  27. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  28. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +712 -427
  29. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  30. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +35 -18
  31. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-inform.mjs +0 -1
  33. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
  35. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-modal.mjs +25 -14
  37. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-operator.mjs +1 -1
  39. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
  41. package/fesm2022/sdcorejs-angular-components-preview.mjs +33 -29
  42. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  43. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +15 -28
  44. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  45. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +2 -3
  46. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  47. package/fesm2022/sdcorejs-angular-components-quick-action.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-section.mjs +0 -1
  49. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +3 -3
  51. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-splitter.mjs +5 -5
  53. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  55. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +31 -31
  56. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  57. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-components-table.mjs +800 -855
  59. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  61. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +6 -6
  62. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  63. package/fesm2022/sdcorejs-angular-components-view.mjs +3 -9
  64. package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -1
  65. package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-directives.mjs +2 -7
  67. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +0 -3
  69. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  71. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +2 -2
  72. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  73. package/fesm2022/sdcorejs-angular-forms-chip.mjs +2 -2
  74. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  75. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +11 -5
  76. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  77. package/fesm2022/sdcorejs-angular-forms-date.mjs +2 -4
  78. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  79. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +2 -6
  80. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  81. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +4 -4
  82. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  83. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +1 -1
  84. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  85. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  86. package/fesm2022/sdcorejs-angular-forms-label.mjs +0 -1
  87. package/fesm2022/sdcorejs-angular-forms-label.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  89. package/fesm2022/sdcorejs-angular-forms-radio.mjs +12 -2
  90. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  91. package/fesm2022/sdcorejs-angular-forms-select.mjs +45 -14
  92. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  93. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  94. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +3 -3
  95. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  96. package/fesm2022/sdcorejs-angular-handlers.mjs +3 -6
  97. package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
  98. package/fesm2022/sdcorejs-angular-i18n.mjs +11 -7
  99. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  100. package/fesm2022/sdcorejs-angular-interceptors.mjs +0 -2
  101. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  102. package/fesm2022/sdcorejs-angular-modules-auth.mjs +14 -38
  103. package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
  104. package/fesm2022/sdcorejs-angular-modules-authom.mjs +14 -14
  105. package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +1 -1
  106. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +22 -11
  107. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
  108. package/fesm2022/sdcorejs-angular-modules-layout.mjs +30 -27
  109. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  110. package/fesm2022/sdcorejs-angular-modules-permission.mjs +5 -12
  111. package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
  112. package/fesm2022/sdcorejs-angular-pipes.mjs +71 -17
  113. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  114. package/fesm2022/sdcorejs-angular-services-api.mjs +0 -2
  115. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  116. package/fesm2022/sdcorejs-angular-services-cache.mjs +5 -11
  117. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  118. package/fesm2022/sdcorejs-angular-services-confirm.mjs +16 -21
  119. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  120. package/fesm2022/sdcorejs-angular-services-docx.mjs +2 -8
  121. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
  122. package/fesm2022/sdcorejs-angular-services-excel.mjs +2 -2
  123. package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
  124. package/fesm2022/sdcorejs-angular-services-license.mjs +5 -12
  125. package/fesm2022/sdcorejs-angular-services-license.mjs.map +1 -1
  126. package/fesm2022/sdcorejs-angular-services-notify.mjs +70 -87
  127. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  128. package/fesm2022/sdcorejs-angular-services-storage.mjs +6 -15
  129. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  130. package/fesm2022/sdcorejs-angular-utilities-data-state.mjs.map +1 -1
  131. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +47 -5
  132. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
  133. package/fesm2022/sdcorejs-angular-utilities-models.mjs +18 -3
  134. package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
  135. package/fesm2022/sdcorejs-angular.mjs.map +1 -1
  136. package/forms/chip/index.d.ts +2 -2
  137. package/forms/chip-calendar/index.d.ts +2 -2
  138. package/forms/date-range/index.d.ts +2 -0
  139. package/forms/input-color/index.d.ts +2 -1
  140. package/forms/select/index.d.ts +10 -2
  141. package/modules/auth/index.d.ts +7 -9
  142. package/modules/permission/index.d.ts +5 -6
  143. package/package.json +2 -2
  144. package/pipes/index.d.ts +22 -4
  145. package/services/confirm/index.d.ts +3 -3
  146. package/services/license/index.d.ts +2 -3
  147. package/services/notify/index.d.ts +4 -5
  148. package/services/storage/index.d.ts +2 -3
  149. package/utilities/extensions/index.d.ts +9 -1
@@ -1,11 +1,13 @@
1
+ @use "sass:math";
2
+
1
3
  // --------------------------------------------------------------------------
2
- // Grid row/col 12-column flexbox + native CSS Grid container
3
- // Thuần CSS Flexbox / CSS Grid, không phụ thuộc framework ngoài.
4
- // Breakpoint convention (sm/md/lg/xl) trùng Bootstrap để host app dễ migrate.
4
+ // Grid - row/col 12-column flexbox + native CSS Grid container
5
+ // Pure CSS Flexbox / CSS Grid, with no external framework dependency.
6
+ // Breakpoint convention (sm/md/lg/xl) matches Bootstrap to ease host migration.
5
7
  // --------------------------------------------------------------------------
6
8
 
7
9
  // --------------------------------------------------------------------------
8
- // 1. Flexbox row/col (.row, .col-{1-12})
10
+ // 1. Flexbox row/col (.row, .col-{1-12})
9
11
  // --------------------------------------------------------------------------
10
12
  $grid-columns: 12;
11
13
  $grid-gutter: 16px;
@@ -45,13 +47,15 @@ $grid-gutter: 16px;
45
47
  > * { padding-left: 2px; padding-right: 2px; }
46
48
  }
47
49
 
48
- // .col-1 .col-12
50
+ // .col-1 ... .col-12
49
51
  @for $i from 1 through $grid-columns {
52
+ $col-size: math.percentage(math.div($i, $grid-columns));
53
+
50
54
  .col-#{$i} {
51
55
  box-sizing: border-box;
52
- width: percentage(calc($i / $grid-columns));
53
- flex: 0 0 percentage(calc($i / $grid-columns));
54
- max-width: percentage(calc($i / $grid-columns));
56
+ width: $col-size;
57
+ flex: 0 0 $col-size;
58
+ max-width: $col-size;
55
59
  padding-left: calc($grid-gutter / 2);
56
60
  padding-right: calc($grid-gutter / 2);
57
61
  }
@@ -65,12 +69,12 @@ $grid-gutter: 16px;
65
69
 
66
70
  // --------------------------------------------------------------------------
67
71
  // 1b. Responsive columns
68
- // col-sm-{1-12} : 576px
69
- // col-md-{1-12} : 768px
70
- // col-lg-{1-12} : 992px
71
- // col-xl-{1-12} : 1200px
72
+ // col-sm-{1-12}: >= 576px
73
+ // col-md-{1-12}: >= 768px
74
+ // col-lg-{1-12}: >= 992px
75
+ // col-xl-{1-12}: >= 1200px
72
76
  //
73
- // Mobile-first: mặc định width: 100%, áp dụng kích thước khi đủ rộng.
77
+ // Mobile-first: default width is 100%; column size applies from breakpoint up.
74
78
  // --------------------------------------------------------------------------
75
79
  $grid-breakpoints: (
76
80
  'sm': 576px,
@@ -79,7 +83,7 @@ $grid-breakpoints: (
79
83
  'xl': 1200px,
80
84
  );
81
85
 
82
- // col-{bp} chiếm hết chiều rộng tại breakpoint đó
86
+ // col-{bp} - full-width flexible column at the breakpoint
83
87
  @each $bp, $min-width in $grid-breakpoints {
84
88
  @media (min-width: $min-width) {
85
89
  .col-#{$bp} {
@@ -90,15 +94,17 @@ $grid-breakpoints: (
90
94
  }
91
95
  }
92
96
 
93
- // col-{bp}-{1-12} chiếm n/12 chiều rộng tại breakpoint đó
97
+ // col-{bp}-{1-12} - n/12 column width at the breakpoint
94
98
  @each $bp, $min-width in $grid-breakpoints {
95
99
  @media (min-width: $min-width) {
96
100
  @for $i from 1 through $grid-columns {
101
+ $col-size: math.percentage(math.div($i, $grid-columns));
102
+
97
103
  .col-#{$bp}-#{$i} {
98
104
  box-sizing: border-box;
99
- width: percentage(calc($i / $grid-columns));
100
- flex: 0 0 percentage(calc($i / $grid-columns));
101
- max-width: percentage(calc($i / $grid-columns));
105
+ width: $col-size;
106
+ flex: 0 0 $col-size;
107
+ max-width: $col-size;
102
108
  padding-left: calc($grid-gutter / 2);
103
109
  padding-right: calc($grid-gutter / 2);
104
110
  }
@@ -107,7 +113,7 @@ $grid-breakpoints: (
107
113
  }
108
114
 
109
115
  // --------------------------------------------------------------------------
110
- // 2. CSS Grid container (.grid-container)
116
+ // 2. CSS Grid container (.grid-container)
111
117
  // grid-container + grid-cols-{1-12} + col-span-{1-12}
112
118
  // --------------------------------------------------------------------------
113
119
  .grid-container {
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter } from '@angular/core';
2
+ import { EventEmitter, OnInit, OnDestroy } from '@angular/core';
3
3
  import { ModelRange, EditorConfig, ModelDocumentSelection, EventInfo, ViewDataTransfer, ClassicEditor, Plugin, Widget, ContextualBalloon } from 'ckeditor5';
4
4
  import { I18nParams } from '@sdcorejs/angular/i18n';
5
5
 
@@ -199,7 +199,7 @@ declare class CkCommentPlugin extends Plugin {
199
199
  clearPendingSelection(): void;
200
200
  }
201
201
 
202
- declare class SdDocumentBuilder {
202
+ declare class SdDocumentBuilder implements OnInit, OnDestroy {
203
203
  #private;
204
204
  option: SdDocumentBuilderOption;
205
205
  disabled: boolean;
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, PipeTransform, OnDestroy, ChangeDetectorRef, AfterViewInit, QueryList, EventEmitter } from '@angular/core';
2
+ import { InjectionToken, PipeTransform, OnDestroy, OnInit, ChangeDetectorRef, AfterViewInit, QueryList, EventEmitter } from '@angular/core';
3
3
  import { SdSearch, SdCustomValidator } from '@sdcorejs/angular/forms/models';
4
4
  import { SdTableColumn, SdTableOption, SdTable } from '@sdcorejs/angular/components/table';
5
5
  import { SdUploadFile } from '@sdcorejs/angular/components/upload-file';
6
6
  import { Operator as Operator$1, ValidationPatternType, Color } from '@sdcorejs/utils/models';
7
7
  import { SdUnwrapSignal } from '@sdcorejs/angular/utilities/models';
8
- import { CdkDragMove, CdkDragDrop } from '@angular/cdk/drag-drop';
8
+ import { CdkDragMove, CdkDragDrop, CdkDrag, CdkDropList } from '@angular/cdk/drag-drop';
9
9
  import { FormGroup } from '@angular/forms';
10
10
  import { SdModal } from '@sdcorejs/angular/components/modal';
11
11
  import { Subject } from 'rxjs';
@@ -458,14 +458,14 @@ interface SdFormGenericHtml {
458
458
  type FormBuilderComponentGroup = 'basic' | 'choice' | 'advanced' | 'layout';
459
459
  interface FormBuilderComponent {
460
460
  type: string;
461
- /** Material Symbols Rounded icon name. Rendered via <span class="msi">{symbol}</span>. */
461
+ /** Material Icons Outlined icon name. Rendered via the builder icon alias. */
462
462
  symbol: string;
463
463
  /** Category group for the left palette grouping. */
464
464
  group: FormBuilderComponentGroup;
465
465
  name: string;
466
466
  }
467
467
  declare const FormBuilderComponents: FormBuilderComponent[];
468
- /** Lookup: component type → Material Symbol + label, used by attribute panel header. */
468
+ /** Lookup: component type → Material icon + label, used by attribute panel header. */
469
469
  declare const COMPONENT_ICONS: Record<string, {
470
470
  symbol: string;
471
471
  label: string;
@@ -530,7 +530,7 @@ interface IWorkflowConfigurationForm<TSelectionArgs = any> {
530
530
  templates: SdFormGenericTemplate[];
531
531
  selections: SdFormGenericDefinitionSelection<any, TSelectionArgs>[] | (() => SdFormGenericDefinitionSelection<any, TSelectionArgs>[]) | (() => Promise<SdFormGenericDefinitionSelection[]>);
532
532
  getValues?: (key: string, selectionArgs?: TSelectionArgs) => Promise<SdFormGenericSelectionItem[]>;
533
- getLazyValues?: (key: string, selectionArgs?: TSelectionArgs) => ((searchArgs: Parameters<SdSearch>[0], args: SdFormGenericArgs) => Promise<SdFormGenericSelectionItem[]>);
533
+ getLazyValues?: (key: string, selectionArgs?: TSelectionArgs) => (searchArgs: Parameters<SdSearch>[0], args: SdFormGenericArgs) => Promise<SdFormGenericSelectionItem[]>;
534
534
  tables: SdFormGenericDefinitionTable[];
535
535
  htmls: SdFormGenericDefinitionHtml[] | (() => SdFormGenericDefinitionHtml[]) | (() => Promise<SdFormGenericDefinitionHtml[]>);
536
536
  validation?: SdFormGenericValidationConfiguration;
@@ -544,7 +544,6 @@ declare const SD_FORM_GENERIC_CONFIGURATION: InjectionToken<ISdFormGenericConfig
544
544
  declare class FormGenericService {
545
545
  #private;
546
546
  private readonly configuration;
547
- constructor(configuration: ISdFormGenericConfiguration);
548
547
  get selections(): (() => Promise<SdFormGenericDefinitionSelection[]>) | SdFormGenericDefinitionSelection<any, any>[] | (() => SdFormGenericDefinitionSelection<any, any>[]);
549
548
  get tables(): _sdcorejs_angular_components_form_generic.SdFormGenericDefinitionTable<any>[];
550
549
  getSelection: (valuesKey: string | undefined | null) => Promise<SdFormGenericDefinitionSelection | undefined>;
@@ -560,7 +559,7 @@ declare class FormGenericService {
560
559
  definitions: () => Promise<SdFormGenericDefinitionHtml[]>;
561
560
  getContent: (template: string, query?: Record<string, any>) => Promise<string>;
562
561
  };
563
- static ɵfac: i0.ɵɵFactoryDeclaration<FormGenericService, [{ optional: true; }]>;
562
+ static ɵfac: i0.ɵɵFactoryDeclaration<FormGenericService, never>;
564
563
  static ɵprov: i0.ɵɵInjectableDeclaration<FormGenericService>;
565
564
  }
566
565
 
@@ -590,7 +589,7 @@ declare class SdFormRenderService {
590
589
  static ɵprov: i0.ɵɵInjectableDeclaration<SdFormRenderService>;
591
590
  }
592
591
 
593
- declare class UploadComponent implements OnDestroy {
592
+ declare class UploadComponent implements OnDestroy, OnInit {
594
593
  #private;
595
594
  private readonly ref;
596
595
  setVariables: Subject<{
@@ -620,7 +619,7 @@ declare class UploadComponent implements OnDestroy {
620
619
  static ɵcmp: i0.ɵɵComponentDeclaration<UploadComponent, "lib-upload", never, { "setVariables": { "alias": "setVariables"; "required": true; }; "form": { "alias": "form"; "required": false; }; "_entity": { "alias": "entity"; "required": true; }; "_component": { "alias": "component"; "required": true; }; "_disabled": { "alias": "disabled"; "required": false; }; "_required": { "alias": "required"; "required": false; }; "_viewed": { "alias": "viewed"; "required": false; }; "_validator": { "alias": "validator"; "required": false; }; }, {}, never, never, true, never>;
621
620
  }
622
621
 
623
- declare class TableComponent implements AfterViewInit, OnDestroy {
622
+ declare class TableComponent implements AfterViewInit, OnDestroy, OnInit {
624
623
  #private;
625
624
  private ref;
626
625
  private readonly formGenericService;
@@ -691,8 +690,6 @@ declare class LibItemComponent {
691
690
 
692
691
  declare class SdFormRender implements OnDestroy, AfterViewInit {
693
692
  #private;
694
- private ref;
695
- private formGenericConfiguration;
696
693
  formRenderItems: QueryList<LibItemComponent>;
697
694
  form: FormGroup;
698
695
  configuration: SdFormRenderConfiguration;
@@ -711,18 +708,17 @@ declare class SdFormRender implements OnDestroy, AfterViewInit {
711
708
  key: string;
712
709
  value: any;
713
710
  }>;
714
- constructor(ref: ChangeDetectorRef, formGenericConfiguration: ISdFormGenericConfiguration | null);
711
+ private readonly ref;
712
+ private readonly formGenericConfiguration;
715
713
  ngAfterViewInit(): void;
716
714
  ngOnDestroy(): void;
717
715
  upload: () => Promise<void>;
718
716
  getValidationMessages: (alert: SdFormGenericValidation["alert"]) => Promise<string[] | undefined>;
719
- static ɵfac: i0.ɵɵFactoryDeclaration<SdFormRender, [null, { optional: true; }]>;
717
+ static ɵfac: i0.ɵɵFactoryDeclaration<SdFormRender, never>;
720
718
  static ɵcmp: i0.ɵɵComponentDeclaration<SdFormRender, "sd-form-render", never, { "form": { "alias": "form"; "required": false; }; "_configuration": { "alias": "configuration"; "required": true; }; "_default": { "alias": "defaultEntity"; "required": false; }; "_entity": { "alias": "entity"; "required": false; }; "_properties": { "alias": "properties"; "required": false; }; "_viewed": { "alias": "viewed"; "required": false; }; }, {}, never, never, true, never>;
721
719
  }
722
720
 
723
- declare class ConfigureValidationComponent {
724
- private ref;
725
- private formGenericConfiguration;
721
+ declare class ConfigureValidationComponent implements AfterViewInit, OnDestroy {
726
722
  modal?: SdModal;
727
723
  form: FormGroup<{}>;
728
724
  attributes: Attribute[];
@@ -733,22 +729,35 @@ declare class ConfigureValidationComponent {
733
729
  display: string;
734
730
  }[];
735
731
  accept: EventEmitter<SdFormGenericValidation[]>;
736
- constructor(ref: ChangeDetectorRef, formGenericConfiguration: ISdFormGenericConfiguration | null);
732
+ private readonly ref;
733
+ private readonly formGenericConfiguration;
734
+ constructor();
737
735
  ngAfterViewInit(): void;
738
736
  ngOnDestroy(): void;
739
737
  open: (formGeneric: SdFormGeneric) => void;
740
738
  addValidation: (type: SdFormGenericValidation["type"]) => void;
741
739
  removaValidation: (index: number) => void;
742
740
  updateValidations: () => void;
743
- static ɵfac: i0.ɵɵFactoryDeclaration<ConfigureValidationComponent, [null, { optional: true; }]>;
741
+ static ɵfac: i0.ɵɵFactoryDeclaration<ConfigureValidationComponent, never>;
744
742
  static ɵcmp: i0.ɵɵComponentDeclaration<ConfigureValidationComponent, "configure-validation", never, {}, { "accept": "accept"; }, never, never, true, never>;
745
743
  }
746
744
 
747
- interface DragDropRowItem {
748
- items: (SdFormGenericComponent | SdFormGenericGroup)[];
745
+ type FormBuilderLayoutItem = SdFormGenericComponent | SdFormGenericGroup;
746
+ interface FormBuilderLayoutRow {
747
+ id: string;
748
+ items: FormBuilderLayoutItem[];
749
+ columns: number;
750
+ }
751
+
752
+ interface DragDropRowItem extends FormBuilderLayoutRow {
749
753
  rowIndex?: number;
750
754
  }
751
- declare class SdFormBuilder {
755
+ interface ResizeState {
756
+ itemId: string;
757
+ rowId: string;
758
+ columns: string;
759
+ }
760
+ declare class SdFormBuilder implements OnInit, OnDestroy {
752
761
  #private;
753
762
  readonly popupViewJSON: i0.Signal<SdModal | undefined>;
754
763
  readonly popupConfigureVariables: i0.Signal<SdModal | undefined>;
@@ -781,6 +790,9 @@ declare class SdFormBuilder {
781
790
  /** Signal toàn cục: TRUE khi BẤT KỲ cdkDrag nào đang active (palette, canvas, group, resize).
782
791
  * Trigger class `.fb-shell--dragging` để ẩn hover/actions/resize toàn diện, không phụ thuộc :has(). */
783
792
  readonly isAnyDragging: i0.WritableSignal<boolean>;
793
+ readonly dragSource: i0.WritableSignal<"row" | "palette" | "canvas" | "resize" | undefined>;
794
+ readonly resizeState: i0.WritableSignal<ResizeState | undefined>;
795
+ readonly isResizing: i0.Signal<boolean>;
784
796
  expand: boolean;
785
797
  dragDropRows: DragDropRowItem[];
786
798
  isDragging: boolean;
@@ -788,18 +800,25 @@ declare class SdFormBuilder {
788
800
  private lastDragPointer?;
789
801
  /** Handler chung cho mọi cdkDragStarted — set signal global true. */
790
802
  onAnyDragStarted: () => void;
803
+ onPaletteDragStarted: () => void;
804
+ onRowDragStarted: () => void;
791
805
  onAnyDragMoved: (event: CdkDragMove<any>) => void;
792
806
  /** Handler chung cho mọi cdkDragEnded — set signal global false (dùng setTimeout 0
793
807
  * để chờ CDK xử lý xong drop event trước khi UI re-enable). */
794
808
  onAnyDragEnded: () => void;
809
+ startResizeControl: (item: SdFormGenericComponent | SdFormGenericGroup, row: DragDropRowItem) => void;
810
+ endResizeControl: (event: any) => void;
795
811
  constructor();
796
812
  ngOnInit(): void;
797
813
  ngOnDestroy(): void;
798
- addComponent: (item: FormBuilderComponent, index?: number) => void;
814
+ addComponent: (item: FormBuilderComponent, index?: number, layoutColumns?: string) => void;
799
815
  /** Symbol Material để render trên canvas item / attribute header. */
800
816
  symbolFor: (item: SdFormGenericComponent | SdFormGenericGroup) => string;
801
817
  /** Human-readable type label (e.g. "Text field", "Date"). */
802
818
  typeLabelFor: (item: SdFormGenericComponent | SdFormGenericGroup) => string;
819
+ placeholderSymbolFor: (item: FormBuilderComponent | SdFormGenericComponent | SdFormGenericGroup | DragDropRowItem | undefined) => string;
820
+ placeholderTitleFor: (item: FormBuilderComponent | SdFormGenericComponent | SdFormGenericGroup | DragDropRowItem | undefined) => string;
821
+ placeholderMetaFor: (item: FormBuilderComponent | SdFormGenericComponent | SdFormGenericGroup | DragDropRowItem | undefined) => string;
803
822
  /** True nếu component có expression điều kiện — drives the "conditional" status chip. */
804
823
  hasConditional: (item: SdFormGenericComponent | SdFormGenericGroup) => boolean;
805
824
  /** Map SdColor preset → 2 CSS var names cho header-bg và header-fg của group card. */
@@ -828,6 +847,9 @@ declare class SdFormBuilder {
828
847
  dragStartComponentItem: (event: any) => void;
829
848
  dragEndComponentItem: (event: any) => void;
830
849
  onMouseover: (event: MouseEvent, rowItem: DragDropRowItem) => void;
850
+ isRowFull: (row: DragDropRowItem) => boolean;
851
+ isRowInlineDropLocked: (row: DragDropRowItem) => boolean;
852
+ canEnterRowDropList: (drag: CdkDrag<FormBuilderComponent | SdFormGenericComponent | SdFormGenericGroup>, drop: CdkDropList<(SdFormGenericComponent | SdFormGenericGroup)[]>) => boolean;
831
853
  onFocus: (event: FocusEvent) => void;
832
854
  xuLyKeoCheo: (dragItem?: SdFormGenericComponent | SdFormGenericGroup) => void;
833
855
  noReturnPredicate: () => boolean;
@@ -853,7 +875,7 @@ declare class SdFormBuilder {
853
875
  static ɵcmp: i0.ɵɵComponentDeclaration<SdFormBuilder, "sd-form-builder", never, { "formGeneric": { "alias": "formGeneric"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
854
876
  }
855
877
 
856
- declare class SdFeelExpression {
878
+ declare class SdFeelExpression implements OnInit {
857
879
  #private;
858
880
  private ref;
859
881
  private expressionFeelPipe;
@@ -97,7 +97,7 @@ interface SdUploadExcelColumnStringArray<T = any> extends SdUploadExcelBaseColum
97
97
  minlength?: number;
98
98
  maxlength?: number;
99
99
  }
100
- type SdImportExcelItem<T = any> = {
100
+ interface SdImportExcelItem<T = any> {
101
101
  data: T;
102
102
  meta: {
103
103
  excelIndex: number;
@@ -107,7 +107,7 @@ type SdImportExcelItem<T = any> = {
107
107
  warning: Record<string, string>;
108
108
  warningMessages: string[];
109
109
  };
110
- };
110
+ }
111
111
 
112
112
  declare class ColumnHiddenPipe implements PipeTransform {
113
113
  constructor();
@@ -1,7 +1,7 @@
1
1
  import { MentionFeed, MentionFeedObjectItem, EditorConfig, ClassicEditor } from 'ckeditor5';
2
2
  export { MentionFeedObjectItem } from 'ckeditor5';
3
3
  import * as i0 from '@angular/core';
4
- import { EventEmitter } from '@angular/core';
4
+ import { OnDestroy, EventEmitter } from '@angular/core';
5
5
  import { ControlValueAccessor } from '@angular/forms';
6
6
 
7
7
  type SdMiniEditorOutputFormat = 'html' | 'markdown';
@@ -62,7 +62,7 @@ type SdMiniEditorConfig = EditorConfig & {
62
62
  * </sd-mini-editor>
63
63
  * ```
64
64
  */
65
- declare class SdMiniEditor implements ControlValueAccessor {
65
+ declare class SdMiniEditor implements ControlValueAccessor, OnDestroy {
66
66
  #private;
67
67
  /** Cấu hình option cho editor */
68
68
  option: SdMiniEditorOption;
@@ -113,11 +113,11 @@ declare class SdMiniEditor implements ControlValueAccessor {
113
113
  /**
114
114
  * Get danh sách mentions trong nội dung
115
115
  */
116
- getMentions(): Array<{
116
+ getMentions(): {
117
117
  id: string;
118
118
  name: string;
119
119
  marker: string;
120
- }>;
120
+ }[];
121
121
  /**
122
122
  * ControlValueAccessor: Write value
123
123
  */
@@ -16,7 +16,7 @@ declare class SdModal {
16
16
  width: _angular_core.InputSignalWithTransform<string, string | null | undefined>;
17
17
  height: _angular_core.InputSignalWithTransform<string, string | null | undefined>;
18
18
  view: _angular_core.InputSignalWithTransform<"dialog" | "bottom-sheet" | undefined, "dialog" | "bottom-sheet" | null | undefined>;
19
- modalClass: _angular_core.InputSignalWithTransform<string | string[] | Record<string, boolean>, string | string[] | Record<string, boolean> | null | undefined>;
19
+ modalClass: _angular_core.InputSignalWithTransform<string | Record<string, boolean> | string[], string | Record<string, boolean> | string[] | null | undefined>;
20
20
  lazyLoadContent: _angular_core.InputSignalWithTransform<boolean, unknown>;
21
21
  hideClose: _angular_core.InputSignalWithTransform<boolean, boolean | "">;
22
22
  disableBackdropClose: _angular_core.InputSignalWithTransform<boolean, boolean | "">;
@@ -150,7 +150,7 @@ interface QbDateModeOption {
150
150
  icon: string;
151
151
  }
152
152
  /** Stable option list for the date-mode select (module ref — never reallocated). */
153
- declare const QB_DATE_MODES: ReadonlyArray<QbDateModeOption>;
153
+ declare const QB_DATE_MODES: readonly QbDateModeOption[];
154
154
  /** One value-source option for field-to-field comparison UI. */
155
155
  interface QbValueSourceOption {
156
156
  value: QbValueSource;
@@ -159,12 +159,12 @@ interface QbValueSourceOption {
159
159
  icon: string;
160
160
  }
161
161
  /** Stable option list for choosing between a literal value and another field. */
162
- declare const QB_VALUE_SOURCE_OPTIONS: ReadonlyArray<QbValueSourceOption>;
162
+ declare const QB_VALUE_SOURCE_OPTIONS: readonly QbValueSourceOption[];
163
163
  /** Stable combined direction×unit option list (token `'unit:direction'`). */
164
- declare const QB_RELATIVE_UNIT_OPTIONS: ReadonlyArray<{
164
+ declare const QB_RELATIVE_UNIT_OPTIONS: readonly {
165
165
  value: string;
166
166
  display: string;
167
- }>;
167
+ }[];
168
168
  /** Shared empty option array — stable ref for fallbacks (avoids per-call allocation). */
169
169
  declare const QB_EMPTY_OPTIONS: SdQueryBuilderFieldOption[];
170
170
 
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Type, ElementRef, ChangeDetectorRef, OnDestroy } from '@angular/core';
2
+ import { InjectionToken, Type, ElementRef, ChangeDetectorRef, OnDestroy } from '@angular/core';
3
3
  import { Color } from '@sdcorejs/utils/models';
4
4
  import { Subject, BehaviorSubject } from 'rxjs';
5
5
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
@@ -22,6 +22,7 @@ interface SdTab {
22
22
  tabInfoChanges: Subject<SdTabInfo>;
23
23
  beforeClose?: () => boolean | Promise<boolean>;
24
24
  }
25
+ declare const SD_TAB: InjectionToken<SdTab>;
25
26
 
26
27
  declare class SdTabRouterNavComponent {
27
28
  tabRouterNav: i0.Signal<ElementRef<any> | undefined>;
@@ -87,7 +88,6 @@ declare class SdTabRouterService {
87
88
  currentTabChanges: BehaviorSubject<SdTab | undefined>;
88
89
  newTabs: BehaviorSubject<SdTab | undefined>;
89
90
  updateTabs: BehaviorSubject<SdTab | undefined>;
90
- constructor();
91
91
  addBuilder: (builder: SdTabComponentBuilder) => void;
92
92
  get currentTab(): SdTab | undefined;
93
93
  get currentKey(): string | null;
@@ -100,5 +100,5 @@ declare class SdTabRouterService {
100
100
  static ɵprov: i0.ɵɵInjectableDeclaration<SdTabRouterService>;
101
101
  }
102
102
 
103
- export { SdTabComponent, SdTabRouterOutletComponent, SdTabRouterService };
103
+ export { SD_TAB, SdTabComponent, SdTabRouterOutletComponent, SdTabRouterService };
104
104
  export type { SdTab, SdTabComponentArgs, SdTabComponentBuilder, SdTabInfo };
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { TemplateRef, Signal, EventEmitter, ChangeDetectorRef, InjectionToken, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
2
+ import { TemplateRef, Signal, EventEmitter, ChangeDetectorRef, InjectionToken, AfterViewInit, OnDestroy } from '@angular/core';
3
3
  import { SdBadge } from '@sdcorejs/angular/components/badge';
4
4
  import { SdSearch } from '@sdcorejs/angular/forms';
5
5
  import { Operator, NestedKeyOf, Order, PagingReq, Color } from '@sdcorejs/utils/models';
@@ -60,6 +60,7 @@ interface SdTableColumnBase<T = any> {
60
60
  filter?: {
61
61
  disabled?: boolean;
62
62
  default?: any;
63
+ onChange?: (value: any, column?: SdTableColumn<T>, columnFilter?: Record<string, any>) => void;
63
64
  operator?: {
64
65
  default?: Operator;
65
66
  enable?: boolean;
@@ -81,7 +82,7 @@ interface SdTableColumnNumber<T = any> extends SdTableColumnBase<T> {
81
82
  field: NestedKeyOf<T>;
82
83
  type: 'number';
83
84
  useBadge?: UseBadgeFunc<T>;
84
- filter?: SdTableColumnBase['filter'] & {
85
+ filter?: SdTableColumnBase<T>['filter'] & {
85
86
  type?: 'split-number';
86
87
  };
87
88
  }
@@ -98,7 +99,7 @@ interface SdTableColumnDate<T = any> extends SdTableColumnBase<T> {
98
99
  field: NestedKeyOf<T>;
99
100
  type: 'date' | 'datetime' | 'time';
100
101
  useBadge?: UseBadgeFunc<T>;
101
- filter?: SdTableColumnBase['filter'] & {
102
+ filter?: SdTableColumnBase<T>['filter'] & {
102
103
  type?: 'daterange' | 'date' | 'split-date';
103
104
  };
104
105
  }
@@ -1146,7 +1147,7 @@ declare class MatPaginatorIntlCro extends MatPaginatorIntl {
1146
1147
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MatPaginatorIntlCro, never>;
1147
1148
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<MatPaginatorIntlCro>;
1148
1149
  }
1149
- declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDestroy {
1150
+ declare class SdTable<T = unknown> implements AfterViewInit, OnDestroy {
1150
1151
  #private;
1151
1152
  autoIdInput: _angular_core.InputSignal<string | null | undefined>;
1152
1153
  autoId: _angular_core.Signal<string | undefined>;
@@ -1182,14 +1183,13 @@ declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDestroy {
1182
1183
  filterRegister: TableFilterRegister;
1183
1184
  key: string;
1184
1185
  columnOperator: Record<string, Operator>;
1185
- columnFilter?: Record<string, any>;
1186
- cacheValues: Record<string, any[]>;
1186
+ columnFilter?: NonNullable<TableFilterValue['columnFilter']>;
1187
+ cacheValues: Record<string, unknown[]>;
1187
1188
  treeRevision: _angular_core.WritableSignal<number>;
1188
1189
  exporting: _angular_core.WritableSignal<boolean>;
1189
1190
  exportTitle: _angular_core.WritableSignal<string>;
1190
1191
  tableConfiguration: ISdTableConfiguration | null;
1191
1192
  constructor();
1192
- ngOnInit(): void;
1193
1193
  ngAfterViewInit(): void;
1194
1194
  ngOnDestroy(): void;
1195
1195
  getFilterRequest: () => SdTableFilterRequest;
@@ -1229,10 +1229,7 @@ declare class SdTable<T = unknown> implements OnInit, AfterViewInit, OnDestroy {
1229
1229
  groupContext: (header: SdTableItem<T>) => SdTableGroupDefContext<T>;
1230
1230
  rowStyle: (row: SdTableItem<T>, index?: number) => Record<string, string> | null;
1231
1231
  clearFilter: () => void;
1232
- setFilter: (args: {
1233
- columnFilter?: Record<string, any>;
1234
- externalFilter?: Record<string, any>;
1235
- }) => void;
1232
+ setFilter: (args?: Pick<TableFilterValue, "columnFilter" | "externalFilter">) => void;
1236
1233
  get dataItems(): T[];
1237
1234
  get selectedItems(): T[];
1238
1235
  detectChanges: () => void;
@@ -21,7 +21,7 @@ declare class SdView {
21
21
  * why: `input.required()` forces the parent to bind `[display]` (compile error otherwise),
22
22
  * so the component never has to guess a fallback string from `value`.
23
23
  */
24
- display: _angular_core.InputSignal<string | null | undefined>;
24
+ display: _angular_core.InputSignal<unknown>;
25
25
  /** When set, the value renders as a link (`<a [sdHref]>`) instead of plain text. */
26
26
  hyperlink: _angular_core.InputSignal<string | null | undefined>;
27
27
  /** Label template handed down by a parent control (wins over `label` + `#sdLabel`). */
@@ -29,7 +29,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
29
29
  args: [{ selector: 'sd-anchor-item', imports: [CommonModule], standalone: true, template: "<section>\n <ng-content></ng-content>\n</section>\n" }]
30
30
  }], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: false }] }] } });
31
31
 
32
- // eslint-disable-next-line @angular-eslint/component-class-suffix
33
32
  class AnchorNav {
34
33
  sections = input.required(...(ngDevMode ? [{ debugName: "sections" }] : []));
35
34
  activeSectionId = input('', ...(ngDevMode ? [{ debugName: "activeSectionId" }] : []));
@@ -51,9 +50,7 @@ class AnchorNav {
51
50
  #clickSectionSubject = new Subject();
52
51
  #subscription = new Subscription();
53
52
  constructor() {
54
- this.#subscription.add(this.#clickSectionSubject
55
- .pipe(debounceTime(this.#delay))
56
- .subscribe((id) => this.clickSection.emit(id)));
53
+ this.#subscription.add(this.#clickSectionSubject.pipe(debounceTime(this.#delay)).subscribe((id) => this.clickSection.emit(id)));
57
54
  }
58
55
  onClickSection = (id) => {
59
56
  this.#clickSectionSubject.next(id);
@@ -77,10 +74,10 @@ class SdAnchor {
77
74
  sidebarWidth = input('200px', ...(ngDevMode ? [{ debugName: "sidebarWidth" }] : []));
78
75
  ellipsis = input(false, ...(ngDevMode ? [{ debugName: "ellipsis", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
79
76
  overScroll = input(false, ...(ngDevMode ? [{ debugName: "overScroll", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
80
- // Mobile: default ẩn nav (sidebar TOC chiếm chỗ trên màn hình hẹp).
81
- // Consumer truyền `[hideNav]="false"` để force hiện trên mobile.
77
+ // Mobile: default ?n nav (sidebar TOC chi?m ch? tr�n m�n h�nh h?p).
78
+ // Consumer truy?n `[hideNav]="false"` d? force hi?n tr�n mobile.
82
79
  hideNav = input(BrowserUtilities.isMobile(), ...(ngDevMode ? [{ debugName: "hideNav", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
83
- // Màu highlight active nav (text + icon + vertical bar). Default 'primary'.
80
+ // M�u highlight active nav (text + icon + vertical bar). Default 'primary'.
84
81
  color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
85
82
  activeSectionId = signal('', ...(ngDevMode ? [{ debugName: "activeSectionId" }] : []));
86
83
  #initialized = false;
@@ -97,7 +94,7 @@ class SdAnchor {
97
94
  this.#registerIntersectionObserver();
98
95
  }
99
96
  });
100
- // Lắng nghe thay đổi sections để đăng lại observe section
97
+ // L?ng nghe thay d?i sections d? dang k� l?i observe section
101
98
  effect(() => {
102
99
  this.sections();
103
100
  if (!this.hideNav() && this.#initialized) {
@@ -108,24 +105,24 @@ class SdAnchor {
108
105
  #registerIntersectionObserver() {
109
106
  this.#cleanIntersectionObserver();
110
107
  const wrapperEl = this.wrapper().nativeElement;
111
- // Brower API IntersectionObserver sẽ hỗ trợ khi nào 1 section được hiện ra trong wrapperEl
108
+ // Brower API IntersectionObserver s? h? tr? khi n�o 1 section du?c hi?n ra trong wrapperEl
112
109
  this.#intersectionObserver = new IntersectionObserver(entries => {
113
110
  for (const entry of entries) {
114
111
  if (entry.isIntersecting) {
115
- // Nếu section mới đi vào vùng nhìn thấy -> add vào set
112
+ // N?u section m?i di v�o v�ng nh�n th?y -> add v�o set
116
113
  this.#visibleSections.add(entry.target);
117
114
  }
118
115
  else {
119
- // Nếu section đã đi ra khỏi vùng nhìn thấy -> xóa khỏi Set
116
+ // N?u section d� di ra kh?i v�ng nh�n th?y -> x�a kh?i Set
120
117
  this.#visibleSections.delete(entry.target);
121
118
  }
122
119
  }
123
- // 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
120
+ // N?u dang scroll b?i click section th� return lu�n, k ph?i qu�t qua t�m v�ng section du?c active
124
121
  if (this.#isClickScrolling) {
125
122
  return;
126
123
  }
127
124
  for (const section of this.sections()) {
128
- // 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
125
+ // Ki?m tra xem DOM c?a section n�o dang n?m trong danh s�ch dang nh�n th?y d? active ch�nh x�c
129
126
  if (this.#visibleSections.has(section.elementRef.nativeElement)) {
130
127
  if (this.activeSectionId() !== section.id) {
131
128
  this.activeSectionId.set(section.id);
@@ -134,7 +131,7 @@ class SdAnchor {
134
131
  }
135
132
  }
136
133
  }, { root: wrapperEl, threshold: 0 });
137
- // Đăng theo dõi từng section trong anchor
134
+ // �ang k� theo d�i t?ng section c� trong anchor
138
135
  for (const section of this.sections()) {
139
136
  this.#intersectionObserver.observe(section.elementRef.nativeElement);
140
137
  }
@@ -149,15 +146,15 @@ class SdAnchor {
149
146
  this.#isClickScrolling = true;
150
147
  const wrapperEl = this.wrapper().nativeElement;
151
148
  const targetElement = targetSection.nativeElement;
152
- const prevScrollTop = wrapperEl.scrollTop; // Lưu lại vị trí cuộn hiện tại của container
153
- const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // Vị trí section cần scroll tới
154
- // Đăng sự kiện nếu đã được scroll xong
149
+ const prevScrollTop = wrapperEl.scrollTop; // Luu l?i v? tr� cu?n hi?n t?i c?a container
150
+ const scrollTop = prevScrollTop + targetElement.getBoundingClientRect().top - wrapperEl.getBoundingClientRect().top; // V? tr� section c?n scroll t?i
151
+ // �ang k� s? ki?n n?u d� du?c scroll xong
155
152
  this.#clickScrollSubscription = fromEvent(wrapperEl, 'scrollend')
156
153
  .pipe(take(1))
157
154
  .subscribe(() => {
158
155
  this.#isClickScrolling = false;
159
156
  });
160
- // Nếu sectionTarget đã đúng vị trí (click nhưng không scroll) thì sau #timeoutScrollFallback kích hoạt lại IntersectionObserver
157
+ // N?u sectionTarget d� ? d�ng v? tr� (click nhung kh�ng scroll) th� sau #timeoutScrollFallback k�ch ho?t l?i IntersectionObserver
161
158
  this.#timeoutId = setTimeout(() => {
162
159
  if (wrapperEl.scrollTop === prevScrollTop) {
163
160
  this.#isClickScrolling = false;