@sdcorejs/angular 21.1.6 → 21.2.1

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 (213) 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/fesm2022/sdcorejs-angular-components-anchor.mjs +37 -13
  6. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  7. package/fesm2022/sdcorejs-angular-components-api-contract-builder.mjs +3409 -0
  8. package/fesm2022/sdcorejs-angular-components-api-contract-builder.mjs.map +1 -0
  9. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +2 -2
  10. package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
  11. package/fesm2022/sdcorejs-angular-components-badge.mjs +27 -2
  12. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  13. package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
  14. package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
  15. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +1 -1
  16. package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -1
  17. package/fesm2022/sdcorejs-angular-components-code-editor.mjs +3 -3
  18. package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -1
  19. package/fesm2022/sdcorejs-angular-components-data-state.mjs +3 -3
  20. package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -1
  21. package/fesm2022/sdcorejs-angular-components-editor.mjs +2 -2
  22. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  23. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +324 -192
  24. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  25. package/fesm2022/sdcorejs-angular-components-history.mjs +4 -4
  26. package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -1
  27. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +13 -5
  28. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  29. package/fesm2022/sdcorejs-angular-components-inform.mjs +3 -3
  30. package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
  31. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +164 -8
  32. package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
  33. package/fesm2022/sdcorejs-angular-components-modal.mjs +30 -18
  34. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  35. package/fesm2022/sdcorejs-angular-components-operator.mjs +2 -2
  36. package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
  37. package/fesm2022/sdcorejs-angular-components-org-chart.mjs +60 -13
  38. package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
  39. package/fesm2022/sdcorejs-angular-components-preview.mjs +27 -17
  40. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  41. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +192 -30
  42. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  43. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +187 -127
  44. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  45. package/fesm2022/sdcorejs-angular-components-section.mjs +33 -2
  46. package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
  47. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +83 -24
  48. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  49. package/fesm2022/sdcorejs-angular-components-splitter.mjs +57 -21
  50. package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -1
  51. package/fesm2022/sdcorejs-angular-components-stepper.mjs +2 -2
  52. package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -1
  53. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +68 -20
  54. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  55. package/fesm2022/sdcorejs-angular-components-tab.mjs +3 -2
  56. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  57. package/fesm2022/sdcorejs-angular-components-table.mjs +556 -268
  58. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  59. package/fesm2022/sdcorejs-angular-components-tree.mjs +80 -17
  60. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  61. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +48 -13
  62. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  63. package/fesm2022/sdcorejs-angular-components.mjs +7 -1
  64. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  65. package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-directives.mjs +45 -8
  67. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +40 -29
  69. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +5 -5
  71. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +67 -50
  73. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-chip.mjs +57 -43
  75. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +232 -61
  77. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-date.mjs +96 -24
  79. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +131 -27
  81. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  82. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +40 -16
  83. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -1
  84. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +16 -5
  85. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  86. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +24 -9
  87. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-forms-input.mjs +58 -10
  89. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  90. package/fesm2022/sdcorejs-angular-forms-models.mjs +227 -6
  91. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  92. package/fesm2022/sdcorejs-angular-forms-radio.mjs +4 -4
  93. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  94. package/fesm2022/sdcorejs-angular-forms-select.mjs +136 -38
  95. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  96. package/fesm2022/sdcorejs-angular-forms-switch.mjs +18 -3
  97. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  98. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +51 -62
  99. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  100. package/fesm2022/sdcorejs-angular-forms-time-range.mjs +57 -12
  101. package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -1
  102. package/fesm2022/sdcorejs-angular-forms-time.mjs +16 -5
  103. package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -1
  104. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +100 -9
  105. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -1
  106. package/fesm2022/sdcorejs-angular-forms.mjs +91 -46
  107. package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
  108. package/fesm2022/sdcorejs-angular-handlers.mjs +18 -3
  109. package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -1
  110. package/fesm2022/sdcorejs-angular-i18n.mjs +895 -68
  111. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  112. package/fesm2022/sdcorejs-angular-interceptors.mjs +87 -29
  113. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  114. package/fesm2022/sdcorejs-angular-modules-auth.mjs +25 -15
  115. package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -1
  116. package/fesm2022/sdcorejs-angular-modules-icon.mjs +2 -2
  117. package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
  118. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +32 -3
  119. package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -1
  120. package/fesm2022/sdcorejs-angular-modules-layout.mjs +342 -111
  121. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  122. package/fesm2022/sdcorejs-angular-modules-permission.mjs +177 -40
  123. package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -1
  124. package/fesm2022/sdcorejs-angular-pipes.mjs +62 -28
  125. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  126. package/fesm2022/sdcorejs-angular-services-api.mjs +123 -13
  127. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  128. package/fesm2022/sdcorejs-angular-services-cache.mjs +53 -3
  129. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  130. package/fesm2022/sdcorejs-angular-services-confirm.mjs +25 -73
  131. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  132. package/fesm2022/sdcorejs-angular-services-excel.mjs +12 -10
  133. package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -1
  134. package/fesm2022/sdcorejs-angular-services-loading.mjs +75 -84
  135. package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
  136. package/fesm2022/sdcorejs-angular-services-notify.mjs +46 -5
  137. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  138. package/fesm2022/sdcorejs-angular-services-storage.mjs +4 -0
  139. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  140. package/fesm2022/sdcorejs-angular-services.mjs +0 -1
  141. package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
  142. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +225 -80
  143. package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -1
  144. package/fesm2022/sdcorejs-angular-utilities-models.mjs +1 -63
  145. package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -1
  146. package/fesm2022/sdcorejs-angular.mjs +17 -10
  147. package/fesm2022/sdcorejs-angular.mjs.map +1 -1
  148. package/package.json +36 -25
  149. package/types/sdcorejs-angular-components-anchor.d.ts +3 -1
  150. package/types/sdcorejs-angular-components-api-contract-builder.d.ts +694 -0
  151. package/types/sdcorejs-angular-components-badge.d.ts +2 -0
  152. package/types/sdcorejs-angular-components-ckeditor-styles.d.ts +1 -1
  153. package/types/sdcorejs-angular-components-form-generic.d.ts +44 -33
  154. package/types/sdcorejs-angular-components-import-excel.d.ts +1 -0
  155. package/types/sdcorejs-angular-components-mini-editor.d.ts +1 -1
  156. package/types/sdcorejs-angular-components-modal-resizable.d.ts +92 -0
  157. package/types/sdcorejs-angular-components-modal.d.ts +3 -2
  158. package/types/sdcorejs-angular-components-org-chart.d.ts +6 -0
  159. package/types/sdcorejs-angular-components-preview.d.ts +1 -0
  160. package/types/sdcorejs-angular-components-query-bar.d.ts +55 -17
  161. package/types/sdcorejs-angular-components-query-builder.d.ts +150 -98
  162. package/types/sdcorejs-angular-components-section.d.ts +5 -0
  163. package/types/sdcorejs-angular-components-tab-router.d.ts +19 -19
  164. package/types/sdcorejs-angular-components-table.d.ts +251 -109
  165. package/types/sdcorejs-angular-components-tree.d.ts +48 -30
  166. package/types/sdcorejs-angular-components-upload-file.d.ts +6 -3
  167. package/types/sdcorejs-angular-components.d.ts +7 -1
  168. package/types/sdcorejs-angular-configurations.d.ts +1 -2
  169. package/types/sdcorejs-angular-forms-autocomplete.d.ts +5 -2
  170. package/types/sdcorejs-angular-forms-chip-calendar.d.ts +10 -0
  171. package/types/sdcorejs-angular-forms-date-range.d.ts +14 -2
  172. package/types/sdcorejs-angular-forms-date.d.ts +13 -2
  173. package/types/sdcorejs-angular-forms-datetime.d.ts +13 -2
  174. package/types/sdcorejs-angular-forms-entity-picker.d.ts +9 -3
  175. package/types/sdcorejs-angular-forms-input-color.d.ts +4 -0
  176. package/types/sdcorejs-angular-forms-input-number.d.ts +3 -0
  177. package/types/sdcorejs-angular-forms-input.d.ts +3 -0
  178. package/types/sdcorejs-angular-forms-models.d.ts +119 -4
  179. package/types/sdcorejs-angular-forms-select.d.ts +27 -4
  180. package/types/sdcorejs-angular-forms-switch.d.ts +7 -1
  181. package/types/sdcorejs-angular-forms-textarea.d.ts +5 -3
  182. package/types/sdcorejs-angular-forms-time-range.d.ts +22 -1
  183. package/types/sdcorejs-angular-forms-tree-select.d.ts +36 -5
  184. package/types/sdcorejs-angular-forms.d.ts +22 -13
  185. package/types/sdcorejs-angular-i18n.d.ts +175 -16
  186. package/types/sdcorejs-angular-interceptors.d.ts +13 -3
  187. package/types/sdcorejs-angular-modules-auth.d.ts +1 -1
  188. package/types/sdcorejs-angular-modules-keycloak.d.ts +1 -0
  189. package/types/sdcorejs-angular-modules-layout.d.ts +94 -28
  190. package/types/sdcorejs-angular-modules-permission.d.ts +66 -4
  191. package/types/sdcorejs-angular-pipes.d.ts +27 -5
  192. package/types/sdcorejs-angular-services-api.d.ts +21 -1
  193. package/types/sdcorejs-angular-services-cache.d.ts +11 -1
  194. package/types/sdcorejs-angular-services-notify.d.ts +1 -1
  195. package/types/sdcorejs-angular-services.d.ts +0 -1
  196. package/types/sdcorejs-angular-utilities-extensions.d.ts +83 -61
  197. package/types/sdcorejs-angular-utilities-models.d.ts +2 -76
  198. package/types/sdcorejs-angular.d.ts +11 -2
  199. package/fesm2022/sdcorejs-angular-components-base.mjs +0 -23
  200. package/fesm2022/sdcorejs-angular-components-base.mjs.map +0 -1
  201. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +0 -5038
  202. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +0 -1
  203. package/fesm2022/sdcorejs-angular-models.mjs +0 -6
  204. package/fesm2022/sdcorejs-angular-models.mjs.map +0 -1
  205. package/fesm2022/sdcorejs-angular-services-docx.mjs +0 -291
  206. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +0 -1
  207. package/fesm2022/sdcorejs-angular-services-license.mjs +0 -97
  208. package/fesm2022/sdcorejs-angular-services-license.mjs.map +0 -1
  209. package/types/sdcorejs-angular-components-base.d.ts +0 -11
  210. package/types/sdcorejs-angular-components-document-builder.d.ts +0 -252
  211. package/types/sdcorejs-angular-models.d.ts +0 -2
  212. package/types/sdcorejs-angular-services-docx.d.ts +0 -27
  213. package/types/sdcorejs-angular-services-license.d.ts +0 -12
