@sdcorejs/angular 20.1.6 → 20.2.0

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 (208) hide show
  1. package/README.md +10 -0
  2. package/assets/scss/core/menu.scss +18 -0
  3. package/assets/scss/core/utilities/_misc.scss +15 -0
  4. package/assets/scss/sd-core.scss +1 -0
  5. package/components/anchor/index.d.ts +3 -1
  6. package/components/badge/index.d.ts +1 -0
  7. package/components/ckeditor-styles/index.d.ts +1 -1
  8. package/components/form-generic/index.d.ts +44 -33
  9. package/components/import-excel/index.d.ts +1 -0
  10. package/components/index.d.ts +6 -1
  11. package/components/mini-editor/index.d.ts +1 -1
  12. package/components/modal/index.d.ts +3 -2
  13. package/components/modal-resizable/index.d.ts +92 -0
  14. package/components/org-chart/index.d.ts +6 -0
  15. package/components/preview/index.d.ts +1 -0
  16. package/components/query-bar/index.d.ts +55 -17
  17. package/components/query-builder/index.d.ts +150 -98
  18. package/components/section/index.d.ts +3 -0
  19. package/components/tab-router/index.d.ts +19 -19
  20. package/components/table/index.d.ts +251 -109
  21. package/components/tree/index.d.ts +48 -30
  22. package/components/upload-file/index.d.ts +6 -3
  23. package/configurations/index.d.ts +1 -2
  24. package/fesm2022/sdcorejs-angular-components-anchor.mjs +37 -13
  25. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +2 -2
  27. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  28. package/fesm2022/sdcorejs-angular-components-badge.mjs +15 -2
  29. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  30. package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
  31. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +1 -1
  33. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
  35. package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-data-state.mjs +3 -3
  37. package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-editor.mjs +2 -2
  39. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +324 -192
  41. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-history.mjs +4 -4
  43. package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +13 -5
  45. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-components-inform.mjs +3 -3
  47. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +164 -8
  49. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-components-modal.mjs +30 -18
  51. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-components-org-chart.mjs +60 -13
  53. package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-components-preview.mjs +27 -17
  55. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +192 -30
  57. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +187 -127
  59. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-components-section.mjs +16 -2
  61. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +83 -24
  63. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  64. package/fesm2022/sdcorejs-angular-components-splitter.mjs +57 -21
  65. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-components-stepper.mjs +2 -2
  67. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +68 -20
  69. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -2
  71. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-components-table.mjs +542 -255
  73. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-components-tree.mjs +80 -17
  75. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +48 -13
  77. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-components.mjs +6 -1
  79. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
  81. package/fesm2022/sdcorejs-angular-directives.mjs +45 -8
  82. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  83. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +40 -29
  84. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  85. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +5 -5
  86. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  87. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +67 -50
  88. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  89. package/fesm2022/sdcorejs-angular-forms-chip.mjs +57 -43
  90. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  91. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +232 -61
  92. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  93. package/fesm2022/sdcorejs-angular-forms-date.mjs +96 -24
  94. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  95. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +131 -27
  96. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  97. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +40 -16
  98. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -1
  99. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +16 -5
  100. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  101. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +24 -9
  102. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  103. package/fesm2022/sdcorejs-angular-forms-input.mjs +58 -10
  104. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  105. package/fesm2022/sdcorejs-angular-forms-models.mjs +227 -6
  106. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  107. package/fesm2022/sdcorejs-angular-forms-radio.mjs +4 -4
  108. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  109. package/fesm2022/sdcorejs-angular-forms-select.mjs +136 -38
  110. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  111. package/fesm2022/sdcorejs-angular-forms-switch.mjs +18 -3
  112. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  113. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +51 -62
  114. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  115. package/fesm2022/sdcorejs-angular-forms-time-range.mjs +57 -12
  116. package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -1
  117. package/fesm2022/sdcorejs-angular-forms-time.mjs +16 -5
  118. package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -1
  119. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +100 -9
  120. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -1
  121. package/fesm2022/sdcorejs-angular-forms.mjs +91 -46
  122. package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
  123. package/fesm2022/sdcorejs-angular-handlers.mjs +18 -3
  124. package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
  125. package/fesm2022/sdcorejs-angular-i18n.mjs +490 -68
  126. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  127. package/fesm2022/sdcorejs-angular-interceptors.mjs +87 -29
  128. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  129. package/fesm2022/sdcorejs-angular-modules-auth.mjs +25 -15
  130. package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
  131. package/fesm2022/sdcorejs-angular-modules-icon.mjs +2 -2
  132. package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
  133. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +32 -3
  134. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
  135. package/fesm2022/sdcorejs-angular-modules-layout.mjs +332 -111
  136. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  137. package/fesm2022/sdcorejs-angular-modules-permission.mjs +177 -40
  138. package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
  139. package/fesm2022/sdcorejs-angular-pipes.mjs +62 -28
  140. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  141. package/fesm2022/sdcorejs-angular-services-api.mjs +123 -13
  142. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  143. package/fesm2022/sdcorejs-angular-services-cache.mjs +53 -3
  144. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  145. package/fesm2022/sdcorejs-angular-services-confirm.mjs +25 -73
  146. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  147. package/fesm2022/sdcorejs-angular-services-excel.mjs +12 -10
  148. package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
  149. package/fesm2022/sdcorejs-angular-services-loading.mjs +75 -84
  150. package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
  151. package/fesm2022/sdcorejs-angular-services-notify.mjs +46 -5
  152. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  153. package/fesm2022/sdcorejs-angular-services-storage.mjs +4 -0
  154. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  155. package/fesm2022/sdcorejs-angular-services.mjs +0 -1
  156. package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
  157. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +225 -80
  158. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
  159. package/fesm2022/sdcorejs-angular-utilities-models.mjs +1 -63
  160. package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
  161. package/fesm2022/sdcorejs-angular.mjs +17 -10
  162. package/fesm2022/sdcorejs-angular.mjs.map +1 -1
  163. package/forms/autocomplete/index.d.ts +5 -2
  164. package/forms/chip-calendar/index.d.ts +10 -0
  165. package/forms/date/index.d.ts +13 -2
  166. package/forms/date-range/index.d.ts +14 -2
  167. package/forms/datetime/index.d.ts +13 -2
  168. package/forms/entity-picker/index.d.ts +9 -3
  169. package/forms/index.d.ts +22 -13
  170. package/forms/input/index.d.ts +3 -0
  171. package/forms/input-color/index.d.ts +4 -0
  172. package/forms/input-number/index.d.ts +3 -0
  173. package/forms/models/index.d.ts +119 -4
  174. package/forms/select/index.d.ts +27 -4
  175. package/forms/switch/index.d.ts +7 -1
  176. package/forms/textarea/index.d.ts +5 -3
  177. package/forms/time-range/index.d.ts +22 -1
  178. package/forms/tree-select/index.d.ts +36 -5
  179. package/i18n/index.d.ts +95 -16
  180. package/index.d.ts +11 -2
  181. package/interceptors/index.d.ts +13 -3
  182. package/modules/auth/index.d.ts +1 -1
  183. package/modules/keycloak/index.d.ts +1 -0
  184. package/modules/layout/index.d.ts +94 -28
  185. package/modules/permission/index.d.ts +66 -4
  186. package/package.json +32 -25
  187. package/pipes/index.d.ts +27 -5
  188. package/services/api/index.d.ts +21 -1
  189. package/services/cache/index.d.ts +11 -1
  190. package/services/index.d.ts +0 -1
  191. package/services/notify/index.d.ts +1 -1
  192. package/utilities/extensions/index.d.ts +83 -61
  193. package/utilities/models/index.d.ts +2 -76
  194. package/components/base/index.d.ts +0 -11
  195. package/components/document-builder/index.d.ts +0 -252
  196. package/fesm2022/sdcorejs-angular-components-base.mjs +0 -23
  197. package/fesm2022/sdcorejs-angular-components-base.mjs.map +0 -1
  198. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +0 -5038
  199. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +0 -1
  200. package/fesm2022/sdcorejs-angular-models.mjs +0 -6
  201. package/fesm2022/sdcorejs-angular-models.mjs.map +0 -1
  202. package/fesm2022/sdcorejs-angular-services-docx.mjs +0 -291
  203. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +0 -1
  204. package/fesm2022/sdcorejs-angular-services-license.mjs +0 -97
  205. package/fesm2022/sdcorejs-angular-services-license.mjs.map +0 -1
  206. package/models/index.d.ts +0 -2
  207. package/services/docx/index.d.ts +0 -27
  208. package/services/license/index.d.ts +0 -12