@@ -46,7 +46,7 @@ type SdCustomValidator = (value: any) => string | Promise<string>;
46
46
  declare const SdInlineErrorValidator: ValidatorFn;
47
47
  declare const HandleSdCustomValidator: (func: SdCustomValidator) => AsyncValidatorFn;
48
48
 
49
- interface SdSelectionData<T = any> {
49
+ interface SdSelectionData<T = unknown> {
50
50
  multiple?: boolean;
51
51
  values: any[];
52
52
  selectedItems: T[];
@@ -60,7 +60,7 @@ interface SdSearchReq<TData extends string | number = string> {
60
60
  searchFields?: string[];
61
61
  value?: TData | TData[];
62
62
  }
63
- type SdSearch<T = any> = (args: SdSearchReq) => Promise<T[]>;
63
+ type SdSearch<T = unknown> = (args: SdSearchReq) => Promise<T[]>;
64
64
 
65
65
  interface SdFormControlSnapshot<T> {
66
66
  value: T | undefined;
@@ -122,6 +122,109 @@ interface SdViewedInlineApi {
122
122
  */
123
123
  declare function sdViewedInline(viewed: Signal<SdViewed>, open?: () => void, disabled?: Signal<boolean>): SdViewedInlineApi;
124
124
 
125
+ /**
126
+ * Output serialization strategy for the temporal form controls (`<sd-date>`, `<sd-datetime>`,
127
+ * `<sd-date-range>`).
128
+ *
129
+ * This names how a committed value leaves the component — through `model` / `modelChange` /
130
+ * `sdChange` and the registered `FormGroup` field. It does **not** touch what the field displays,
131
+ * and it is **not** an Angular input-coercion `transform`.
132
+ */
133
+ type SdTemporalValueTransform = 'ISOString' | 'UTCString';
134
+ /** Every supported strategy, derived from the strategy map so the two can never drift. */
135
+ declare const SD_TEMPORAL_VALUE_TRANSFORMS: readonly SdTemporalValueTransform[];
136
+ declare function sdIsTemporalValueTransform(value: unknown): value is SdTemporalValueTransform;
137
+ /**
138
+ * Serializes a committed value with the active strategy.
139
+ *
140
+ * Returns `null` for anything that is not a usable `Date`, so an invalid value can never reach a
141
+ * serializer and produce the string `"Invalid Date"`. Callers treat `null` as "keep the existing
142
+ * representation".
143
+ */
144
+ declare function sdSerializeTemporalValue(value: Date | null | undefined, transform: SdTemporalValueTransform | null | undefined): string | null;
145
+ /** Local midnight of the given day. Date-only controls serialize this instant, never the raw value. */
146
+ declare function sdLocalStartOfDay(value: Date): Date;
147
+ /**
148
+ * Parses the wire formats these transforms emit, so a component can read back its own output.
149
+ *
150
+ * Deliberately narrow: only ISO 8601 and the RFC-1123 shape `toUTCString()` produces are accepted.
151
+ * Handing the whole job to `new Date(text)` would make every loosely date-shaped string parse
152
+ * differently per browser, and would swallow the legacy canonical formats the components already
153
+ * parse with their own strict parsers. Returns `null` when the text is not one of these.
154
+ */
155
+ declare function sdParseTransformedTemporal(value: unknown): Date | null;
156
+
157
+ interface ɵSdModelFacingControlOptions<TModel> {
158
+ /** Whether the model-facing control should be the one registered in the parent form. */
159
+ readonly active: Signal<boolean>;
160
+ /** The component's public model. */
161
+ readonly model: Signal<TModel>;
162
+ /** Applies an external write that arrived through the registered control. */
163
+ readonly writeModel: (value: TModel) => void;
164
+ /** The internal UI control whose validity, disabled and interaction state must be mirrored. */
165
+ readonly source: Signal<AbstractControl>;
166
+ /** Compares two model values; defaults to `Object.is`. */
167
+ readonly modelEquals?: (left: TModel, right: TModel) => boolean;
168
+ }
169
+ interface ɵSdModelFacingControl<TModel> {
170
+ /** The control itself. Holds the public model value, never the editor representation. */
171
+ readonly control: SdFormControl;
172
+ /** Feed straight into `ɵsdFormControlConnector`'s `registeredControl`. */
173
+ readonly registered: Signal<AbstractControl | null>;
174
+ }
175
+ /**
176
+ * A second control that carries the **public model** so it can be registered in the parent form in
177
+ * place of the editor-facing control.
178
+ *
179
+ * why: `<sd-date>` and friends bind their control directly to the Material editor, so that control
180
+ * necessarily holds a `Date` or a display string. That is invisible until `transform` is set — at
181
+ * which point the consumer is told `form.get(name).value` equals `model`, and finding a raw `Date`
182
+ * there instead makes the promise false. Rather than reshaping the editor binding (which would
183
+ * change behaviour for every existing consumer), this mirrors the model into a control of its own
184
+ * and hands *that* one to the form.
185
+ *
186
+ * Both directions are wired, and neither can feed back on the other:
187
+ * - model changes are pushed in with `emitEvent: false`, so they raise no `valueChanges`;
188
+ * - a write that arrives on this control goes to `writeModel`, exactly like a write on the editor
189
+ * control would, so `modelChange` / `sdChange` still fire once.
190
+ *
191
+ * Validity, disabled and touched/dirty are mirrored from `source`, so registering this control does
192
+ * not quietly drop the editor's validators (min/max, parse errors, required) from the parent form.
193
+ *
194
+ * Must be called from an injection context.
195
+ */
196
+ declare function ɵsdModelFacingControl<TModel>(options: ɵSdModelFacingControlOptions<TModel>): ɵSdModelFacingControl<TModel>;
197
+
198
+ /**
199
+ * @internal Macrotask timers owned by a component/directive injector.
200
+ *
201
+ * Every pending handle is cleared when the host is destroyed, so a deferred focus,
202
+ * panel-open or emit can never run against a torn-down view.
203
+ */
204
+ interface ɵSdTimerScope {
205
+ /**
206
+ * `setTimeout` with the same observable timing, minus the leak: the handle is tracked
207
+ * and cleared on destroy. Scheduling after destroy is a no-op.
208
+ */
209
+ schedule(handler: () => void, delayMs?: number): void;
210
+ /** Cancels every pending timer without waiting for destroy. */
211
+ clear(): void;
212
+ /** Number of timers still pending. Test/diagnostics only. */
213
+ readonly pending: number;
214
+ }
215
+ /**
216
+ * @internal Creates a destroy-scoped timer bag. MUST be called from an injection context
217
+ * (class field initializer or constructor) because it resolves `DestroyRef`.
218
+ *
219
+ * why: gần như mọi form control đều hoãn focus / mở panel bằng `setTimeout(..., 100)` để chờ
220
+ * Material dựng xong DOM. Handle không được giữ lại nên callback vẫn chạy sau khi host view đã
221
+ * destroy — route đổi nhanh hoặc chip bị gỡ giữa lúc focus là đủ để `detectChanges()` ném
222
+ * `ViewDestroyedError`, hoặc để một output bắn ra sau khi consumer đã unsubscribe. Gom vào một
223
+ * scope duy nhất để nơi dùng chỉ cần đổi `setTimeout(fn, ms)` → `#timers.schedule(fn, ms)`,
224
+ * KHÔNG đổi độ trễ (đây là fix vòng đời, không phải fix hành vi).
225
+ */
226
+ declare function ɵsdTimerScope(): ɵSdTimerScope;
227
+
125
228
  type ɵSdFormControlParent = FormGroup | NgForm | {
126
229
  readonly form: unknown;
127
230
  } | null | undefined;
@@ -132,6 +235,18 @@ interface ɵSdFormControlConnectorBaseOptions<TControl> {
132
235
  readonly name: Signal<string | null | undefined>;
133
236
  /** Canonical control registered in the parent form. */
134
237
  readonly control: Signal<AbstractControl<TControl>>;
238
+ /**
239
+ * Control to register in the parent form **instead of** `control`, when the two must differ.
240
+ *
241
+ * why: `<sd-date>` / `<sd-datetime>` / `<sd-date-range>` bind `control` straight to the Material
242
+ * editor, so it necessarily holds the editor's own representation (a `Date`, or the display
243
+ * string) — not the public model. That is fine until `transform` is set, at which point the
244
+ * consumer is promised that `form.get(name).value` matches `model` and the `sdChange` payload.
245
+ * Yielding a model-facing control here moves only the *registration*; validators, disabled, state
246
+ * and the model binding all stay on `control`, so a `null`/absent signal keeps today's behaviour
247
+ * exactly. The component owning both controls is responsible for mirroring value and validity.
248
+ */
249
+ readonly registeredControl?: Signal<AbstractControl | null | undefined>;
135
250
  readonly validators?: Signal<ValidatorFn | readonly ValidatorFn[] | null | undefined>;
136
251
  readonly asyncValidators?: Signal<AsyncValidatorFn | readonly AsyncValidatorFn[] | null | undefined>;
137
252
  /** Adds/removes Validators.required while preserving validators supplied above. */
@@ -228,5 +343,5 @@ declare class SdStrictDateFnsAdapter extends DateFnsAdapter {
228
343
  /** `provideDateFnsAdapter` + ép dùng adapter parse chặt ở trên. */
229
344
  declare function provideSdStrictDateFnsAdapter(formats: MatDateFormats): Provider[];
230
345
 
231
- export { HandleSdCustomValidator, SD_FORM_CONFIGURATION, SdFormControl, SdInlineErrorValidator, SdStrictDateFnsAdapter, provideSdStrictDateFnsAdapter, sdFormControlState, sdViewedInline, sdViewedTransform, ɵsdCoerceFormGroup, ɵsdFormControlConnector };
232
- export type { ISdFormConfiguration, SdCustomValidator, SdFormControlSnapshot, SdSearch, SdSearchReq, SdSelectionData, SdViewed, SdViewedInlineApi, SdViewedInput, ɵSdFormControlConnector, ɵSdFormControlConnectorOptions, ɵSdFormControlConnectorState, ɵSdFormControlParent };
346
+ export { HandleSdCustomValidator, SD_FORM_CONFIGURATION, SD_TEMPORAL_VALUE_TRANSFORMS, SdFormControl, SdInlineErrorValidator, SdStrictDateFnsAdapter, provideSdStrictDateFnsAdapter, sdFormControlState, sdIsTemporalValueTransform, sdLocalStartOfDay, sdParseTransformedTemporal, sdSerializeTemporalValue, sdViewedInline, sdViewedTransform, ɵsdCoerceFormGroup, ɵsdFormControlConnector, ɵsdModelFacingControl, ɵsdTimerScope };
347
+ export type { ISdFormConfiguration, SdCustomValidator, SdFormControlSnapshot, SdSearch, SdSearchReq, SdSelectionData, SdTemporalValueTransform, SdViewed, SdViewedInlineApi, SdViewedInput, ɵSdFormControlConnector, ɵSdFormControlConnectorOptions, ɵSdFormControlConnectorState, ɵSdFormControlParent, ɵSdModelFacingControl, ɵSdModelFacingControlOptions, ɵSdTimerScope };
@@ -25,6 +25,9 @@ declare class SdSelectFooterActionDirective {
25
25
  declare class SdSelect<T extends object | string | number = Record<string, unknown>> implements OnInit {
26
26
  #private;
27
27
  id: string;
28
+ /** why: id ổn định của <mat-error> để control trỏ `aria-describedby` sang — thông báo lỗi
29
+ * phải đọc được từ chính control, không chỉ hiện ra màn hình. */
30
+ readonly errorId: string;
28
31
  matInputRef: Signal<MatInput | undefined>;
29
32
  selectRef: Signal<MatSelect | undefined>;
30
33
  sdLabelTemplate: Signal<TemplateRef<any> | undefined>;
@@ -62,8 +65,8 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
62
65
  label: _angular_core.InputSignal<string | undefined>;
63
66
  helperText: _angular_core.InputSignal<string | undefined>;
64
67
  placeholder: _angular_core.InputSignal<string | undefined>;
65
- valueField: _angular_core.InputSignal<T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string>;
66
- displayField: _angular_core.InputSignal<T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string>;
68
+ valueField: _angular_core.InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
69
+ displayField: _angular_core.InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
67
70
  disabledField: _angular_core.InputSignal<"" | (T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string)>;
68
71
  cacheChecksum: _angular_core.InputSignal<any>;
69
72
  limit: _angular_core.InputSignal<number>;
@@ -75,6 +78,11 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
75
78
  /** Display mode: `false` edit · `true` static view · `'inline'` view + click-to-edit (bare editor). */
76
79
  viewed: _angular_core.InputSignalWithTransform<SdViewed, SdViewedInput>;
77
80
  multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
81
+ /**
82
+ * Hiện option "Tất cả" đầu panel (chỉ multiple + items là mảng tĩnh/Signal — ẩn với
83
+ * SdSearch lazy vì dataset không xác định). Opt-in, default `false`.
84
+ */
85
+ showSelectAll: _angular_core.InputSignalWithTransform<boolean, unknown>;
78
86
  /**
79
87
  * Whether the `viewed='inline'` text face shows a hover clear-× to empty the value.
80
88
  * Default `true`. Set `false` where the HOST owns removal (e.g. `<sd-query-bar>` chips,
@@ -99,7 +107,7 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
99
107
  items: _angular_core.InputSignal<SdSearch | T[] | Signal<T[]> | null | undefined>;
100
108
  valueModel: _angular_core.ModelSignal<string | number | boolean | (string | number)[] | null | undefined>;
101
109
  sdChange: _angular_core.OutputEmitterRef<any>;
102
- sdSelection: _angular_core.OutputEmitterRef<SdSelectionData<any>>;
110
+ sdSelection: _angular_core.OutputEmitterRef<SdSelectionData<unknown>>;
103
111
  formControl: SdFormControl;
104
112
  inputControl: FormControl<string | null>;
105
113
  loading: _angular_core.WritableSignal<boolean>;
@@ -120,6 +128,15 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
120
128
  normalizedValue: Signal<string | number | boolean | (string | number | boolean)[] | null | undefined>;
121
129
  filtered: Signal<boolean>;
122
130
  delayTime: Signal<0 | 500>;
131
+ /**
132
+ * Scope của "Tất cả": item enabled khớp search text hiện tại, tính trên MẢNG NGUỒN
133
+ * `actualItems()`.
134
+ */
135
+ readonly selectAllScope: Signal<T[]>;
136
+ /** Row "Tất cả" chỉ render khi opt-in + multiple + items tĩnh + scope có item để thao tác. */
137
+ readonly selectAllVisible: Signal<boolean>;
138
+ /** Trạng thái checkbox "Tất cả", tính trên items ENABLED trong scope (item disabled bỏ qua). */
139
+ readonly selectAllState: Signal<"checked" | "indeterminate" | "unchecked">;
123
140
  itemValue: (item: T) => unknown;
124
141
  itemDisplay: (item: T) => string;
125
142
  itemDisabled: (item: T) => boolean;
@@ -130,6 +147,12 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
130
147
  constructor();
131
148
  ngOnInit(): void;
132
149
  onSelectionChange: (change: MatSelectChange) => void;
150
+ /**
151
+ * Toggle "Tất cả" theo scope hiện tại (items enabled khớp search):
152
+ * - Đang `checked` → BỎ chọn các value trong scope (giữ value ngoài scope, kể cả item disabled đã chọn).
153
+ * - Ngược lại → CHỌN THÊM toàn bộ scope, union với selection hiện có (additive khi đang search).
154
+ */
155
+ toggleSelectAll: () => void;
133
156
  reValidate: () => void;
134
157
  clear: ($event?: any) => void;
135
158
  onClick: () => void;
@@ -140,7 +163,7 @@ declare class SdSelect<T extends object | string | number = Record<string, unkno
140
163
  open: () => void;
141
164
  onOpenedChange: (isOpened: boolean) => void;
142
165
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSelect<any>, never>;
143
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSelect<any>, "sd-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": true; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": true; "isSignal": true; }; "disabledField": { "alias": "disabledField"; "required": false; "isSignal": true; }; "cacheChecksum": { "alias": "cacheChecksum"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; "minWidthPanel": { "alias": "minWidthPanel"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; "inlineError": { "alias": "inlineError"; "required": false; "isSignal": true; }; "appearanceInput": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "valueModel": { "alias": "model"; "required": false; "isSignal": true; }; }, { "valueModel": "modelChange"; "sdChange": "sdChange"; "sdSelection": "sdSelection"; }, ["sdLabelTemplate", "sdValueTemplate", "sdSelectedTemplate", "itemDef", "sdViewDef", "footerActions"], ["[sdLabel]"], true, never>;
166
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdSelect<any>, "sd-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": false; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": false; "isSignal": true; }; "disabledField": { "alias": "disabledField"; "required": false; "isSignal": true; }; "cacheChecksum": { "alias": "cacheChecksum"; "required": false; "isSignal": true; }; "limit": { "alias": "limit"; "required": false; "isSignal": true; }; "hyperlink": { "alias": "hyperlink"; "required": false; "isSignal": true; }; "minWidthPanel": { "alias": "minWidthPanel"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "showSelectAll": { "alias": "showSelectAll"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; "inlineError": { "alias": "inlineError"; "required": false; "isSignal": true; }; "appearanceInput": { "alias": "appearance"; "required": false; "isSignal": true; }; "floatLabel": { "alias": "floatLabel"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "valueModel": { "alias": "model"; "required": false; "isSignal": true; }; }, { "valueModel": "modelChange"; "sdChange": "sdChange"; "sdSelection": "sdSelection"; }, ["sdLabelTemplate", "sdValueTemplate", "sdSelectedTemplate", "itemDef", "sdViewDef", "footerActions"], ["[sdLabel]"], true, never>;
144
167
  }
145
168
 
146
169
  export { SdSelect, SdSelectFooterActionDirective };
@@ -1,6 +1,7 @@
1
+ import * as _sdcorejs_angular_forms_models from '@sdcorejs/angular/forms/models';
2
+ import { SdFormControl, ɵSdFormControlParent as _SdFormControlParent, SdViewed, SdViewedInput } from '@sdcorejs/angular/forms/models';
1
3
  import * as _angular_core from '@angular/core';
2
4
  import { OnInit, OnDestroy } from '@angular/core';
3
- import { SdFormControl, ɵSdFormControlParent as _SdFormControlParent, SdViewed, SdViewedInput } from '@sdcorejs/angular/forms/models';
4
5
  import { Color } from '@sdcorejs/utils/models';
5
6
 
6
7
  declare class SdSwitch implements OnInit, OnDestroy {
@@ -26,6 +27,11 @@ declare class SdSwitch implements OnInit, OnDestroy {
26
27
  readonly dataEmpty: _angular_core.Signal<"true" | "false">;
27
28
  readonly dataValue: _angular_core.Signal<string>;
28
29
  readonly dataRequired: _angular_core.Signal<"true" | "false">;
30
+ readonly errorMessage: _angular_core.Signal<string | undefined>;
31
+ /** Shared reactive form policy — `validationError` is already interaction-gated (touched/dirty). */
32
+ readonly connectorState: _angular_core.Signal<_sdcorejs_angular_forms_models.ɵSdFormControlConnectorState<boolean | null | undefined>>;
33
+ /** Message to render inline; `undefined` while untouched, or when `hideInlineError` is set. */
34
+ readonly visibleErrorMessage: _angular_core.Signal<string | undefined>;
29
35
  ngOnInit(): void;
30
36
  ngOnDestroy(): void;
31
37
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdSwitch, never>;
@@ -1,14 +1,17 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnInit, AfterViewInit, OnDestroy, ElementRef } from '@angular/core';
2
+ import { OnInit, OnDestroy, ElementRef } from '@angular/core';
3
3
  import { FormGroup } from '@angular/forms';
4
4
  import { MatFormFieldAppearance, FloatLabelType } from '@angular/material/form-field';
5
5
  import { SdViewDefDirective, SdLabelDefDirective, SdSuffixDefDirective } from '@sdcorejs/angular/forms/directives';
6
6
  import { SdViewed, SdViewedInput, SdCustomValidator, SdFormControl } from '@sdcorejs/angular/forms/models';
7
7
  import { Size } from '@sdcorejs/utils/models';
8
8
 
9
- declare class SdTextarea implements OnInit, AfterViewInit, OnDestroy {
9
+ declare class SdTextarea implements OnInit, OnDestroy {
10
10
  #private;
11
11
  id: string;
12
+ /** why: id ổn định của <mat-error> để control trỏ `aria-describedby` sang — thông báo lỗi
13
+ * phải đọc được từ chính control, không chỉ hiện ra màn hình. */
14
+ readonly errorId: string;
12
15
  textareaRef: _angular_core.Signal<ElementRef<HTMLTextAreaElement> | undefined>;
13
16
  sdViewDef: _angular_core.Signal<SdViewDefDirective<any, any> | undefined>;
14
17
  sdLabelDef: _angular_core.Signal<SdLabelDefDirective | undefined>;
@@ -59,7 +62,6 @@ declare class SdTextarea implements OnInit, AfterViewInit, OnDestroy {
59
62
  isFocused: boolean;
60
63
  constructor();
61
64
  ngOnInit(): void;
62
- ngAfterViewInit(): void;
63
65
  ngOnDestroy(): void;
64
66
  onFocus: () => void;
65
67
  onBlur: () => void;
@@ -75,8 +75,29 @@ declare class SdTimeRange {
75
75
  readonly isReadonly: _angular_core.Signal<boolean>;
76
76
  readonly viewTemplate: _angular_core.Signal<TemplateRef<unknown> | undefined>;
77
77
  readonly displayValue: _angular_core.Signal<string>;
78
- readonly showClear: _angular_core.Signal<boolean>;
78
+ /**
79
+ * Endpoint invalid ĐÃ gate theo tương tác — CHỈ dùng cho hiển thị (message, `data-invalid`).
80
+ * `connectorState().invalid` của `sd-time` là `invalid && (touched || dirty)`.
81
+ */
79
82
  readonly endpointInvalid: _angular_core.Signal<boolean>;
83
+ /**
84
+ * Endpoint invalid THÔ — không gate theo tương tác. Dùng cho VALIDATOR của control tổng.
85
+ * why: endpoint không còn được đăng ký vào FormGroup của consumer, nên validity của chúng chỉ
86
+ * tới được form cha qua control tổng. Nếu đường đó cũng gate theo `touched || dirty` thì một
87
+ * endpoint invalid do ghi programmatic (chưa ai chạm vào) sẽ để form cha VALID — sai contract
88
+ * đã ghi trong `sd-time-range.md`.
89
+ * `formControl.invalid` là property thường nên tự nó không phát tín hiệu; đọc `connectorState()`
90
+ * một nhịp để computed có dependency reactive theo `events` của endpoint control.
91
+ */
92
+ readonly endpointInvalidRaw: _angular_core.Signal<boolean>;
93
+ /**
94
+ * Message đã gate theo tương tác — thứ template được phép hiển thị.
95
+ * why: `errorMessage()` thô bung lỗi ngay lần paint đầu với `[required]`, khi người dùng chưa
96
+ * chạm vào ô nào. `connectorState().validationError` gate theo control tổng; range còn có 2
97
+ * endpoint có thể invalid trong khi control tổng chưa dirty (text sai không tới được model tổng),
98
+ * nên phải cộng thêm nhánh endpoint — `endpointInvalid` tự nó đã gate theo touched/dirty.
99
+ */
100
+ readonly visibleError: _angular_core.Signal<string | undefined>;
80
101
  readonly dataDisabled: _angular_core.Signal<"true" | "false">;
81
102
  readonly dataInvalid: _angular_core.Signal<"true" | "false">;
82
103
  readonly dataEmpty: _angular_core.Signal<"true" | "false">;
@@ -2,9 +2,12 @@ import * as _sdcorejs_angular_forms_models from '@sdcorejs/angular/forms/models'
2
2
  import { ɵSdFormControlParent as _SdFormControlParent, SdViewed, SdViewedInput, SdFormControl } from '@sdcorejs/angular/forms/models';
3
3
  import * as _angular_core from '@angular/core';
4
4
  import { ElementRef, TemplateRef } from '@angular/core';
5
- import { FormGroup } from '@angular/forms';
5
+ import { FormGroup, FormControl } from '@angular/forms';
6
+ import { ErrorStateMatcher } from '@angular/material/core';
7
+ import { MatFormFieldAppearance } from '@angular/material/form-field';
6
8
  import { SdModal } from '@sdcorejs/angular/components/modal';
7
9
  import { SdTree, SdTreeItemContext, SdTreeDataSource, SdTreeItem, SdTreeOption, SdTreeLoadErrorEvent, SdTreeComponentOption, SdTreeSelectionEvent } from '@sdcorejs/angular/components/tree';
10
+ import { Size } from '@sdcorejs/utils/models';
8
11
 
9
12
  type SdTreeSelectModel<TKey> = TKey | TKey[] | null | undefined;
10
13
  type SdTreeSelectTemplateContext<T> = SdTreeItemContext<T>;
@@ -16,18 +19,24 @@ declare class SdTreeSelectNodeTemplateDirective<T> {
16
19
  }
17
20
  declare class SdTreeSelect<T = unknown, TKey = string | number> {
18
21
  #private;
19
- readonly trigger: _angular_core.Signal<ElementRef<HTMLButtonElement> | undefined>;
22
+ readonly trigger: _angular_core.Signal<ElementRef<HTMLInputElement> | undefined>;
20
23
  readonly modal: _angular_core.Signal<SdModal | undefined>;
21
24
  readonly treeComponent: _angular_core.Signal<SdTree<T> | undefined>;
22
25
  readonly nodeTemplate: _angular_core.Signal<SdTreeSelectNodeTemplateDirective<any> | undefined>;
26
+ readonly errorId: string;
23
27
  readonly autoIdInput: _angular_core.InputSignal<string | null | undefined>;
24
28
  readonly autoId: _angular_core.Signal<string | undefined>;
25
29
  readonly name: _angular_core.InputSignal<string>;
26
30
  readonly form: _angular_core.InputSignalWithTransform<FormGroup<any> | undefined, _SdFormControlParent>;
27
31
  readonly label: _angular_core.InputSignal<string | undefined>;
32
+ readonly helperText: _angular_core.InputSignal<string | undefined>;
28
33
  readonly placeholder: _angular_core.InputSignal<string | null | undefined>;
29
34
  readonly modalTitle: _angular_core.InputSignal<string | null | undefined>;
30
35
  readonly ariaLabel: _angular_core.InputSignal<string | undefined>;
36
+ readonly size: _angular_core.InputSignal<Size>;
37
+ readonly appearanceInput: _angular_core.InputSignal<MatFormFieldAppearance | undefined>;
38
+ readonly appearance: _angular_core.Signal<MatFormFieldAppearance>;
39
+ readonly hideInlineError: _angular_core.InputSignalWithTransform<boolean, unknown>;
31
40
  readonly items: _angular_core.InputSignal<SdTreeDataSource<SdTreeItem<T>>>;
32
41
  readonly tree: _angular_core.InputSignal<SdTreeOption<T>>;
33
42
  readonly valueField: _angular_core.InputSignal<(T extends object ? { [Key in keyof T & string]: T[Key] extends string | number | boolean | Function | Date | null | undefined ? Key : T[Key] extends any[] ? Key : T[Key] extends object ? Key | `${Key}.${T[Key] extends infer T_1 ? T_1 extends T[Key] ? T_1 extends object ? { [Key_2 in keyof T_1 & string]: T_1[Key_2] extends string | number | boolean | Function | Date | null | undefined ? Key_2 : T_1[Key_2] extends any[] ? Key_2 : T_1[Key_2] extends object ? Key_2 | `${Key_2}.${T_1[Key_2] extends infer T_2 ? T_2 extends T_1[Key_2] ? T_2 extends object ? { [Key_3 in keyof T_2 & string]: T_2[Key_3] extends string | number | boolean | Function | Date | null | undefined ? Key_3 : T_2[Key_3] extends any[] ? Key_3 : T_2[Key_3] extends object ? Key_3 | `${Key_3}.${T_2[Key_3] extends infer T_3 ? T_3 extends T_2[Key_3] ? T_3 extends object ? { [Key_4 in keyof T_3 & string]: T_3[Key_4] extends string | number | boolean | Function | Date | null | undefined ? Key_4 : T_3[Key_4] extends any[] ? Key_4 : T_3[Key_4] extends object ? Key_4 : Key_4; }[keyof T_3 & string] : string : never : never}` : Key_3; }[keyof T_2 & string] : string : never : never}` : Key_2; }[keyof T_1 & string] : string : never : never}` : Key; }[keyof T & string] : string) | undefined>;
@@ -39,15 +48,36 @@ declare class SdTreeSelect<T = unknown, TKey = string | number> {
39
48
  readonly multiple: _angular_core.InputSignalWithTransform<boolean, unknown>;
40
49
  readonly cascade: _angular_core.InputSignal<"independent" | "descendants">;
41
50
  readonly required: _angular_core.InputSignalWithTransform<boolean, unknown>;
51
+ /** Component-local error text. Set it to force the control invalid and render the message. */
52
+ readonly inlineError: _angular_core.InputSignal<string | undefined>;
42
53
  readonly clearable: _angular_core.InputSignalWithTransform<boolean, unknown>;
43
54
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, unknown>;
44
55
  readonly readonly: _angular_core.InputSignalWithTransform<boolean, unknown>;
45
56
  readonly viewed: _angular_core.InputSignalWithTransform<SdViewed, SdViewedInput>;
46
57
  readonly model: _angular_core.ModelSignal<SdTreeSelectModel<TKey>>;
47
58
  readonly sdChange: _angular_core.OutputEmitterRef<SdTreeSelectModel<TKey>>;
48
- readonly sdLoadError: _angular_core.OutputEmitterRef<SdTreeLoadErrorEvent<T>>;
59
+ readonly loadError: _angular_core.OutputEmitterRef<SdTreeLoadErrorEvent<T>>;
49
60
  readonly formControl: SdFormControl;
61
+ readonly errorMessage: _angular_core.Signal<string | undefined>;
50
62
  readonly connectorState: _angular_core.Signal<_sdcorejs_angular_forms_models.ɵSdFormControlConnectorState<SdTreeSelectModel<TKey>>>;
63
+ /** Interaction-gated validation message; `undefined` until the control is touched/dirty. */
64
+ readonly visibleErrorMessage: _angular_core.Signal<string | undefined>;
65
+ /**
66
+ * Text-only control backing the readonly trigger; `formControl` above holds the real keys.
67
+ *
68
+ * why: phải là một `FormControl` THẬT chứ không phải `[value]`. `MatInput.ngDoCheck` chỉ gọi
69
+ * `updateErrorState()` khi có `NgControl` — không có nó thì `errorState` đứng yên ở `false`, mà
70
+ * `<mat-error>`, viền đỏ và `aria-invalid` đều bám vào cờ đó, nên field bắt buộc bỏ trống lại im
71
+ * lặng y như bug cũ. Trạng thái disabled cũng chảy qua control này (MatInput tự đồng bộ
72
+ * `disabled` từ `ngControl` mỗi vòng CD, nên bind `[disabled]` trên template sẽ bị ghi đè).
73
+ */
74
+ readonly displayControl: FormControl<string>;
75
+ /**
76
+ * why: MatInput đã có `NgControl`, nhưng control đó là ô TEXT — nó không biết gì về `required`
77
+ * hay validator của tree-select. Matcher nối thẳng `errorState` của Material vào message đã gate
78
+ * theo tương tác của connector.
79
+ */
80
+ readonly errorStateMatcher: ErrorStateMatcher;
51
81
  readonly draftKeys: _angular_core.WritableSignal<TKey[]>;
52
82
  readonly modelKeys: _angular_core.Signal<TKey[]>;
53
83
  readonly effectivePlaceholder: _angular_core.Signal<string>;
@@ -57,7 +87,8 @@ declare class SdTreeSelect<T = unknown, TKey = string | number> {
57
87
  readonly draftEntities: _angular_core.Signal<T[]>;
58
88
  readonly displayText: _angular_core.Signal<string>;
59
89
  readonly treeOption: _angular_core.Signal<SdTreeComponentOption<T>>;
60
- open(): void;
90
+ constructor();
91
+ open(event?: Event): void;
61
92
  applySelection(): void;
62
93
  cancel(): void;
63
94
  clear(event?: Event): void;
@@ -68,7 +99,7 @@ declare class SdTreeSelect<T = unknown, TKey = string | number> {
68
99
  keyOf(item: T): TKey;
69
100
  displayEntity(item: T): string;
70
101
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SdTreeSelect<any, any>, never>;
71
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdTreeSelect<any, any>, "sd-tree-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "modalTitle": { "alias": "modalTitle"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "tree": { "alias": "tree"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": false; "isSignal": true; }; "keySelector": { "alias": "keySelector"; "required": false; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": false; "isSignal": true; }; "displayWith": { "alias": "displayWith"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; "disabledNode": { "alias": "disabledNode"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "cascade": { "alias": "cascade"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "model": { "alias": "model"; "required": false; "isSignal": true; }; }, { "model": "modelChange"; "sdChange": "sdChange"; "sdLoadError": "sdLoadError"; }, ["nodeTemplate"], never, true, never>;
102
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SdTreeSelect<any, any>, "sd-tree-select", never, { "autoIdInput": { "alias": "autoId"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "form": { "alias": "form"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "helperText": { "alias": "helperText"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "modalTitle": { "alias": "modalTitle"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "appearanceInput": { "alias": "appearance"; "required": false; "isSignal": true; }; "hideInlineError": { "alias": "hideInlineError"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "tree": { "alias": "tree"; "required": false; "isSignal": true; }; "valueField": { "alias": "valueField"; "required": false; "isSignal": true; }; "keySelector": { "alias": "keySelector"; "required": false; "isSignal": true; }; "displayField": { "alias": "displayField"; "required": false; "isSignal": true; }; "displayWith": { "alias": "displayWith"; "required": false; "isSignal": true; }; "compareWith": { "alias": "compareWith"; "required": false; "isSignal": true; }; "disabledNode": { "alias": "disabledNode"; "required": false; "isSignal": true; }; "multiple": { "alias": "multiple"; "required": false; "isSignal": true; }; "cascade": { "alias": "cascade"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "inlineError": { "alias": "inlineError"; "required": false; "isSignal": true; }; "clearable": { "alias": "clearable"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "viewed": { "alias": "viewed"; "required": false; "isSignal": true; }; "model": { "alias": "model"; "required": false; "isSignal": true; }; }, { "model": "modelChange"; "sdChange": "sdChange"; "loadError": "loadError"; }, ["nodeTemplate"], ["[sdLabel]"], true, never>;
72
103
  }
73
104
  declare function normalizeTreeSelectKeys<TKey>(value: SdTreeSelectModel<TKey>, multiple: boolean): TKey[];
74
105
 
@@ -1,42 +1,51 @@
1
+ import * as i21 from '@sdcorejs/angular/forms/directives';
1
2
  export * from '@sdcorejs/angular/forms/directives';
2
3
  export * from '@sdcorejs/angular/forms/models';
4
+ import * as i1 from '@sdcorejs/angular/forms/label';
3
5
  export * from '@sdcorejs/angular/forms/label';
4
- import * as i1 from '@sdcorejs/angular/forms/input';
6
+ import * as i2 from '@sdcorejs/angular/forms/input';
5
7
  export * from '@sdcorejs/angular/forms/input';
8
+ import * as i3 from '@sdcorejs/angular/forms/input-color';
6
9
  export * from '@sdcorejs/angular/forms/input-color';
10
+ import * as i4 from '@sdcorejs/angular/forms/inline-text';
7
11
  export * from '@sdcorejs/angular/forms/inline-text';
8
- import * as i2 from '@sdcorejs/angular/forms/input-number';
12
+ import * as i5 from '@sdcorejs/angular/forms/input-number';
9
13
  export * from '@sdcorejs/angular/forms/input-number';
10
- import * as i3 from '@sdcorejs/angular/forms/date';
14
+ import * as i6 from '@sdcorejs/angular/forms/date';
11
15
  export * from '@sdcorejs/angular/forms/date';
16
+ import * as i7 from '@sdcorejs/angular/forms/datetime';
12
17
  export * from '@sdcorejs/angular/forms/datetime';
13
- import * as i4 from '@sdcorejs/angular/forms/date-range';
18
+ import * as i8 from '@sdcorejs/angular/forms/date-range';
14
19
  export * from '@sdcorejs/angular/forms/date-range';
15
- import * as i5 from '@sdcorejs/angular/forms/time';
20
+ import * as i9 from '@sdcorejs/angular/forms/time';
16
21
  export * from '@sdcorejs/angular/forms/time';
17
- import * as i6 from '@sdcorejs/angular/forms/time-range';
22
+ import * as i10 from '@sdcorejs/angular/forms/time-range';
18
23
  export * from '@sdcorejs/angular/forms/time-range';
19
- import * as i7 from '@sdcorejs/angular/forms/entity-picker';
24
+ import * as i11 from '@sdcorejs/angular/forms/entity-picker';
20
25
  export * from '@sdcorejs/angular/forms/entity-picker';
21
- import * as i8 from '@sdcorejs/angular/forms/tree-select';
26
+ import * as i12 from '@sdcorejs/angular/forms/tree-select';
22
27
  export * from '@sdcorejs/angular/forms/tree-select';
23
- import * as i9 from '@sdcorejs/angular/forms/select';
28
+ import * as i13 from '@sdcorejs/angular/forms/select';
24
29
  export * from '@sdcorejs/angular/forms/select';
25
- import * as i10 from '@sdcorejs/angular/forms/autocomplete';
30
+ import * as i14 from '@sdcorejs/angular/forms/autocomplete';
26
31
  export * from '@sdcorejs/angular/forms/autocomplete';
32
+ import * as i15 from '@sdcorejs/angular/forms/switch';
27
33
  export * from '@sdcorejs/angular/forms/switch';
28
- import * as i11 from '@sdcorejs/angular/forms/radio';
34
+ import * as i16 from '@sdcorejs/angular/forms/radio';
29
35
  export * from '@sdcorejs/angular/forms/radio';
30
- import * as i12 from '@sdcorejs/angular/forms/textarea';
36
+ import * as i17 from '@sdcorejs/angular/forms/textarea';
31
37
  export * from '@sdcorejs/angular/forms/textarea';
38
+ import * as i18 from '@sdcorejs/angular/forms/chip';
32
39
  export * from '@sdcorejs/angular/forms/chip';
40
+ import * as i19 from '@sdcorejs/angular/forms/chip-calendar';
33
41
  export * from '@sdcorejs/angular/forms/chip-calendar';
42
+ import * as i20 from '@sdcorejs/angular/forms/checkbox';
34
43
  export * from '@sdcorejs/angular/forms/checkbox';
35
44
  import * as i0 from '@angular/core';
36
45
 
37
46
  declare class SdFormsModule {
38
47
  static ɵfac: i0.ɵɵFactoryDeclaration<SdFormsModule, never>;
39
- static ɵmod: i0.ɵɵNgModuleDeclaration<SdFormsModule, never, [typeof i1.SdInput, typeof i2.SdInputNumber, typeof i3.SdDate, typeof i4.SdDateRange, typeof i5.SdTime, typeof i6.SdTimeRange, typeof i7.SdEntityPicker, typeof i8.SdTreeSelect, typeof i9.SdSelect, typeof i10.SdAutocomplete, typeof i11.SdRadio, typeof i12.SdTextarea], [typeof i1.SdInput, typeof i2.SdInputNumber, typeof i3.SdDate, typeof i4.SdDateRange, typeof i5.SdTime, typeof i6.SdTimeRange, typeof i7.SdEntityPicker, typeof i8.SdTreeSelect, typeof i9.SdSelect, typeof i10.SdAutocomplete, typeof i11.SdRadio, typeof i12.SdTextarea]>;
48
+ static ɵmod: i0.ɵɵNgModuleDeclaration<SdFormsModule, never, [typeof i1.SdLabel, typeof i2.SdInput, typeof i3.SdInputColor, typeof i4.SdInlineText, typeof i5.SdInputNumber, typeof i6.SdDate, typeof i7.SdDatetime, typeof i8.SdDateRange, typeof i9.SdTime, typeof i10.SdTimeRange, typeof i11.SdEntityPicker, typeof i12.SdTreeSelect, typeof i13.SdSelect, typeof i14.SdAutocomplete, typeof i15.SdSwitch, typeof i16.SdRadio, typeof i17.SdTextarea, typeof i18.SdChip, typeof i19.SdChipCalendar, typeof i20.SdCheckbox, typeof i21.SdSuffixDefDirective, typeof i21.SdLabelDefDirective, typeof i21.SdViewDefDirective, typeof i21.SdItemDefDefDirective, typeof i13.SdSelectFooterActionDirective, typeof i11.SdEntityPickerSelectedTemplateDirective, typeof i11.SdEntityPickerRowTemplateDirective, typeof i11.SdEntityPickerDetailTemplateDirective, typeof i12.SdTreeSelectNodeTemplateDirective], [typeof i1.SdLabel, typeof i2.SdInput, typeof i3.SdInputColor, typeof i4.SdInlineText, typeof i5.SdInputNumber, typeof i6.SdDate, typeof i7.SdDatetime, typeof i8.SdDateRange, typeof i9.SdTime, typeof i10.SdTimeRange, typeof i11.SdEntityPicker, typeof i12.SdTreeSelect, typeof i13.SdSelect, typeof i14.SdAutocomplete, typeof i15.SdSwitch, typeof i16.SdRadio, typeof i17.SdTextarea, typeof i18.SdChip, typeof i19.SdChipCalendar, typeof i20.SdCheckbox, typeof i21.SdSuffixDefDirective, typeof i21.SdLabelDefDirective, typeof i21.SdViewDefDirective, typeof i21.SdItemDefDefDirective, typeof i13.SdSelectFooterActionDirective, typeof i11.SdEntityPickerSelectedTemplateDirective, typeof i11.SdEntityPickerRowTemplateDirective, typeof i11.SdEntityPickerDetailTemplateDirective, typeof i12.SdTreeSelectNodeTemplateDirective]>;
40
49
  static ɵinj: i0.ɵɵInjectorDeclaration<SdFormsModule>;
41
50
  }
42
51