@@ -5,7 +5,7 @@ import { MatMenu } from '@angular/material/menu';
5
5
  import { SdSearch } from '@sdcorejs/angular/forms/models';
6
6
 
7
7
  type SdQueryFieldType = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'values' | 'lazy-values';
8
- interface SdQueryFieldBase<T = any> {
8
+ interface SdQueryFieldBase<T = unknown> {
9
9
  /** Dot-notation field path (matches `Filter.field`). */
10
10
  key: NestedKeyOf<T>;
11
11
  /** Human-readable label shown on chip + field picker. */
@@ -30,10 +30,10 @@ interface SdQueryFieldBase<T = any> {
30
30
  /** Field is offered in picker but not interactive (read-only badge in chip). */
31
31
  disabled?: boolean;
32
32
  }
33
- interface SdQueryFieldString<T = any> extends SdQueryFieldBase<T> {
33
+ interface SdQueryFieldString<T = unknown> extends SdQueryFieldBase<T> {
34
34
  type: 'string';
35
35
  }
36
- interface SdQueryFieldNumber<T = any> extends SdQueryFieldBase<T> {
36
+ interface SdQueryFieldNumber<T = unknown> extends SdQueryFieldBase<T> {
37
37
  type: 'number';
38
38
  /** Bounds for the input control inside the chip popover. */
39
39
  min?: number;
@@ -41,13 +41,13 @@ interface SdQueryFieldNumber<T = any> extends SdQueryFieldBase<T> {
41
41
  /** Step for the number input. */
42
42
  step?: number;
43
43
  }
44
- interface SdQueryFieldBoolean<T = any> extends SdQueryFieldBase<T> {
44
+ interface SdQueryFieldBoolean<T = unknown> extends SdQueryFieldBase<T> {
45
45
  type: 'boolean';
46
46
  /** Labels rendered for the true/false buttons. Default: "Có" / "Không". */
47
47
  trueLabel?: string;
48
48
  falseLabel?: string;
49
49
  }
50
- interface SdQueryFieldDate<T = any> extends SdQueryFieldBase<T> {
50
+ interface SdQueryFieldDate<T = unknown> extends SdQueryFieldBase<T> {
51
51
  type: 'date' | 'datetime';
52
52
  /** Restrict the picker calendar to this range. */
53
53
  min?: Date | string;
@@ -57,7 +57,7 @@ interface SdQueryFieldDate<T = any> extends SdQueryFieldBase<T> {
57
57
  * Statically-known options (sync array, signal, or one-shot promise).
58
58
  * Mirrors `SdTableColumnValues.option`.
59
59
  */
60
- interface SdQueryFieldValues<T = any, K = Record<string, any>> extends SdQueryFieldBase<T> {
60
+ interface SdQueryFieldValues<T = unknown, K = Record<string, any>> extends SdQueryFieldBase<T> {
61
61
  type: 'values';
62
62
  option: {
63
63
  items: K[] | Signal<K[]> | (() => Promise<K[]>);
@@ -71,7 +71,7 @@ interface SdQueryFieldValues<T = any, K = Record<string, any>> extends SdQueryFi
71
71
  * `{ type: 'SEARCH', searchText }` for live queries and `{ type: 'VALUE', value }` for
72
72
  * resolving chip-display labels of already-selected IDs.
73
73
  */
74
- interface SdQueryFieldLazyValues<T = any, K = Record<string, any>> extends SdQueryFieldBase<T> {
74
+ interface SdQueryFieldLazyValues<T = unknown, K = Record<string, any>> extends SdQueryFieldBase<T> {
75
75
  type: 'lazy-values';
76
76
  option: {
77
77
  search: SdSearch<K>;
@@ -79,16 +79,16 @@ interface SdQueryFieldLazyValues<T = any, K = Record<string, any>> extends SdQue
79
79
  displayField: NestedKeyOf<K>;
80
80
  };
81
81
  }
82
- type SdQueryField<T = any> = SdQueryFieldString<T> | SdQueryFieldNumber<T> | SdQueryFieldBoolean<T> | SdQueryFieldDate<T> | SdQueryFieldValues<T> | SdQueryFieldLazyValues<T>;
82
+ type SdQueryField<T = unknown> = SdQueryFieldString<T> | SdQueryFieldNumber<T> | SdQueryFieldBoolean<T> | SdQueryFieldDate<T> | SdQueryFieldValues<T> | SdQueryFieldLazyValues<T>;
83
83
  type SdQueryLogic = 'AND' | 'OR';
84
- interface SdQuery<T = any> {
84
+ interface SdQuery<T = unknown> {
85
85
  filters: Filter<T>[];
86
86
  /** Global connector between filters. Defaults to `'AND'`. */
87
87
  logic?: SdQueryLogic;
88
88
  /** Free-text search box (only present when `showSearch=true`). */
89
89
  search?: string;
90
90
  }
91
- interface SdQueryBarOption<T = any> {
91
+ interface SdQueryBarOption<T = unknown> {
92
92
  /** Prefix for auto-generated `data-autoid` on inner controls. */
93
93
  autoId?: string;
94
94
  /** Available fields the user can filter by. */
@@ -111,7 +111,7 @@ interface SdQueryBarOption<T = any> {
111
111
  onApply?: (query: SdQuery<T>) => void;
112
112
  }
113
113
  /** Persisted bookmark of a query (filters + logic + search) — managed by `[savedFiltersKey]`. */
114
- interface SdSavedFilter<T = any> {
114
+ interface SdSavedFilter<T = unknown> {
115
115
  id: string;
116
116
  name: string;
117
117
  query: SdQuery<T>;
@@ -123,7 +123,7 @@ interface SdSavedFilter<T = any> {
123
123
  * - 'operator' — operator menu open, waiting for the user to pick a condition
124
124
  * - 'value' — operator locked, value picker / seamless input is the focus
125
125
  */
126
- interface BuildingChip<T = any> {
126
+ interface BuildingChip<T = unknown> {
127
127
  field: SdQueryField<T>;
128
128
  operator?: Operator;
129
129
  step: 'operator' | 'value';
@@ -151,6 +151,9 @@ declare function sdQueryDefaultOperator(field: SdQueryField): Operator;
151
151
  * - `operators === true` → full set for the type
152
152
  * - `operators` is an array → that array (deduped against the type set is the caller's job)
153
153
  * - otherwise (simple mode) → just the single default operator (no real choice)
154
+ *
155
+ * The returned array is referentially stable for a given `field` object, so it is safe to call
156
+ * straight from a template binding.
154
157
  */
155
158
  declare function sdQueryAllowedOperators(field: SdQueryField): Operator[];
156
159
  /**
@@ -175,6 +178,14 @@ declare function sdQueryShowOperatorSelector(field: SdQueryField): boolean;
175
178
  */
176
179
  declare class SdQueryChipPopover {
177
180
  #private;
181
+ readonly swapFieldTooltip: _angular_core.Signal<string>;
182
+ readonly fromPlaceholder: _angular_core.Signal<string>;
183
+ readonly toPlaceholder: _angular_core.Signal<string>;
184
+ readonly booleanTrueLabel: _angular_core.Signal<string>;
185
+ readonly booleanFalseLabel: _angular_core.Signal<string>;
186
+ readonly selectValuePlaceholder: _angular_core.Signal<string>;
187
+ readonly enterValuePlaceholder: _angular_core.Signal<string>;
188
+ readonly loadingValuesLabel: _angular_core.Signal<string>;
178
189
  /** Resolved field of the currently editing chip — parent passes from `fieldByKey()`. */
179
190
  readonly field: _angular_core.InputSignal<SdQueryField | undefined>;
180
191
  /** The chip's current Filter — used by `seed()` for initial staging values. */
@@ -271,7 +282,7 @@ declare class SdQueryBar {
271
282
  /** The extracted chip popover — owns operator+value staging + commit-on-close. */
272
283
  readonly chipPopover: _angular_core.Signal<SdQueryChipPopover | undefined>;
273
284
  /** Main option object. Prefer this API for new usage; individual inputs stay as a migration bridge. */
274
- readonly option: _angular_core.InputSignal<SdQueryBarOption<any> | undefined>;
285
+ readonly option: _angular_core.InputSignal<SdQueryBarOption<unknown> | undefined>;
275
286
  /** Prefix for auto-generated `data-autoid` on inner controls (chips, operator/value editors, buttons). */
276
287
  readonly autoIdInput: _angular_core.InputSignalWithTransform<string | undefined, string | null | undefined>;
277
288
  /** Available fields the user can filter by. Required for the field picker. */
@@ -312,7 +323,7 @@ declare class SdQueryBar {
312
323
  * Snapshot of the current query — fed into `<sd-query-saved-filters-menu [query]>` so
313
324
  * saving a filter captures live filters/logic/search.
314
325
  */
315
- readonly currentQuery: _angular_core.Signal<SdQuery<any>>;
326
+ readonly currentQuery: _angular_core.Signal<SdQuery<unknown>>;
316
327
  /** Receive an applied filter from the saved-filters menu — re-install bar state + trigger apply. */
317
328
  onApplyFilter(saved: SdSavedFilter): void;
318
329
  /** Show AND/OR segmented toggle (renders only when there are ≥2 filters). */
@@ -322,9 +333,15 @@ declare class SdQueryBar {
322
333
  /** Render the operator label on the chip face (default: hidden — operator only visible in popover). */
323
334
  readonly showOperatorOnChip: _angular_core.InputSignalWithTransform<boolean, unknown>;
324
335
  /** Composite payload — emitted whenever filters / logic / search change. */
325
- readonly queryChange: _angular_core.OutputEmitterRef<SdQuery<any>>;
336
+ readonly queryChange: _angular_core.OutputEmitterRef<SdQuery<unknown>>;
326
337
  /** Fires when the user presses "Áp dụng" inside a chip popover — host should reload data. */
327
- readonly apply: _angular_core.OutputEmitterRef<SdQuery<any>>;
338
+ readonly apply: _angular_core.OutputEmitterRef<SdQuery<unknown>>;
339
+ /** Placeholder của ô tìm kiếm tự do bên trái. */
340
+ readonly searchPlaceholder: _angular_core.Signal<string>;
341
+ /** Tooltip nút "+" khi consumer chưa khai `fields`. */
342
+ readonly noFieldsLabel: _angular_core.Signal<string>;
343
+ /** Tooltip nút "+" ở trạng thái bình thường. */
344
+ readonly addFilterLabel: _angular_core.Signal<string>;
328
345
  /** Map of `field.key` → `SdQueryField` for fast lookup from filters[]. */
329
346
  readonly resolvedAutoId: _angular_core.Signal<string | undefined>;
330
347
  readonly resolvedFields: _angular_core.Signal<SdQueryField[]>;
@@ -354,13 +371,34 @@ declare class SdQueryBar {
354
371
  * popover-mode chips read `multiple()` from the child popover directly.
355
372
  */
356
373
  multiple(op: Operator): boolean;
374
+ /**
375
+ * Stable track key of a filter row. Assigned lazily on first read.
376
+ *
377
+ * ⚠️ Hai ràng buộc với `filters`, đều là hợp đồng của consumer:
378
+ *
379
+ * 1. KHÔNG được chứa cùng một object `Filter` ở hai vị trí. Khoá theo identity nên hai vị trí sẽ
380
+ * cho hai track key trùng nhau và Angular ném NG0955. Đã thử khử trùng bằng hậu tố `$index`
381
+ * và HỎNG: Angular đánh giá biểu thức `track` trên CẢ collection cũ khi diff, nên một filter
382
+ * vừa bị xoá cho `indexOf === -1`, key đổi, và MỌI chip bị huỷ rồi dựng lại. Để Angular báo
383
+ * NG0955 là đúng — thông điệp của nó đã chỉ rõ vấn đề.
384
+ * 2. Object phải ỔN ĐỊNH giữa các lần change detection. Sinh lại object mới mỗi pass
385
+ * (vd `[option]="{ filters: buildFilters() }"`) sẽ khiến mọi chip nhận id mới mỗi pass và bị
386
+ * huỷ + dựng lại — tệ hơn cả `track $index` cũ.
387
+ */
388
+ rowId(filter: Filter): string;
357
389
  readonly iconFor: typeof sdQueryFieldIcon;
358
390
  /** Chip is "active" when it has a non-empty value OR a no-data operator (NULL/NOT_NULL). */
359
391
  isFilterActive(filter: Filter): boolean;
360
392
  /** Rendered value text on a chip. */
361
393
  chipValueText(filter: Filter): string;
362
394
  isNoDataOperator(op: Operator | string): boolean;
363
- readonly building: _angular_core.Signal<BuildingChip<any> | null>;
395
+ readonly building: _angular_core.Signal<BuildingChip<unknown> | null>;
396
+ /**
397
+ * Allowed operators of `field` — safe to call from a template binding: `sdQueryAllowedOperators`
398
+ * memo hoá theo object field nên ref trả về ổn định giữa các chu kỳ CD.
399
+ * why: `<sd-query-build-chip [allowedOperators]>` là OnPush; ref mới mỗi CD sẽ dirty child liên
400
+ * tục (bug class cấp-phát-mỗi-CD).
401
+ */
364
402
  allowedOperatorsFor(field: SdQueryField): Operator[];
365
403
  inlineAutoId(index: number, role: string): string;
366
404
  /** Entry point from the field picker — start building a chip for `field`. */
@@ -1,4 +1,3 @@
1
- import * as _sdcorejs_angular_components_query_builder from '@sdcorejs/angular/components/query-builder';
2
1
  import * as _angular_core from '@angular/core';
3
2
  import { Operator, DateRelative, Filter } from '@sdcorejs/utils/models';
4
3
 
@@ -22,17 +21,17 @@ interface SdQueryBuilderField {
22
21
  label: string;
23
22
  /** Field type — picks the default operator set + value editor control. */
24
23
  type: SdQueryBuilderFieldType;
25
- /** Material icon shown before the label in the field picker; falls back to `QB_TYPE_ICON[type]` then `'tune'`. */
24
+ /** Material icon shown before the label in the field picker; falls back to `SD_QB_TYPE_ICON[type]` then `'tune'`. */
26
25
  icon?: string;
27
- /** Override the allowed operator set (otherwise `QB_OPERATORS_BY_TYPE[type]`). */
26
+ /** Override the allowed operator set (otherwise `SD_QB_OPERATORS_BY_TYPE[type]`). */
28
27
  operators?: Operator[];
29
- /** Override the starting operator (otherwise `QB_DEFAULT_OPERATOR_BY_TYPE[type]`). */
28
+ /** Override the starting operator (otherwise `SD_QB_DEFAULT_OPERATOR_BY_TYPE[type]`). */
30
29
  defaultOperator?: Operator;
31
30
  /** Options for `type: 'values'` — the select list + display-label lookup. */
32
31
  values?: SdQueryBuilderFieldOption[];
33
- /** Label for the `true` branch of a boolean field (default `'Có'`). */
32
+ /** Label for the `true` branch of a boolean field (defaults to i18n `core.component.query-builder.boolean.true`). */
34
33
  trueLabel?: string;
35
- /** Label for the `false` branch of a boolean field (default `'Không'`). */
34
+ /** Label for the `false` branch of a boolean field (defaults to i18n `core.component.query-builder.boolean.false`). */
36
35
  falseLabel?: string;
37
36
  /** Lower bound for number / date value editors. */
38
37
  min?: number | string;
@@ -47,7 +46,7 @@ interface SdQueryBuilderOption {
47
46
  autoId?: string;
48
47
  fields: SdQueryBuilderField[];
49
48
  mode?: 'edit' | 'view';
50
- comparisonMode?: QbComparisonMode;
49
+ comparisonMode?: SdQbComparisonMode;
51
50
  disabled?: boolean;
52
51
  value?: Filter | null;
53
52
  filters?: Filter[];
@@ -56,22 +55,22 @@ interface SdQueryBuilderOption {
56
55
  onFiltersChange?: (filters: Filter[]) => void;
57
56
  onRootLogicChange?: (logic: 'AND' | 'OR') => void;
58
57
  }
59
- type QbNode = QbGroup | QbRule;
58
+ type SdQbNode = SdQbGroup | SdQbRule;
60
59
  /** Component-level capability for right-hand operands. */
61
- type QbComparisonMode = 'value-only' | 'value-or-field';
60
+ type SdQbComparisonMode = 'value-only' | 'value-or-field';
62
61
  /** Per-rule right-hand operand source. */
63
- type QbValueSource = 'literal' | 'field';
62
+ type SdQbValueSource = 'literal' | 'field';
64
63
  /** A logical group of nodes joined by AND / OR. Maps to `FilterAndOr`. */
65
- interface QbGroup {
64
+ interface SdQbGroup {
66
65
  id: string;
67
66
  kind: 'group';
68
67
  logic: 'AND' | 'OR';
69
- children: QbNode[];
68
+ children: SdQbNode[];
70
69
  /** UI-only: whether this group's "+" dropdown is open. */
71
70
  open?: boolean;
72
71
  }
73
72
  /** A single `field operator value` condition. Maps to a leaf `Filter`. */
74
- interface QbRule {
73
+ interface SdQbRule {
75
74
  id: string;
76
75
  kind: 'rule';
77
76
  field?: string;
@@ -79,94 +78,101 @@ interface QbRule {
79
78
  /** Single value, `{ from, to }` for BETWEEN, or an array for IN / NOT_IN. */
80
79
  value?: any;
81
80
  /** Internal UI state: literal input or a same-type field reference. */
82
- valueSource?: QbValueSource;
81
+ valueSource?: SdQbValueSource;
83
82
  /** Right-hand field key when `valueSource` is `'field'`. */
84
83
  compareField?: string;
85
84
  }
86
- /** Type guard — narrows a `QbNode` to a `QbGroup`. */
87
- declare function isQbGroup(node: QbNode): node is QbGroup;
88
- type QbTokenKind = 'field' | 'op' | 'value' | 'logic' | 'paren' | 'plain';
85
+ /** Type guard — narrows a `SdQbNode` to a `SdQbGroup`. */
86
+ declare function sdIsQbGroup(node: SdQbNode): node is SdQbGroup;
87
+ type SdQbTokenKind = 'field' | 'op' | 'value' | 'logic' | 'paren' | 'plain';
89
88
  /** One piece of the rendered raw query string, tagged for highlight styling. */
90
- interface QbToken {
89
+ interface SdQbToken {
91
90
  text: string;
92
- kind: QbTokenKind;
91
+ kind: SdQbTokenKind;
93
92
  }
94
93
  /** Allowed operators per field type — used when `field.operators` is not set. */
95
- declare const QB_OPERATORS_BY_TYPE: Record<SdQueryBuilderFieldType, Operator[]>;
94
+ declare const SD_QB_OPERATORS_BY_TYPE: Record<SdQueryBuilderFieldType, Operator[]>;
96
95
  /** Default operator when a rule is first created for a field. */
97
- declare const QB_DEFAULT_OPERATOR_BY_TYPE: Record<SdQueryBuilderFieldType, Operator>;
96
+ declare const SD_QB_DEFAULT_OPERATOR_BY_TYPE: Record<SdQueryBuilderFieldType, Operator>;
98
97
  /** Operators with no value payload — the value editor is hidden for these. */
99
- declare const QB_NO_DATA_OPERATORS: Operator[];
98
+ declare const SD_QB_NO_DATA_OPERATORS: Operator[];
100
99
  /** Operators whose value is an array — the value editor offers multi-select. */
101
- declare const QB_MULTI_OPERATORS: Operator[];
100
+ declare const SD_QB_MULTI_OPERATORS: Operator[];
102
101
  /** Operators allowed for `field` — explicit override wins, else the per-type set. */
103
- declare function qbAllowedOperators(field: SdQueryBuilderField | undefined): Operator[];
102
+ declare function sdQbAllowedOperators(field: SdQueryBuilderField | undefined): Operator[];
104
103
  /** Starting operator for a new rule on `field` — falls back to the per-type default. */
105
- declare function qbDefaultOperator(field: SdQueryBuilderField | undefined): Operator | undefined;
104
+ declare function sdQbDefaultOperator(field: SdQueryBuilderField | undefined): Operator | undefined;
106
105
  /** True when `op` is NULL / NOT_NULL (no value editor). */
107
- declare function qbIsNoDataOperator(op: Operator | undefined): boolean;
106
+ declare function sdQbIsNoDataOperator(op: Operator | undefined): boolean;
108
107
  /** True when `op` is IN / NOT_IN (array value). */
109
- declare function qbIsMultiOperator(op: Operator | undefined): boolean;
108
+ declare function sdQbIsMultiOperator(op: Operator | undefined): boolean;
110
109
  /** True when the operator accepts one right-hand operand, including a field reference. */
111
- declare function qbSupportsFieldCompareOperator(op: Operator | undefined): boolean;
110
+ declare function sdQbSupportsFieldCompareOperator(op: Operator | undefined): boolean;
112
111
  /**
113
112
  * Icon fallback per field type when `SdQueryBuilderField.icon` is not set.
114
113
  * Mirrors query-bar's `SD_QUERY_TYPE_ICON` so the two components read consistently,
115
114
  * but kept local so query-builder has no dependency on the query-bar package.
116
115
  */
117
- declare const QB_TYPE_ICON: Record<SdQueryBuilderFieldType, string>;
116
+ declare const SD_QB_TYPE_ICON: Record<SdQueryBuilderFieldType, string>;
118
117
  /**
119
118
  * Icon shown before a field in the field picker / selected trigger.
120
- * Priority: `field.icon` → `QB_TYPE_ICON[field.type]` → `'tune'` (default, like query-bar).
119
+ * Priority: `field.icon` → `SD_QB_TYPE_ICON[field.type]` → `'tune'` (default, like query-bar).
121
120
  */
122
- declare function qbFieldIcon(field: SdQueryBuilderField | undefined): string;
121
+ declare function sdQbFieldIcon(field: SdQueryBuilderField | undefined): string;
123
122
  /** Next stable node id with the given prefix. */
124
- declare function qbId(prefix?: string): string;
123
+ declare function sdQbId(prefix?: string): string;
125
124
  /** Build a fresh rule node (optionally pre-filled). */
126
- declare function qbNewRule(field?: string, operator?: Operator, value?: any, valueSource?: QbValueSource, compareField?: string): QbRule;
125
+ declare function sdQbNewRule(field?: string, operator?: Operator, value?: any, valueSource?: SdQbValueSource, compareField?: string): SdQbRule;
127
126
  /** Build a fresh group node. */
128
- declare function qbNewGroup(logic?: 'AND' | 'OR', children?: QbNode[]): QbGroup;
127
+ declare function sdQbNewGroup(logic?: 'AND' | 'OR', children?: SdQbNode[]): SdQbGroup;
129
128
  /** Offset unit for a relative date — re-exported from the utils `DateRelative` model. */
130
129
  type SdQbRelativeUnit = DateRelative['unit'];
131
130
  /** Offset direction for a relative date — re-exported from the utils `DateRelative` model. */
132
131
  type SdQbRelativeDirection = DateRelative['direction'];
133
132
  /** Sentinel held as a rule value (and emitted as `data`) for the "today" date mode. */
134
- declare const QB_TODAY = "TODAY";
133
+ declare const SD_QB_TODAY = "TODAY";
135
134
  /** The `'TODAY'` sentinel type (matches the utils `date-today` data literal). */
136
- type QbToday = typeof QB_TODAY;
135
+ type SdQbToday = typeof SD_QB_TODAY;
137
136
  /** Date value editor mode for a date/datetime rule (derived from the rule value). */
138
- type QbDateMode = 'absolute' | 'now' | 'relative';
137
+ type SdQbDateMode = 'absolute' | 'now' | 'relative';
139
138
  /** Type guard — narrows a rule value to a utils `DateRelative` (offset spec). */
140
- declare const qbIsRelativeDate: (v: any) => v is DateRelative;
139
+ declare const sdQbIsRelativeDate: (v: any) => v is DateRelative;
141
140
  /** Type guard — narrows a rule value to the `'TODAY'` sentinel ("now"/today mode). */
142
- declare function qbIsToday(v: any): v is QbToday;
141
+ declare function sdQbIsToday(v: any): v is SdQbToday;
143
142
  /** Starting relative value when a rule first switches to "relative" mode. */
144
- declare function qbDefaultRelative(): DateRelative;
143
+ declare function sdQbDefaultRelative(): DateRelative;
145
144
  /** One date-mode option — carries a Material icon shown in the dropdown + selected trigger. */
146
- interface QbDateModeOption {
147
- value: QbDateMode;
148
- display: string;
145
+ interface SdQbDateModeOption {
146
+ value: SdQbDateMode;
147
+ /** i18n key of the label — resolved at read time, NOT at module-eval time. */
148
+ labelKey: string;
149
149
  /** Material icon name (outlined set). */
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: QbDateModeOption[];
153
+ declare const SD_QB_DATE_MODES: SdQbDateModeOption[];
154
154
  /** One value-source option for field-to-field comparison UI. */
155
- interface QbValueSourceOption {
156
- value: QbValueSource;
157
- display: string;
155
+ interface SdQbValueSourceOption {
156
+ value: SdQbValueSource;
157
+ /** i18n key of the label — resolved at read time, NOT at module-eval time. */
158
+ labelKey: string;
158
159
  /** Material icon name (outlined set). */
159
160
  icon: string;
160
161
  }
161
162
  /** Stable option list for choosing between a literal value and another field. */
162
- declare const QB_VALUE_SOURCE_OPTIONS: QbValueSourceOption[];
163
- /** Stable combined direction×unit option list (token `'unit:direction'`). */
164
- declare const QB_RELATIVE_UNIT_OPTIONS: {
163
+ declare const SD_QB_VALUE_SOURCE_OPTIONS: SdQbValueSourceOption[];
164
+ /** One combined direction×unit option (token `'unit:direction'`). */
165
+ interface SdQbRelativeUnitOption {
165
166
  value: string;
166
- display: string;
167
- }[];
167
+ /** i18n key of the label — resolved at read time, NOT at module-eval time. */
168
+ labelKey: string;
169
+ }
170
+ /** Stable combined direction×unit option list (token `'unit:direction'`). */
171
+ declare const SD_QB_RELATIVE_UNIT_OPTIONS: SdQbRelativeUnitOption[];
172
+ /** i18n key of the combined `unit`×`direction` phrase for a relative-date offset. */
173
+ declare function qbRelativeLabelKey(unit: SdQbRelativeUnit, direction: SdQbRelativeDirection): string;
168
174
  /** Shared empty option array — stable ref for fallbacks (avoids per-call allocation). */
169
- declare const QB_EMPTY_OPTIONS: SdQueryBuilderFieldOption[];
175
+ declare const SD_QB_EMPTY_OPTIONS: SdQueryBuilderFieldOption[];
170
176
 
171
177
  /**
172
178
  * Visual filter / rule builder. Compose nested AND / OR groups of
@@ -184,7 +190,7 @@ declare class SdQueryBuilder {
184
190
  /** `'edit'` (default) = interactive tree · `'view'` = read-only raw-query string. */
185
191
  readonly mode: _angular_core.InputSignal<"edit" | "view">;
186
192
  /** `value-only` = literal operands only · `value-or-field` = each rule may compare against another field. */
187
- readonly comparisonMode: _angular_core.InputSignal<QbComparisonMode>;
193
+ readonly comparisonMode: _angular_core.InputSignal<SdQbComparisonMode>;
188
194
  /** Disable all editing controls. */
189
195
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
190
196
  /** Prefix for `data-autoid` on inner controls (E2E selectors). */
@@ -195,42 +201,64 @@ declare class SdQueryBuilder {
195
201
  readonly filters: _angular_core.ModelSignal<Filter[]>;
196
202
  /** Root group's logical connector. `[(rootLogic)]`. */
197
203
  readonly rootLogic: _angular_core.ModelSignal<"AND" | "OR">;
198
- readonly tree: _angular_core.Signal<QbGroup>;
204
+ readonly tree: _angular_core.Signal<SdQbGroup>;
199
205
  /** `field.key` → field, for fast lookup from a rule. */
200
206
  readonly resolvedFields: _angular_core.Signal<SdQueryBuilderField[]>;
201
207
  readonly resolvedMode: _angular_core.Signal<"edit" | "view">;
202
- readonly resolvedComparisonMode: _angular_core.Signal<QbComparisonMode>;
208
+ readonly resolvedComparisonMode: _angular_core.Signal<SdQbComparisonMode>;
203
209
  readonly resolvedDisabled: _angular_core.Signal<boolean>;
204
210
  readonly resolvedAutoId: _angular_core.Signal<string | undefined>;
205
211
  readonly fieldByKey: _angular_core.Signal<Record<string, SdQueryBuilderField>>;
206
212
  /** Stable option list for the date-mode select. */
207
- readonly dateModes: _sdcorejs_angular_components_query_builder.QbDateModeOption[];
213
+ readonly dateModes: _angular_core.Signal<{
214
+ display: string;
215
+ value: SdQbDateMode;
216
+ labelKey: string;
217
+ icon: string;
218
+ }[]>;
208
219
  /** Stable option list for the literal-vs-field operand select. */
209
- readonly valueSourceOptions: _sdcorejs_angular_components_query_builder.QbValueSourceOption[];
220
+ readonly valueSourceOptions: _angular_core.Signal<{
221
+ display: string;
222
+ value: SdQbValueSource;
223
+ labelKey: string;
224
+ icon: string;
225
+ }[]>;
210
226
  /** Stable combined unit×direction option list for the relative select. */
211
- readonly relativeUnitOptions: {
212
- value: string;
227
+ readonly relativeUnitOptions: _angular_core.Signal<{
213
228
  display: string;
214
- }[];
215
- /** View-mode token stream — recomputed from the emitted value. */
216
- readonly tokens: _angular_core.Signal<QbToken[]>;
229
+ value: string;
230
+ labelKey: string;
231
+ }[]>;
232
+ readonly selectFieldLabel: _angular_core.Signal<string>;
233
+ readonly valueLabel: _angular_core.Signal<string>;
234
+ readonly fromLabel: _angular_core.Signal<string>;
235
+ readonly toLabel: _angular_core.Signal<string>;
236
+ readonly addLabel: _angular_core.Signal<string>;
237
+ readonly addNodeLabel: _angular_core.Signal<string>;
238
+ readonly conditionLabel: _angular_core.Signal<string>;
239
+ readonly groupLabel: _angular_core.Signal<string>;
240
+ readonly removeGroupLabel: _angular_core.Signal<string>;
241
+ readonly removeConditionLabel: _angular_core.Signal<string>;
242
+ readonly emptyLabel: _angular_core.Signal<string>;
243
+ /** View-mode token stream — recomputed from the emitted value (and from the active language). */
244
+ readonly tokens: _angular_core.Signal<SdQbToken[]>;
217
245
  readonly isView: _angular_core.Signal<boolean>;
218
246
  /** Expose the type-guard to the template. */
219
- readonly isGroup: typeof isQbGroup;
247
+ readonly isGroup: typeof sdIsQbGroup;
220
248
  /** Resolve the leading icon for a field (own `icon` → per-type → `'tune'`) — used by the field picker. */
221
- readonly fieldIcon: typeof qbFieldIcon;
249
+ readonly fieldIcon: typeof sdQbFieldIcon;
222
250
  constructor();
223
251
  /** Switch a group's AND/OR connector and re-emit. No-op when disabled or unchanged. */
224
- setGroupLogic(group: QbGroup, logic: 'AND' | 'OR'): void;
252
+ setGroupLogic(group: SdQbGroup, logic: 'AND' | 'OR'): void;
225
253
  /** Open this group's "+" menu (closing any other open one). UI-only — does not emit. */
226
- toggleDropdown(group: QbGroup, event: Event): void;
254
+ toggleDropdown(group: SdQbGroup, event: Event): void;
227
255
  closeAllDropdowns(): void;
228
256
  /** Append a blank rule to `group`. */
229
- addRule(group: QbGroup): void;
257
+ addRule(group: SdQbGroup): void;
230
258
  /** Append a nested sub-group (seeded with one blank rule) to `group`. */
231
- addGroup(group: QbGroup): void;
259
+ addGroup(group: SdQbGroup): void;
232
260
  /** Remove the child at `index` from `parent` (a rule or a whole sub-group). */
233
- removeNode(parent: QbGroup, index: number): void;
261
+ removeNode(parent: SdQbGroup, index: number): void;
234
262
  /**
235
263
  * Point `rule` at a new field. Resets operator to the field's default and the value
236
264
  * to that operator's empty shape — the old operator/value rarely fit the new type.
@@ -239,52 +267,73 @@ declare class SdQueryBuilder {
239
267
  * @param key - the chosen field key (from the field picker). Swap-only: a null / undefined
240
268
  * key is a no-op — the field can be changed but never cleared (issue #2).
241
269
  */
242
- setField(rule: QbRule, key: any): void;
270
+ setField(rule: SdQbRule, key: any): void;
243
271
  /** Change `rule`'s operator and reshape its value to fit the new operator (array / range / none). */
244
- setOperator(rule: QbRule, op: Operator | undefined): void;
272
+ setOperator(rule: SdQbRule, op: Operator | undefined): void;
245
273
  /** Set a single-value rule's value (coercing numeric fields to `number`). */
246
- setScalar(rule: QbRule, raw: any): void;
274
+ setScalar(rule: SdQbRule, raw: any): void;
247
275
  /** Set the lower bound of a BETWEEN rule's `{ from, to }` value. */
248
- setBetweenFrom(rule: QbRule, raw: any): void;
276
+ setBetweenFrom(rule: SdQbRule, raw: any): void;
249
277
  /** Set the upper bound of a BETWEEN rule's `{ from, to }` value. */
250
- setBetweenTo(rule: QbRule, raw: any): void;
251
- setValueSource(rule: QbRule, source: unknown): void;
252
- setCompareField(rule: QbRule, key: any): void;
278
+ setBetweenTo(rule: SdQbRule, raw: any): void;
279
+ setValueSource(rule: SdQbRule, source: unknown): void;
280
+ setCompareField(rule: SdQbRule, key: any): void;
253
281
  /** The field metadata for a rule's current `field` key (or undefined if unset). */
254
- fieldOf(rule: QbRule): SdQueryBuilderField | undefined;
282
+ fieldOf(rule: SdQbRule): SdQueryBuilderField | undefined;
255
283
  /** Operators allowed for a rule, derived from its field's type / override. */
256
- allowedOperators(rule: QbRule): Operator[];
284
+ allowedOperators(rule: SdQbRule): Operator[];
257
285
  /** Whether to render the operator picker — hidden when only one operator is allowed. */
258
- showOperatorSelector(rule: QbRule): boolean;
259
- compareFields(rule: QbRule): SdQueryBuilderField[];
260
- canCompareWithField(rule: QbRule): boolean;
261
- showValueSourceSelector(rule: QbRule): boolean;
262
- valueSourceOf(rule: QbRule): QbValueSource;
263
- isFieldSource(rule: QbRule): boolean;
286
+ showOperatorSelector(rule: SdQbRule): boolean;
287
+ compareFields(rule: SdQbRule): SdQueryBuilderField[];
288
+ canCompareWithField(rule: SdQbRule): boolean;
289
+ showValueSourceSelector(rule: SdQbRule): boolean;
290
+ valueSourceOf(rule: SdQbRule): SdQbValueSource;
291
+ isFieldSource(rule: SdQbRule): boolean;
264
292
  /** True for NULL / NOT_NULL — the template then renders no value editor. */
265
293
  isNoData(op: Operator | undefined): boolean;
266
294
  /** True for IN / NOT_IN — the template then renders a multi-select value editor. */
267
295
  isMulti(op: Operator | undefined): boolean;
268
296
  /** `[true/false]` option list for a boolean field's value select (stable reference). */
269
297
  booleanItems(field: SdQueryBuilderField): SdQueryBuilderFieldOption[];
298
+ /**
299
+ * Option list cho field `type:'values'`.
300
+ *
301
+ * why: template cũ bind thẳng `[items]="fieldOf(rule)!.values || []"`. `values` là OPTIONAL trên
302
+ * `SdQueryBuilderField`, nên với field khai thiếu `values`, nhánh `|| []` cấp phát một mảng MỚI
303
+ * mỗi lần change detection chạy — đúng nguyên nhân OOM đã ghi ở `#booleanOptionsByKey`:
304
+ * `sd-select` có `toObservable(items)` → `markForCheck()` → CD mới → mảng mới → lặp vô hạn.
305
+ *
306
+ * why: KHÔNG memo hoá qua `computed<Map>` snapshot. `field.values` vốn ĐÃ là mảng của consumer
307
+ * nên tự nó ổn định; snapshot vào Map chỉ thêm một tầng cache không bao giờ invalidate khi
308
+ * consumer nạp option bất đồng bộ bằng cách gán tại chỗ (`fields[0].values = loaded`) — reference
309
+ * `fields` không đổi nên `computed` giữ nguyên list cũ vĩnh viễn. Chỉ nhánh RỖNG cần hằng số
310
+ * dùng chung để tránh literal mới mỗi CD.
311
+ */
312
+ valueItems(field: SdQueryBuilderField): SdQueryBuilderFieldOption[];
270
313
  /** Current date-value mode of a rule, derived from its value (no separate state). */
271
- dateMode(rule: QbRule): QbDateMode;
314
+ dateMode(rule: SdQbRule): SdQbDateMode;
272
315
  /** Switch a date/datetime rule's value mode, reseeding the value for the new mode. */
273
- setDateMode(rule: QbRule, mode: unknown): void;
316
+ setDateMode(rule: SdQbRule, mode: unknown): void;
274
317
  /** Read the offset amount of a relative rule (default 1). */
275
- relativeAmount(rule: QbRule): number;
318
+ relativeAmount(rule: SdQbRule): number;
276
319
  /** Set the offset amount (clamped to an integer >= 1). */
277
- setRelativeAmount(rule: QbRule, raw: any): void;
320
+ setRelativeAmount(rule: SdQbRule, raw: any): void;
278
321
  /** Read the `'unit:direction'` token of a relative rule (default `'day:previous'`). */
279
- relativeUnitDirValue(rule: QbRule): string;
322
+ relativeUnitDirValue(rule: SdQbRule): string;
280
323
  /** Set the offset unit + direction from a `'unit:direction'` token. */
281
- setRelativeUnitDir(rule: QbRule, token: unknown): void;
324
+ setRelativeUnitDir(rule: SdQbRule, token: unknown): void;
282
325
  /** Build a `data-autoid` for an inner control under this builder's `autoId` prefix. */
283
326
  autoIdFor(suffix: string): string;
284
327
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdQueryBuilder, never>;
285
328
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdQueryBuilder, "sd-query-builder", never, { "option": { "alias": "option"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "mode": { "alias": "mode"; "required": false; "isSignal": true; }; "comparisonMode": { "alias": "comparisonMode"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "autoId": { "alias": "autoId"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "filters": { "alias": "filters"; "required": false; "isSignal": true; }; "rootLogic": { "alias": "rootLogic"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "filters": "filtersChange"; "rootLogic": "rootLogicChange"; }, never, never, true, never>;
286
329
  }
287
330
 
331
+ /**
332
+ * Hàm dịch một key i18n, do component truyền xuống.
333
+ * why: `filterToTokens` là hàm thuần cấp module nên không inject `I18nService` được; nhận translator
334
+ * qua tham số vẫn giữ được tính thuần mà bỏ được chuỗi tiếng Việt hardcode trong chuỗi view.
335
+ */
336
+ type SdQbTranslate = (key: string, params?: Record<string, string | number>) => string;
288
337
  /**
289
338
  * Map the internal builder tree to the public `Filter` (the root is always a
290
339
  * `FilterAndOr`). Rules missing field / operator / value — and empty nested
@@ -293,28 +342,31 @@ declare class SdQueryBuilder {
293
342
  * @param group - the editable tree's root group.
294
343
  * @returns the canonical nested `Filter`, or `null` when no complete rule survives.
295
344
  */
296
- declare function treeToFilter(group: QbGroup): Filter | null;
345
+ declare function treeToFilter(group: SdQbGroup): Filter | null;
297
346
  /**
298
347
  * Inverse of {@link treeToFilter} — rebuild the editable tree from a `Filter` so a
299
348
  * consumer can seed `[value]`. A non-group (bare) filter is wrapped in an AND root;
300
349
  * `null` yields an empty AND root.
301
350
  *
302
351
  * @param filter - a `Filter` (group or leaf), or `null` / `undefined` for an empty tree.
303
- * @returns a fresh root `QbGroup` mirroring the filter's structure.
352
+ * @returns a fresh root `SdQbGroup` mirroring the filter's structure.
304
353
  */
305
- declare function filterToTree(filter: Filter | null | undefined): QbGroup;
354
+ declare function filterToTree(filter: Filter | null | undefined): SdQbGroup;
306
355
  /**
307
356
  * Render a `Filter` to a SQL-ish token stream for view mode. Field tokens use the
308
357
  * matching field's `label`; operators map to SQL syntax (`= != like between is null …`);
309
358
  * `and` / `or` are lowercase; nested multi-child groups are wrapped in parentheses.
310
359
  * Returns a token stream (not a string) so the template can wrap each piece in a
311
- * highlight `<span>` keyed by `QbToken.kind`.
360
+ * highlight `<span>` keyed by `SdQbToken.kind`.
312
361
  *
313
362
  * @param filter - the `Filter` to render, or `null` / `undefined`.
314
363
  * @param fields - field metadata, used to resolve each field key to its display label + value formatting.
364
+ * @param translate - i18n lookup for language-dependent value tokens (today / relative offsets /
365
+ * boolean labels). Optional so the serializer stays callable outside an Angular injection context;
366
+ * omitting it renders the raw i18n keys.
315
367
  * @returns the ordered tokens, or `[]` when `filter` is empty.
316
368
  */
317
- declare function filterToTokens(filter: Filter | null | undefined, fields: SdQueryBuilderField[]): QbToken[];
369
+ declare function filterToTokens(filter: Filter | null | undefined, fields: SdQueryBuilderField[], translate?: SdQbTranslate): SdQbToken[];
318
370
 
319
- export { QB_DATE_MODES, QB_DEFAULT_OPERATOR_BY_TYPE, QB_EMPTY_OPTIONS, QB_MULTI_OPERATORS, QB_NO_DATA_OPERATORS, QB_OPERATORS_BY_TYPE, QB_RELATIVE_UNIT_OPTIONS, QB_TODAY, QB_TYPE_ICON, QB_VALUE_SOURCE_OPTIONS, SdQueryBuilder, filterToTokens, filterToTree, isQbGroup, qbAllowedOperators, qbDefaultOperator, qbDefaultRelative, qbFieldIcon, qbId, qbIsMultiOperator, qbIsNoDataOperator, qbIsRelativeDate, qbIsToday, qbNewGroup, qbNewRule, qbSupportsFieldCompareOperator, treeToFilter };
320
- export type { QbComparisonMode, QbDateMode, QbDateModeOption, QbGroup, QbNode, QbRule, QbToday, QbToken, QbTokenKind, QbValueSource, QbValueSourceOption, SdQbRelativeDirection, SdQbRelativeUnit, SdQueryBuilderField, SdQueryBuilderFieldOption, SdQueryBuilderFieldType, SdQueryBuilderOption };
371
+ export { SD_QB_DATE_MODES, SD_QB_DEFAULT_OPERATOR_BY_TYPE, SD_QB_EMPTY_OPTIONS, SD_QB_MULTI_OPERATORS, SD_QB_NO_DATA_OPERATORS, SD_QB_OPERATORS_BY_TYPE, SD_QB_RELATIVE_UNIT_OPTIONS, SD_QB_TODAY, SD_QB_TYPE_ICON, SD_QB_VALUE_SOURCE_OPTIONS, SdQueryBuilder, filterToTokens, filterToTree, qbRelativeLabelKey, sdIsQbGroup, sdQbAllowedOperators, sdQbDefaultOperator, sdQbDefaultRelative, sdQbFieldIcon, sdQbId, sdQbIsMultiOperator, sdQbIsNoDataOperator, sdQbIsRelativeDate, sdQbIsToday, sdQbNewGroup, sdQbNewRule, sdQbSupportsFieldCompareOperator, treeToFilter };
372
+ export type { SdQbComparisonMode, SdQbDateMode, SdQbDateModeOption, SdQbGroup, SdQbNode, SdQbRelativeDirection, SdQbRelativeUnit, SdQbRelativeUnitOption, SdQbRule, SdQbToday, SdQbToken, SdQbTokenKind, SdQbTranslate, SdQbValueSource, SdQbValueSourceOption, SdQueryBuilderField, SdQueryBuilderFieldOption, SdQueryBuilderFieldType, SdQueryBuilderOption };
@@ -10,8 +10,11 @@ declare class SdSection {
10
10
  collapsed: _angular_core.ModelSignal<boolean>;
11
11
  collapsible: _angular_core.InputSignalWithTransform<boolean, unknown>;
12
12
  hideHeader: _angular_core.InputSignalWithTransform<boolean, unknown>;
13
+ /** Id của vùng body, để header `aria-controls` trỏ tới khi section collapsible. */
14
+ readonly bodyId: string;
13
15
  constructor();
14
16
  toggleCollapse: () => void;
17
+ onHeaderKeydown: (event: KeyboardEvent) => void;
15
18
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSection, never>;
16
19
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSection, "sd-section", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "subTitle": { "alias": "subTitle"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "iconColor": { "alias": "iconColor"; "required": false; "isSignal": true; }; "collapsed": { "alias": "collapsed"; "required": false; "isSignal": true; }; "collapsible": { "alias": "collapsible"; "required": false; "isSignal": true; }; "hideHeader": { "alias": "hideHeader"; "required": false; "isSignal": true; }; }, { "collapsed": "collapsedChange"; }, never, ["[sdHeaderLeft]", "[sdHeaderRight]", "*", "[sdFooterLeft]", "[sdFooterRight]"], true, never>;
17
20
  }