@sd-angular/core 19.0.0-beta.32 → 19.0.0-beta.34

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 (34) hide show
  1. package/components/view/src/view.component.d.ts +11 -11
  2. package/fesm2022/sd-angular-core-components-table.mjs +4 -4
  3. package/fesm2022/sd-angular-core-components-table.mjs.map +1 -1
  4. package/fesm2022/sd-angular-core-components-view.mjs +28 -40
  5. package/fesm2022/sd-angular-core-components-view.mjs.map +1 -1
  6. package/fesm2022/sd-angular-core-components-workflow.mjs +22 -22
  7. package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
  8. package/fesm2022/sd-angular-core-forms-autocomplete.mjs +165 -327
  9. package/fesm2022/sd-angular-core-forms-autocomplete.mjs.map +1 -1
  10. package/fesm2022/sd-angular-core-forms-date.mjs +134 -279
  11. package/fesm2022/sd-angular-core-forms-date.mjs.map +1 -1
  12. package/fesm2022/sd-angular-core-forms-datetime.mjs +132 -289
  13. package/fesm2022/sd-angular-core-forms-datetime.mjs.map +1 -1
  14. package/fesm2022/sd-angular-core-forms-input-number.mjs +161 -337
  15. package/fesm2022/sd-angular-core-forms-input-number.mjs.map +1 -1
  16. package/fesm2022/sd-angular-core-forms-input.mjs +126 -286
  17. package/fesm2022/sd-angular-core-forms-input.mjs.map +1 -1
  18. package/fesm2022/sd-angular-core-forms-select.mjs +205 -400
  19. package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
  20. package/fesm2022/sd-angular-core-forms-textarea.mjs +120 -226
  21. package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
  22. package/fesm2022/sd-angular-core-modules-layout.mjs +1 -1
  23. package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
  24. package/fesm2022/sd-angular-core-services-confirm.mjs +1 -1
  25. package/forms/autocomplete/src/autocomplete.component.d.ts +44 -51
  26. package/forms/date/src/date.component.d.ts +40 -46
  27. package/forms/datetime/src/datetime.component.d.ts +39 -47
  28. package/forms/input/src/input.component.d.ts +44 -55
  29. package/forms/input-number/src/input-number.component.d.ts +45 -53
  30. package/forms/select/src/select.component.d.ts +47 -56
  31. package/forms/textarea/src/textarea.component.d.ts +33 -40
  32. package/package.json +39 -39
  33. package/sd-angular-core-19.0.0-beta.34.tgz +0 -0
  34. package/sd-angular-core-19.0.0-beta.32.tgz +0 -0
@@ -1,12 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ContentChild, ViewChild, Input, Output, Inject, Optional, ChangeDetectionStrategy, Component } from '@angular/core';
3
- import { debounceTime, switchMap, map, catchError, finalize, startWith } from 'rxjs/operators';
2
+ import { viewChild, contentChild, inject, ChangeDetectorRef, input, computed, booleanAttribute, model, output, EventEmitter, effect, untracked, Output, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { toObservable } from '@angular/core/rxjs-interop';
4
+ import { tap, map, debounce, switchMap, catchError, finalize, startWith } from 'rxjs/operators';
5
+ import { Subscription, combineLatest, timer, of, defer, from } from 'rxjs';
6
+ import * as uuid from 'uuid';
4
7
  import * as i1 from '@angular/common';
5
8
  import { CommonModule } from '@angular/common';
6
9
  import * as i2 from '@angular/forms';
7
10
  import { NgForm, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
8
11
  import * as i5 from '@angular/material/autocomplete';
9
- import { MatAutocompleteModule, MatAutocompleteTrigger } from '@angular/material/autocomplete';
12
+ import { MatAutocompleteTrigger, MatAutocompleteModule } from '@angular/material/autocomplete';
10
13
  import { MatFormFieldModule } from '@angular/material/form-field';
11
14
  import * as i6 from '@angular/material/icon';
12
15
  import { MatIconModule } from '@angular/material/icon';
@@ -17,12 +20,10 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
17
20
  import * as i4 from '@angular/material/tooltip';
18
21
  import { MatTooltipModule } from '@angular/material/tooltip';
19
22
  import { SdItemDefDefDirective, SdViewDefDirective } from '@sd-angular/core/forms/directives';
20
- import { SdFormControl, HandleSdCustomValidator, SD_FORM_CONFIGURATION } from '@sd-angular/core/forms/models';
23
+ import { SD_FORM_CONFIGURATION, SdFormControl, HandleSdCustomValidator } from '@sd-angular/core/forms/models';
21
24
  import { ArrayUtilities, SdUtilities } from '@sd-angular/core/utilities/extensions';
22
25
  import { SdView } from '@sd-angular/core/components/view';
23
26
  import { SdLabel } from '@sd-angular/core/forms/label';
24
- import { BehaviorSubject, Subscription, combineLatest, of, defer, from } from 'rxjs';
25
- import * as uuid from 'uuid';
26
27
 
27
28
  /* eslint-disable @angular-eslint/component-class-suffix */
28
29
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -38,174 +39,130 @@ class SdAutocompleteErrotStateMatcher {
38
39
  }
39
40
  }
40
41
  class SdAutocomplete {
41
- ref;
42
- formConfig;
43
- sdLabelTemplate;
44
- sdValueTemplate;
45
42
  id = `I${uuid.v4()}`;
46
- autoId;
47
- set _autoId(val) {
48
- if (!val) {
49
- return;
50
- }
51
- this.autoId = `forms-autocomplete-${val}`;
52
- }
53
- // @Input() set key(value: any) {
54
- // this.#cache = {};
55
- // this.#item = {};
56
- // }
57
- autocompleteTrigger;
58
- #model;
59
- #delay = 0; // Sau khoảng thời gian delay nếu không có thay đổi thì thì mới bắt đầu thực hiện gọi hàm
60
- #name = uuid.v4();
61
- set name(val) {
62
- if (val) {
63
- this.#name = val;
64
- }
65
- }
66
- appearance = 'outline';
43
+ // ==========================================
44
+ // 1. SIGNAL QUERIES
45
+ // ==========================================
46
+ input = viewChild('input');
47
+ autocompleteTrigger = viewChild(MatAutocompleteTrigger);
48
+ sdLabelTemplate = contentChild('sdLabel');
49
+ sdValueTemplate = contentChild('sdValue');
50
+ itemDef = contentChild(SdItemDefDefDirective);
51
+ sdViewDef = contentChild(SdViewDefDirective);
52
+ // ==========================================
53
+ // 2. INJECTS
54
+ // ==========================================
55
+ ref = inject(ChangeDetectorRef);
56
+ formConfig = inject(SD_FORM_CONFIGURATION, { optional: true });
57
+ // ==========================================
58
+ // 3. SIGNAL INPUTS & MODEL
59
+ // ==========================================
60
+ autoIdInput = input(undefined, { alias: 'autoId' });
61
+ autoId = computed(() => this.autoIdInput() ? `forms-autocomplete-${this.autoIdInput()}` : undefined);
62
+ name = input(uuid.v4());
63
+ size = input('md');
64
+ form = input();
65
+ label = input();
66
+ helperText = input();
67
+ placeholder = input();
68
+ valueField = input();
69
+ displayField = input();
70
+ disabledField = input('');
71
+ limit = input(100);
72
+ cacheChecksum = input();
73
+ hyperlink = input();
74
+ items = input();
75
+ hideInlineError = input(false, { transform: booleanAttribute });
76
+ addable = input(false, { transform: booleanAttribute });
77
+ required = input(false, { transform: booleanAttribute });
78
+ disabled = input(false, { transform: booleanAttribute });
79
+ viewed = input(false, { transform: booleanAttribute });
80
+ validator = input();
81
+ inlineError = input();
82
+ appearanceInput = input(undefined, { alias: 'appearance' });
83
+ appearance = computed(() => this.appearanceInput() ?? this.formConfig?.appearance ?? 'outline');
84
+ valueModel = model(undefined, { alias: 'model' });
85
+ // ==========================================
86
+ // 4. SIGNAL OUTPUTS (Giữ sdAdd làm EventEmitter để check observed)
87
+ // ==========================================
88
+ sdChange = output();
89
+ sdSelection = output();
90
+ sdAdd = new EventEmitter();
91
+ // ==========================================
92
+ // 5. INTERNAL STATE & RXJS STREAMS
93
+ // ==========================================
67
94
  loading = false;
95
+ isFocused = false;
96
+ isTyping = false;
68
97
  inputControl = new SdFormControl();
69
98
  formControl = new SdFormControl();
70
99
  matcher = new SdAutocompleteErrotStateMatcher(this.formControl);
71
- size = 'md';
72
- #form;
73
- set form(val) {
74
- if (val) {
75
- if (val instanceof NgForm) {
76
- this.#form = val.form;
77
- }
78
- else {
79
- this.#form = val;
80
- }
81
- }
82
- }
83
- label;
84
- set _label(val) {
85
- this.label = val;
86
- }
87
- helperText;
88
- set _helperText(val) {
89
- this.helperText = val;
90
- }
91
- valueField;
92
- displayField;
93
- disabledField = '';
94
- placeholder;
95
- #itemsChanges = new BehaviorSubject([]);
96
- set items(items) {
97
- this.#delay = 0;
98
- // Mỗi lần items được set lại phải clear cache
99
- this.#cache = {};
100
- if (!items) {
101
- this.#itemsChanges.next([]);
102
- }
103
- else if (Array.isArray(items)) {
104
- this.#itemsChanges.next(items.filter(e => e !== null && e !== undefined));
105
- }
106
- else {
107
- this.#itemsChanges.next(items);
108
- this.#delay = 500;
109
- }
110
- this.formControl.updateValueAndValidity();
111
- }
112
- limit = 100;
113
- filteredItems;
114
- // Nếu items là 1 function gọi về server và có những tham số bên ngoài tác động đến kết quả trả về thì truyền thêm
115
- // Ví dụ: [cacheCheckSum]="{a: aValue, b: bValue}"
116
- cacheChecksum;
117
- controlPlaceHolder;
118
- set model(value) {
119
- if (this.#model !== value) {
120
- this.#model = value;
121
- this.formControl.setValue(value);
122
- }
123
- }
124
- addable = false;
125
- set _addable(addable) {
126
- this.addable = addable === '' || !!addable;
127
- }
128
- itemDef;
129
- modelChange = new EventEmitter();
130
- sdChange = new EventEmitter();
131
- sdSelection = new EventEmitter();
132
- sdAdd = new EventEmitter();
133
- // Optional
134
- set disabled(val) {
135
- val = val === '' || val || !!val;
136
- if (val) {
137
- this.inputControl.disable();
138
- this.formControl.disable();
139
- }
140
- else {
141
- this.inputControl.enable();
142
- this.formControl.enable();
143
- }
144
- }
145
- viewed = false;
146
- set _viewed(val) {
147
- this.viewed = val === '' || !!val;
148
- }
149
- hyperlink;
150
- required = false;
151
- set _required(val) {
152
- this.required = val === '' || !!val;
153
- this.#updateValidator();
154
- }
155
- #validator;
156
- set _validator(value) {
157
- this.#validator = value;
158
- this.#updateValidator();
159
- }
160
- inlineError;
161
- set _inlineError(val) {
162
- this.inlineError = val;
163
- this.#updateValidator();
164
- }
165
- hideInlineError = false;
166
- set _hideInlineError(val) {
167
- this.hideInlineError = val === '' || val;
168
- val = val === '' || val;
169
- }
100
+ #cache = {};
101
+ #item = {};
170
102
  #subscription = new Subscription();
171
- input;
172
- sdViewDef;
173
- isFocused = false;
103
+ // RxJS Streams giữ nguyên logic xịn xò của bạn
104
+ filteredItems;
174
105
  selected;
175
106
  display;
176
- #cache = {};
177
- #item = {};
178
- isTyping = false;
179
- constructor(ref, formConfig) {
180
- this.ref = ref;
181
- this.formConfig = formConfig;
107
+ controlPlaceHolder;
108
+ constructor() {
109
+ // Tự động gán model vào formControl (Giữ lại emitEvent: true để kích hoạt RxJS pipeline)
110
+ effect(() => {
111
+ const val = this.valueModel();
112
+ untracked(() => {
113
+ if (this.formControl.value !== val) {
114
+ this.formControl.setValue(val);
115
+ }
116
+ });
117
+ });
118
+ // Đồng bộ Disable
119
+ effect(() => {
120
+ if (this.disabled()) {
121
+ this.inputControl.disable({ emitEvent: false });
122
+ this.formControl.disable({ emitEvent: false });
123
+ }
124
+ else {
125
+ this.inputControl.enable({ emitEvent: false });
126
+ this.formControl.enable({ emitEvent: false });
127
+ }
128
+ });
129
+ // Cập nhật Validator
130
+ effect(() => {
131
+ const req = this.required();
132
+ const val = this.validator();
133
+ const inl = this.inlineError();
134
+ untracked(() => this.#updateValidator(req, val, inl));
135
+ });
182
136
  }
183
137
  ngOnInit() {
184
- this.appearance = this.appearance || this.formConfig?.appearance;
185
138
  this.#subscription.add(this.inputControl.touchChanges.subscribe(() => {
186
139
  this.formControl.markAsTouched();
187
140
  this.ref.markForCheck();
188
141
  }));
189
- this.#subscription.add(this.formControl.sdChanges.subscribe(() => {
190
- this.ref.markForCheck();
191
- }));
192
- this.#subscription.add(this.inputControl.sdChanges.subscribe(() => {
193
- this.ref.markForCheck();
194
- }));
195
- this.#subscription.add(this.inputControl.valueChanges.subscribe(() => {
196
- this.isTyping = true;
142
+ this.#subscription.add(this.formControl.sdChanges.subscribe(() => this.ref.markForCheck()));
143
+ this.#subscription.add(this.inputControl.sdChanges.subscribe(() => this.ref.markForCheck()));
144
+ this.#subscription.add(this.inputControl.valueChanges.subscribe(() => { this.isTyping = true; }));
145
+ // CẦU NỐI RXJS - Bọc items Signal thành Observable
146
+ const cleanItems$ = toObservable(this.items).pipe(tap(() => { this.#cache = {}; }), // Clear cache mỗi khi items đổi
147
+ map(items => {
148
+ if (!items)
149
+ return [];
150
+ if (Array.isArray(items))
151
+ return items.filter(e => e !== null && e !== undefined);
152
+ return items;
197
153
  }));
198
154
  this.filteredItems = combineLatest([
199
- this.#itemsChanges.asObservable(),
200
- this.inputControl.valueChanges.pipe(debounceTime(this.#delay)),
155
+ cleanItems$,
156
+ // Thay thế logic delay cũ bằng debounce() động rất thông minh
157
+ this.inputControl.valueChanges.pipe(debounce(() => timer(typeof this.items() === 'function' ? 500 : 0))),
201
158
  ]).pipe(switchMap(([items, searchText]) => {
202
159
  this.isTyping = false;
203
160
  searchText = searchText || '';
204
161
  if (typeof items !== 'function') {
205
- return of(ArrayUtilities.paging(ArrayUtilities.search(items, searchText, [this.valueField, this.displayField]), this.limit));
162
+ return of(ArrayUtilities.paging(ArrayUtilities.search(items, searchText, [this.valueField(), this.displayField()]), this.limit()));
206
163
  }
207
164
  const key = SdUtilities.hash({
208
- checksum: this.cacheChecksum || null,
165
+ checksum: this.cacheChecksum() || null,
209
166
  searchText,
210
167
  });
211
168
  if (this.#cache[key] !== undefined) {
@@ -224,7 +181,7 @@ class SdAutocomplete {
224
181
  this.ref.markForCheck();
225
182
  return obs.pipe(map(data => {
226
183
  this.#cache[key] = data || [];
227
- Object.assign(this.#item, ArrayUtilities.toObject(this.valueField, this.#cache[key]));
184
+ Object.assign(this.#item, ArrayUtilities.toObject(this.valueField(), this.#cache[key]));
228
185
  return this.#cache[key];
229
186
  }), catchError(() => of([])), finalize(() => {
230
187
  this.loading = false;
@@ -232,20 +189,18 @@ class SdAutocomplete {
232
189
  }));
233
190
  }));
234
191
  this.selected = combineLatest([
235
- this.#itemsChanges.asObservable(),
192
+ cleanItems$,
236
193
  this.formControl.valueChanges.pipe(startWith(this.formControl.value)),
237
194
  ]).pipe(switchMap(([items]) => {
238
- // Vì một số lý do chưa xác định mà khi sử dụng sdViewDef thì khi chuyển sang dạng view sẽ trigger val = null
239
- // Nhưng formControl.value vẫn có giá trị đúng nên thực hiện gán val = this.formControl.value;
240
195
  const val = this.formControl.value;
241
- if (!this.valueField) {
196
+ const vField = this.valueField();
197
+ const dField = this.displayField();
198
+ if (!vField)
242
199
  return of(val);
243
- }
244
200
  if (val || val === 0) {
245
201
  if (typeof items === 'function') {
246
- if (this.#item[val]) {
202
+ if (this.#item[val])
247
203
  return of(this.#item[val]);
248
- }
249
204
  let obs;
250
205
  const func = items({ type: 'VALUE', value: val });
251
206
  if (func instanceof Promise) {
@@ -255,31 +210,23 @@ class SdAutocomplete {
255
210
  obs = func;
256
211
  }
257
212
  return obs.pipe(map(data => {
258
- Object.assign(this.#item, ArrayUtilities.toObject(this.valueField, data));
259
- return (this.#item[val] || {
260
- [this.valueField]: val,
261
- [this.displayField]: val,
262
- });
263
- }), catchError(() => {
264
- return of({
265
- [this.valueField]: val,
266
- [this.displayField]: val,
267
- });
268
- }), finalize(() => {
213
+ Object.assign(this.#item, ArrayUtilities.toObject(vField, data));
214
+ return this.#item[val] || { [vField]: val, [dField]: val };
215
+ }), catchError(() => of({ [vField]: val, [dField]: val })), finalize(() => {
269
216
  this.loading = false;
270
217
  this.ref.markForCheck();
271
218
  }));
272
219
  }
273
- return of(items.find((e) => e[this.valueField] === val));
220
+ return of(items.find((e) => e[vField] === val));
274
221
  }
275
222
  return of('');
276
223
  }));
277
224
  this.controlPlaceHolder = this.selected.pipe(map((item) => {
278
- return item?.[this.displayField] ?? item ?? this.placeholder ?? (this.appearance ? this.label : '');
225
+ return item?.[this.displayField()] ?? item ?? this.placeholder() ?? (this.appearance() ? this.label() : '');
279
226
  }));
280
227
  this.display = this.selected.pipe(map((item) => {
281
- if (this.disabledField && typeof item === 'object' && !!item) {
282
- return item?.[this.disabledField] ?? '';
228
+ if (this.disabledField() && typeof item === 'object' && !!item) {
229
+ return item?.[this.disabledField()] ?? '';
283
230
  }
284
231
  if (typeof item === 'string' || typeof item === 'number') {
285
232
  return item;
@@ -288,87 +235,71 @@ class SdAutocomplete {
288
235
  }));
289
236
  }
290
237
  ngAfterViewInit() {
291
- this.#form?.addControl(this.#name, this.formControl);
238
+ const formGroup = this.form() instanceof NgForm ? this.form().form : this.form();
239
+ formGroup?.addControl(this.name(), this.formControl);
292
240
  }
293
241
  ngOnDestroy() {
294
242
  this.#subscription.unsubscribe();
295
- this.#form?.removeControl(this.#name);
243
+ const formGroup = this.form() instanceof NgForm ? this.form().form : this.form();
244
+ formGroup?.removeControl(this.name());
296
245
  }
297
246
  onSelect = (item) => {
298
- if (item) {
299
- if (typeof item === 'string' || typeof item === 'number') {
300
- if (this.formControl.value !== item) {
301
- this.formControl.setValue(item);
302
- this.modelChange.emit(item);
303
- this.sdChange.emit(item);
304
- this.sdSelection.emit({
305
- values: [item],
306
- selectedItems: [item],
307
- value: item,
308
- selectedItem: item,
309
- });
310
- }
247
+ if (!item)
248
+ return;
249
+ const vField = this.valueField();
250
+ const dField = this.displayField();
251
+ if (typeof item === 'string' || typeof item === 'number') {
252
+ if (this.formControl.value !== item) {
253
+ this.formControl.setValue(item);
254
+ this.valueModel.set(item);
255
+ this.sdChange.emit(item);
256
+ this.sdSelection.emit({ values: [item], selectedItems: [item], value: item, selectedItem: item });
311
257
  }
312
- else if (this.valueField && this.displayField) {
313
- const val = item?.[this.valueField] || null;
314
- if (this.formControl.value !== val) {
315
- this.formControl.setValue(val);
316
- this.modelChange.emit(val);
317
- this.sdChange.emit(val);
318
- this.sdSelection.emit({
319
- values: [val],
320
- selectedItems: [item],
321
- value: val,
322
- selectedItem: item,
323
- });
324
- }
258
+ }
259
+ else if (vField && dField) {
260
+ const val = item?.[vField] || null;
261
+ if (this.formControl.value !== val) {
262
+ this.formControl.setValue(val);
263
+ this.valueModel.set(val);
264
+ this.sdChange.emit(val);
265
+ this.sdSelection.emit({ values: [val], selectedItems: [item], value: val, selectedItem: item });
325
266
  }
326
- this.inputControl.setValue('', {
327
- emitEvent: false,
328
- });
329
267
  }
268
+ this.inputControl.setValue('', { emitEvent: false });
330
269
  };
331
270
  onFocus = () => {
332
271
  this.isFocused = true;
333
272
  this.inputControl.setValue('');
334
- // this.inputControl.updateValueAndValidity();
335
273
  };
336
274
  onBlur = () => {
337
275
  this.isFocused = false;
338
- this.inputControl.setValue('', {
339
- emitEvent: false,
340
- });
276
+ this.inputControl.setValue('', { emitEvent: false });
341
277
  };
342
278
  onClick = () => {
343
- if (this.sdViewDef?.templateRef) {
279
+ if (this.sdViewDef()?.templateRef) {
344
280
  if (!this.formControl.disabled && !this.isFocused) {
345
281
  this.focus();
346
282
  }
347
283
  }
348
284
  };
349
285
  blur = () => {
350
- this.input?.nativeElement?.blur();
286
+ this.input()?.nativeElement?.blur();
351
287
  };
352
288
  focus = () => {
353
289
  this.isFocused = true;
354
290
  setTimeout(() => {
355
- this.autocompleteTrigger?.openPanel();
356
- this.input?.nativeElement?.focus();
291
+ this.autocompleteTrigger()?.openPanel();
292
+ this.input()?.nativeElement?.focus();
357
293
  }, 100);
358
294
  };
359
295
  clear = ($event) => {
360
296
  $event?.stopPropagation();
361
297
  this.inputControl?.setValue('');
362
- if (this.#model) {
298
+ if (this.valueModel()) {
363
299
  this.formControl.setValue(null);
364
- this.modelChange.emit(null);
300
+ this.valueModel.set(null);
365
301
  this.sdChange.emit(null);
366
- this.sdSelection.emit({
367
- values: [null],
368
- selectedItems: [],
369
- value: null,
370
- selectedItem: null,
371
- });
302
+ this.sdSelection.emit({ values: [null], selectedItems: [], value: null, selectedItem: null });
372
303
  }
373
304
  };
374
305
  onAdd = ($event) => {
@@ -379,33 +310,24 @@ class SdAutocomplete {
379
310
  reValidate = () => {
380
311
  this.inputControl.updateValueAndValidity({ emitEvent: true });
381
312
  };
382
- #updateValidator = () => {
383
- this.formControl.clearValidators();
384
- this.formControl.clearAsyncValidators();
313
+ #updateValidator = (req, val, inl) => {
385
314
  const validators = [];
386
315
  const asyncValidators = [];
387
- // const asyncValidators: AsyncValidatorFn[] = [];
388
- if (this.required) {
316
+ if (req)
389
317
  validators.push(Validators.required);
390
- }
391
- if (this.#validator) {
392
- asyncValidators.push(HandleSdCustomValidator(this.#validator));
393
- }
394
- if (this.inlineError) {
318
+ if (val)
319
+ asyncValidators.push(HandleSdCustomValidator(val));
320
+ if (inl)
395
321
  validators.push(this.customInlineErrorValidator());
396
- }
397
- this.formControl.setValidators(validators);
398
- this.formControl.setAsyncValidators(asyncValidators);
322
+ this.formControl.setValidators(validators.length ? validators : null);
323
+ this.formControl.setAsyncValidators(asyncValidators.length ? asyncValidators : null);
399
324
  this.formControl.updateValueAndValidity();
400
325
  };
401
- // Hàm tạo Validators tùy chỉnh cho inlineError
402
326
  customInlineErrorValidator() {
403
- return () => {
404
- return { inlineError: true };
405
- };
327
+ return () => ({ inlineError: true });
406
328
  }
407
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdAutocomplete, deps: [{ token: i0.ChangeDetectorRef }, { token: SD_FORM_CONFIGURATION, optional: true }], target: i0.ɵɵFactoryTarget.Component });
408
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdAutocomplete, isStandalone: true, selector: "sd-autocomplete", inputs: { _autoId: ["autoId", "_autoId"], name: "name", appearance: "appearance", size: "size", form: "form", _label: ["label", "_label"], _helperText: ["helperText", "_helperText"], valueField: "valueField", displayField: "displayField", disabledField: "disabledField", placeholder: "placeholder", items: "items", limit: "limit", cacheChecksum: "cacheChecksum", model: "model", _addable: ["addable", "_addable"], disabled: "disabled", _viewed: ["viewed", "_viewed"], hyperlink: "hyperlink", _required: ["required", "_required"], _validator: ["validator", "_validator"], _inlineError: ["inlineError", "_inlineError"], _hideInlineError: ["hideInlineError", "_hideInlineError"] }, outputs: { modelChange: "modelChange", sdChange: "sdChange", sdSelection: "sdSelection", sdAdd: "sdAdd" }, queries: [{ propertyName: "sdLabelTemplate", first: true, predicate: ["sdLabel"], descendants: true }, { propertyName: "sdValueTemplate", first: true, predicate: ["sdValue"], descendants: true }, { propertyName: "itemDef", first: true, predicate: SdItemDefDefDirective, descendants: true }, { propertyName: "sdViewDef", first: true, predicate: SdViewDefDirective, descendants: true }], viewQueries: [{ propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true, read: MatAutocompleteTrigger }, { propertyName: "input", first: true, predicate: ["input"], descendants: true }], ngImport: i0, template: "@if (viewed) {\r\n <sd-view\r\n [label]=\"label\"\r\n [labelTemplate]=\"sdLabelTemplate\"\r\n [value]=\"formControl.value\"\r\n [display]=\"display | async\"\r\n [hyperlink]=\"hyperlink\"\r\n [valueTemplate]=\"sdValueTemplate\">\r\n </sd-view>\r\n} @else {\r\n @if (!appearance) {\r\n <ng-content select=\"[sdLabel]\">\r\n @if (label) {\r\n <sd-label [label]=\"label\" [required]=\"required\"></sd-label>\r\n }\r\n </ng-content>\r\n }\r\n <div\r\n class=\"d-flex align-items-center\"\r\n [class.sd-view]=\"sdViewDef?.templateRef\"\r\n [class.c-focused]=\"isFocused\"\r\n [class.c-disabled]=\"formControl.disabled\"\r\n (click)=\"onClick()\"\r\n aria-hidden=\"true\">\r\n @if (sdViewDef?.templateRef && !autocompleteTrigger?.panelOpen && !isFocused) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n sdViewDef!.templateRef;\r\n context: {\r\n value: formControl.value,\r\n selectedItem: selected | async,\r\n }\r\n \">\r\n </ng-container>\r\n } @else {\r\n <mat-form-field\r\n [class.sd-md]=\"size === 'md'\"\r\n [class.sd-sm]=\"size === 'sm'\"\r\n [class.hide-inline-error]=\"hideInlineError\"\r\n [floatLabel]=\"formControl.value ? 'always' : 'auto'\"\r\n [appearance]=\"appearance || 'outline'\">\r\n @if (appearance && label) {\r\n <mat-label style=\"display: inline-block\">\r\n <div style=\"display: flex; align-items: center; gap: 4px\">\r\n <span>{{ label }}</span>\r\n @if (helperText) {\r\n <mat-icon [matTooltip]=\"helperText\" matTooltipPosition=\"below\">info_outline</mat-icon>\r\n }\r\n </div>\r\n </mat-label>\r\n }\r\n <input\r\n [id]=\"id\"\r\n [formControl]=\"inputControl\"\r\n [placeholder]=\"(controlPlaceHolder | async) || ''\"\r\n [class.c-selected]=\"formControl.value\"\r\n [matAutocomplete]=\"auto\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n matInput\r\n [autocomplete]=\"id\"\r\n autocorrect=\"off\"\r\n [errorStateMatcher]=\"matcher\"\r\n [required]=\"required\"\r\n #input\r\n #autocompleteTrigger\r\n [attr.data-autoId]=\"autoId\"\r\n aria-hidden=\"true\" />\r\n @if (!loading && formControl.value && !inputControl.disabled) {\r\n <mat-icon class=\"pointer sd-suffix-icon\" (click)=\"clear($event)\" matSuffix>cancel</mat-icon>\r\n } @else if (loading) {\r\n <mat-spinner [diameter]=\"20\" matSuffix></mat-spinner>\r\n } @else {\r\n <mat-icon class=\"pointer sd-suffix-icon\" matSuffix>search</mat-icon>\r\n }\r\n <!-- <i [class.d-none]=\"!loading\" class=\"fa fa-spinner fa-pulse c-loading-icon\"></i> -->\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"onSelect($event.option.value)\" class=\"sd-autocomplete-panel\">\r\n @let items = filteredItems | async;\r\n @if (items?.length) {\r\n <mat-option\r\n *ngFor=\"let item of items\"\r\n [value]=\"item\"\r\n matTooltipPosition=\"above\"\r\n [matTooltip]=\"displayField ? item[displayField] : item\"\r\n [disabled]=\"item[disabledField]\">\r\n <ng-container *ngIf=\"itemDef?.templateRef\">\r\n <ng-container *ngTemplateOutlet=\"itemDef?.templateRef ?? null; context: { item: item }\"> </ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"!itemDef?.templateRef\">\r\n {{ displayField ? item[displayField] : item }}\r\n </ng-container>\r\n </mat-option>\r\n } @else if (!items?.length && inputControl.value && !isTyping && !loading) {}\r\n @if (addable && sdAdd.observers.length) {\r\n <mat-option class=\"sd__option--add\" (keyup.Space)=\"$event.stopPropagation()\" disabled=\"true\">\r\n <div (click)=\"onAdd($event)\">\r\n <mat-icon class=\"mr-1\">add</mat-icon>\r\n {{ 'New item' }}\r\n </div>\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n @if (formControl.errors?.['required']) {\r\n <mat-error>\r\n @if (!hideInlineError) {\r\n Vui l\u00F2ng nh\u1EADp th\u00F4ng tin\r\n }\r\n </mat-error>\r\n }\r\n @if (formControl.errors?.['customValidator']) {\r\n <mat-error>\r\n @if (!hideInlineError) {\r\n {{ formControl.errors?.['customValidator'] }}\r\n }\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n}\r\n", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{padding-top:5px;display:block}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-black100)}:host ::ng-deep .mat-mdc-form-field input.c-selected::placeholder{color:#000;opacity:1}:host ::ng-deep .mat-mdc-form-field input.c-selected:-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.c-selected::-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected:-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}:host ::ng-deep .mat-mdc-form-field:hover .icon-copy{opacity:1}:host ::ng-deep .mat-mdc-form-field .icon-copy{cursor:pointer;width:.9em;height:.9em;fill:#00000080;transition:opacity .2s linear;opacity:0}::ng-deep .sd-autocomplete-panel .mat-mdc-option{min-height:36px!important;padding:8px 12px!important}::ng-deep .sd-autocomplete-panel .mdc-list-item__primary-text{font-size:14px!important;line-height:normal}::ng-deep .sd-autocomplete-panel .mat-pseudo-checkbox{transform:scale(.75);margin-right:8px!important}.sd-view:not(.c-focused):not(.c-disabled):hover{background-color:#ebecf0}.sd__option--add{position:sticky;bottom:0;background-color:#fff;z-index:10;color:#000000de;cursor:pointer!important}.c-loading-icon{position:absolute;right:5px;top:5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: SdLabel, selector: "sd-label", inputs: ["label", "description", "required", "helperText"] }, { kind: "component", type: SdView, selector: "sd-view", inputs: ["label", "value", "display", "hyperlink", "labelTemplate", "valueTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
329
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdAutocomplete, deps: [], target: i0.ɵɵFactoryTarget.Component });
330
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: SdAutocomplete, isStandalone: true, selector: "sd-autocomplete", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, helperText: { classPropertyName: "helperText", publicName: "helperText", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, valueField: { classPropertyName: "valueField", publicName: "valueField", isSignal: true, isRequired: false, transformFunction: null }, displayField: { classPropertyName: "displayField", publicName: "displayField", isSignal: true, isRequired: false, transformFunction: null }, disabledField: { classPropertyName: "disabledField", publicName: "disabledField", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null }, cacheChecksum: { classPropertyName: "cacheChecksum", publicName: "cacheChecksum", isSignal: true, isRequired: false, transformFunction: null }, hyperlink: { classPropertyName: "hyperlink", publicName: "hyperlink", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, hideInlineError: { classPropertyName: "hideInlineError", publicName: "hideInlineError", isSignal: true, isRequired: false, transformFunction: null }, addable: { classPropertyName: "addable", publicName: "addable", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, viewed: { classPropertyName: "viewed", publicName: "viewed", isSignal: true, isRequired: false, transformFunction: null }, validator: { classPropertyName: "validator", publicName: "validator", isSignal: true, isRequired: false, transformFunction: null }, inlineError: { classPropertyName: "inlineError", publicName: "inlineError", isSignal: true, isRequired: false, transformFunction: null }, appearanceInput: { classPropertyName: "appearanceInput", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange", sdChange: "sdChange", sdSelection: "sdSelection", sdAdd: "sdAdd" }, queries: [{ propertyName: "sdLabelTemplate", first: true, predicate: ["sdLabel"], descendants: true, isSignal: true }, { propertyName: "sdValueTemplate", first: true, predicate: ["sdValue"], descendants: true, isSignal: true }, { propertyName: "itemDef", first: true, predicate: SdItemDefDefDirective, descendants: true, isSignal: true }, { propertyName: "sdViewDef", first: true, predicate: SdViewDefDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "input", first: true, predicate: ["input"], descendants: true, isSignal: true }, { propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true, isSignal: true }], ngImport: i0, template: "@if (viewed()) {\r\n <sd-view\r\n [label]=\"label()\"\r\n [labelTemplate]=\"sdLabelTemplate()\"\r\n [value]=\"formControl.value\"\r\n [display]=\"display | async\"\r\n [hyperlink]=\"hyperlink()\"\r\n [valueTemplate]=\"sdValueTemplate()\">\r\n </sd-view>\r\n} @else {\r\n @if (!appearance()) {\r\n <ng-content select=\"[sdLabel]\">\r\n @if (label()) {\r\n <sd-label [label]=\"label()\" [required]=\"required()\"></sd-label>\r\n }\r\n </ng-content>\r\n }\r\n <div\r\n class=\"d-flex align-items-center\"\r\n [class.sd-view]=\"sdViewDef()?.templateRef\"\r\n [class.c-focused]=\"isFocused\"\r\n [class.c-disabled]=\"formControl.disabled\"\r\n (click)=\"onClick()\"\r\n aria-hidden=\"true\">\r\n \r\n @if (sdViewDef()?.templateRef && !autocompleteTrigger()?.panelOpen && !isFocused) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n sdViewDef()!.templateRef;\r\n context: {\r\n value: formControl.value,\r\n selectedItem: selected | async,\r\n }\r\n \">\r\n </ng-container>\r\n } @else {\r\n <mat-form-field\r\n [class.sd-md]=\"size() === 'md'\"\r\n [class.sd-sm]=\"size() === 'sm'\"\r\n [class.hide-inline-error]=\"hideInlineError()\"\r\n [floatLabel]=\"formControl.value ? 'always' : 'auto'\"\r\n [appearance]=\"appearance() || 'outline'\">\r\n \r\n @if (appearance() && label()) {\r\n <mat-label style=\"display: inline-block\">\r\n <div style=\"display: flex; align-items: center; gap: 4px\">\r\n <span>{{ label() }}</span>\r\n @if (helperText()) {\r\n <mat-icon [matTooltip]=\"helperText()!\" matTooltipPosition=\"below\">info_outline</mat-icon>\r\n }\r\n </div>\r\n </mat-label>\r\n }\r\n \r\n <input\r\n [id]=\"id\"\r\n [formControl]=\"inputControl\"\r\n [placeholder]=\"(controlPlaceHolder | async) || ''\"\r\n [class.c-selected]=\"formControl.value\"\r\n [matAutocomplete]=\"auto\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n matInput\r\n [autocomplete]=\"id\"\r\n autocorrect=\"off\"\r\n [errorStateMatcher]=\"matcher\"\r\n [required]=\"required()\"\r\n #input\r\n #autocompleteTrigger=\"matAutocompleteTrigger\"\r\n [attr.data-autoId]=\"autoId()\"\r\n aria-hidden=\"true\" />\r\n \r\n @if (!loading && formControl.value && !inputControl.disabled) {\r\n <mat-icon class=\"pointer sd-suffix-icon\" (click)=\"clear($event)\" matSuffix>cancel</mat-icon>\r\n } @else if (loading) {\r\n <mat-spinner [diameter]=\"20\" matSuffix></mat-spinner>\r\n } @else {\r\n <mat-icon class=\"pointer sd-suffix-icon\" matSuffix>search</mat-icon>\r\n }\r\n\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"onSelect($event.option.value)\" class=\"sd-autocomplete-panel\">\r\n @let itemsList = filteredItems | async;\r\n \r\n @if (itemsList?.length) {\r\n @for (item of itemsList; track $index) {\r\n <mat-option\r\n [value]=\"item\"\r\n matTooltipPosition=\"above\"\r\n [matTooltip]=\"displayField() ? item[displayField()!] : item\"\r\n [disabled]=\"disabledField() ? item[disabledField()] : false\">\r\n \r\n @if (itemDef()?.templateRef) {\r\n <ng-container *ngTemplateOutlet=\"itemDef()!.templateRef ?? null; context: { item: item }\"> </ng-container>\r\n } @else {\r\n {{ displayField() ? item[displayField()!] : item }}\r\n }\r\n </mat-option>\r\n }\r\n } @else if (!itemsList?.length && inputControl.value && !isTyping && !loading) {\r\n }\r\n \r\n @if (addable() && sdAdd.observed) {\r\n <mat-option class=\"sd__option--add\" (keyup.Space)=\"$event.stopPropagation()\" disabled=\"true\">\r\n <div (click)=\"onAdd($event)\">\r\n <mat-icon class=\"mr-1\">add</mat-icon>\r\n {{ 'New item' }}\r\n </div>\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n @if (formControl.errors?.['required']) {\r\n <mat-error>\r\n @if (!hideInlineError()) {\r\n Vui l\u00F2ng nh\u1EADp th\u00F4ng tin\r\n }\r\n </mat-error>\r\n }\r\n @if (formControl.errors?.['customValidator']) {\r\n <mat-error>\r\n @if (!hideInlineError()) {\r\n {{ formControl.errors?.['customValidator'] }}\r\n }\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n}", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{padding-top:5px;display:block}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-black100)}:host ::ng-deep .mat-mdc-form-field input.c-selected::placeholder{color:#000;opacity:1}:host ::ng-deep .mat-mdc-form-field input.c-selected:-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.c-selected::-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected:-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}:host ::ng-deep .mat-mdc-form-field:hover .icon-copy{opacity:1}:host ::ng-deep .mat-mdc-form-field .icon-copy{cursor:pointer;width:.9em;height:.9em;fill:#00000080;transition:opacity .2s linear;opacity:0}::ng-deep .sd-autocomplete-panel .mat-mdc-option{min-height:36px!important;padding:8px 12px!important}::ng-deep .sd-autocomplete-panel .mdc-list-item__primary-text{font-size:14px!important;line-height:normal}::ng-deep .sd-autocomplete-panel .mat-pseudo-checkbox{transform:scale(.75);margin-right:8px!important}.sd-view:not(.c-focused):not(.c-disabled):hover{background-color:#ebecf0}.sd__option--add{position:sticky;bottom:0;background-color:#fff;z-index:10;color:#000000de;cursor:pointer!important}.c-loading-icon{position:absolute;right:5px;top:5px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i3.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i3.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i5.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i7.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: SdLabel, selector: "sd-label", inputs: ["label", "description", "required", "helperText"] }, { kind: "component", type: SdView, selector: "sd-view", inputs: ["label", "value", "display", "hyperlink", "labelTemplate", "valueTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
409
331
  }
410
332
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdAutocomplete, decorators: [{
411
333
  type: Component,
@@ -421,93 +343,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
421
343
  MatProgressSpinnerModule,
422
344
  SdLabel,
423
345
  SdView
424
- ], template: "@if (viewed) {\r\n <sd-view\r\n [label]=\"label\"\r\n [labelTemplate]=\"sdLabelTemplate\"\r\n [value]=\"formControl.value\"\r\n [display]=\"display | async\"\r\n [hyperlink]=\"hyperlink\"\r\n [valueTemplate]=\"sdValueTemplate\">\r\n </sd-view>\r\n} @else {\r\n @if (!appearance) {\r\n <ng-content select=\"[sdLabel]\">\r\n @if (label) {\r\n <sd-label [label]=\"label\" [required]=\"required\"></sd-label>\r\n }\r\n </ng-content>\r\n }\r\n <div\r\n class=\"d-flex align-items-center\"\r\n [class.sd-view]=\"sdViewDef?.templateRef\"\r\n [class.c-focused]=\"isFocused\"\r\n [class.c-disabled]=\"formControl.disabled\"\r\n (click)=\"onClick()\"\r\n aria-hidden=\"true\">\r\n @if (sdViewDef?.templateRef && !autocompleteTrigger?.panelOpen && !isFocused) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n sdViewDef!.templateRef;\r\n context: {\r\n value: formControl.value,\r\n selectedItem: selected | async,\r\n }\r\n \">\r\n </ng-container>\r\n } @else {\r\n <mat-form-field\r\n [class.sd-md]=\"size === 'md'\"\r\n [class.sd-sm]=\"size === 'sm'\"\r\n [class.hide-inline-error]=\"hideInlineError\"\r\n [floatLabel]=\"formControl.value ? 'always' : 'auto'\"\r\n [appearance]=\"appearance || 'outline'\">\r\n @if (appearance && label) {\r\n <mat-label style=\"display: inline-block\">\r\n <div style=\"display: flex; align-items: center; gap: 4px\">\r\n <span>{{ label }}</span>\r\n @if (helperText) {\r\n <mat-icon [matTooltip]=\"helperText\" matTooltipPosition=\"below\">info_outline</mat-icon>\r\n }\r\n </div>\r\n </mat-label>\r\n }\r\n <input\r\n [id]=\"id\"\r\n [formControl]=\"inputControl\"\r\n [placeholder]=\"(controlPlaceHolder | async) || ''\"\r\n [class.c-selected]=\"formControl.value\"\r\n [matAutocomplete]=\"auto\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n matInput\r\n [autocomplete]=\"id\"\r\n autocorrect=\"off\"\r\n [errorStateMatcher]=\"matcher\"\r\n [required]=\"required\"\r\n #input\r\n #autocompleteTrigger\r\n [attr.data-autoId]=\"autoId\"\r\n aria-hidden=\"true\" />\r\n @if (!loading && formControl.value && !inputControl.disabled) {\r\n <mat-icon class=\"pointer sd-suffix-icon\" (click)=\"clear($event)\" matSuffix>cancel</mat-icon>\r\n } @else if (loading) {\r\n <mat-spinner [diameter]=\"20\" matSuffix></mat-spinner>\r\n } @else {\r\n <mat-icon class=\"pointer sd-suffix-icon\" matSuffix>search</mat-icon>\r\n }\r\n <!-- <i [class.d-none]=\"!loading\" class=\"fa fa-spinner fa-pulse c-loading-icon\"></i> -->\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"onSelect($event.option.value)\" class=\"sd-autocomplete-panel\">\r\n @let items = filteredItems | async;\r\n @if (items?.length) {\r\n <mat-option\r\n *ngFor=\"let item of items\"\r\n [value]=\"item\"\r\n matTooltipPosition=\"above\"\r\n [matTooltip]=\"displayField ? item[displayField] : item\"\r\n [disabled]=\"item[disabledField]\">\r\n <ng-container *ngIf=\"itemDef?.templateRef\">\r\n <ng-container *ngTemplateOutlet=\"itemDef?.templateRef ?? null; context: { item: item }\"> </ng-container>\r\n </ng-container>\r\n <ng-container *ngIf=\"!itemDef?.templateRef\">\r\n {{ displayField ? item[displayField] : item }}\r\n </ng-container>\r\n </mat-option>\r\n } @else if (!items?.length && inputControl.value && !isTyping && !loading) {}\r\n @if (addable && sdAdd.observers.length) {\r\n <mat-option class=\"sd__option--add\" (keyup.Space)=\"$event.stopPropagation()\" disabled=\"true\">\r\n <div (click)=\"onAdd($event)\">\r\n <mat-icon class=\"mr-1\">add</mat-icon>\r\n {{ 'New item' }}\r\n </div>\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n @if (formControl.errors?.['required']) {\r\n <mat-error>\r\n @if (!hideInlineError) {\r\n Vui l\u00F2ng nh\u1EADp th\u00F4ng tin\r\n }\r\n </mat-error>\r\n }\r\n @if (formControl.errors?.['customValidator']) {\r\n <mat-error>\r\n @if (!hideInlineError) {\r\n {{ formControl.errors?.['customValidator'] }}\r\n }\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n}\r\n", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{padding-top:5px;display:block}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-black100)}:host ::ng-deep .mat-mdc-form-field input.c-selected::placeholder{color:#000;opacity:1}:host ::ng-deep .mat-mdc-form-field input.c-selected:-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.c-selected::-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected:-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}:host ::ng-deep .mat-mdc-form-field:hover .icon-copy{opacity:1}:host ::ng-deep .mat-mdc-form-field .icon-copy{cursor:pointer;width:.9em;height:.9em;fill:#00000080;transition:opacity .2s linear;opacity:0}::ng-deep .sd-autocomplete-panel .mat-mdc-option{min-height:36px!important;padding:8px 12px!important}::ng-deep .sd-autocomplete-panel .mdc-list-item__primary-text{font-size:14px!important;line-height:normal}::ng-deep .sd-autocomplete-panel .mat-pseudo-checkbox{transform:scale(.75);margin-right:8px!important}.sd-view:not(.c-focused):not(.c-disabled):hover{background-color:#ebecf0}.sd__option--add{position:sticky;bottom:0;background-color:#fff;z-index:10;color:#000000de;cursor:pointer!important}.c-loading-icon{position:absolute;right:5px;top:5px}\n"] }]
425
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
426
- type: Inject,
427
- args: [SD_FORM_CONFIGURATION]
428
- }, {
429
- type: Optional
430
- }] }], propDecorators: { sdLabelTemplate: [{
431
- type: ContentChild,
432
- args: ['sdLabel']
433
- }], sdValueTemplate: [{
434
- type: ContentChild,
435
- args: ['sdValue']
436
- }], _autoId: [{
437
- type: Input,
438
- args: ['autoId']
439
- }], autocompleteTrigger: [{
440
- type: ViewChild,
441
- args: [MatAutocompleteTrigger, { read: MatAutocompleteTrigger }]
442
- }], name: [{
443
- type: Input
444
- }], appearance: [{
445
- type: Input
446
- }], size: [{
447
- type: Input
448
- }], form: [{
449
- type: Input
450
- }], _label: [{
451
- type: Input,
452
- args: ['label']
453
- }], _helperText: [{
454
- type: Input,
455
- args: ['helperText']
456
- }], valueField: [{
457
- type: Input
458
- }], displayField: [{
459
- type: Input
460
- }], disabledField: [{
461
- type: Input
462
- }], placeholder: [{
463
- type: Input
464
- }], items: [{
465
- type: Input
466
- }], limit: [{
467
- type: Input
468
- }], cacheChecksum: [{
469
- type: Input
470
- }], model: [{
471
- type: Input
472
- }], _addable: [{
473
- type: Input,
474
- args: ['addable']
475
- }], itemDef: [{
476
- type: ContentChild,
477
- args: [SdItemDefDefDirective]
478
- }], modelChange: [{
479
- type: Output
480
- }], sdChange: [{
481
- type: Output
482
- }], sdSelection: [{
483
- type: Output
484
- }], sdAdd: [{
346
+ ], template: "@if (viewed()) {\r\n <sd-view\r\n [label]=\"label()\"\r\n [labelTemplate]=\"sdLabelTemplate()\"\r\n [value]=\"formControl.value\"\r\n [display]=\"display | async\"\r\n [hyperlink]=\"hyperlink()\"\r\n [valueTemplate]=\"sdValueTemplate()\">\r\n </sd-view>\r\n} @else {\r\n @if (!appearance()) {\r\n <ng-content select=\"[sdLabel]\">\r\n @if (label()) {\r\n <sd-label [label]=\"label()\" [required]=\"required()\"></sd-label>\r\n }\r\n </ng-content>\r\n }\r\n <div\r\n class=\"d-flex align-items-center\"\r\n [class.sd-view]=\"sdViewDef()?.templateRef\"\r\n [class.c-focused]=\"isFocused\"\r\n [class.c-disabled]=\"formControl.disabled\"\r\n (click)=\"onClick()\"\r\n aria-hidden=\"true\">\r\n \r\n @if (sdViewDef()?.templateRef && !autocompleteTrigger()?.panelOpen && !isFocused) {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n sdViewDef()!.templateRef;\r\n context: {\r\n value: formControl.value,\r\n selectedItem: selected | async,\r\n }\r\n \">\r\n </ng-container>\r\n } @else {\r\n <mat-form-field\r\n [class.sd-md]=\"size() === 'md'\"\r\n [class.sd-sm]=\"size() === 'sm'\"\r\n [class.hide-inline-error]=\"hideInlineError()\"\r\n [floatLabel]=\"formControl.value ? 'always' : 'auto'\"\r\n [appearance]=\"appearance() || 'outline'\">\r\n \r\n @if (appearance() && label()) {\r\n <mat-label style=\"display: inline-block\">\r\n <div style=\"display: flex; align-items: center; gap: 4px\">\r\n <span>{{ label() }}</span>\r\n @if (helperText()) {\r\n <mat-icon [matTooltip]=\"helperText()!\" matTooltipPosition=\"below\">info_outline</mat-icon>\r\n }\r\n </div>\r\n </mat-label>\r\n }\r\n \r\n <input\r\n [id]=\"id\"\r\n [formControl]=\"inputControl\"\r\n [placeholder]=\"(controlPlaceHolder | async) || ''\"\r\n [class.c-selected]=\"formControl.value\"\r\n [matAutocomplete]=\"auto\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n matInput\r\n [autocomplete]=\"id\"\r\n autocorrect=\"off\"\r\n [errorStateMatcher]=\"matcher\"\r\n [required]=\"required()\"\r\n #input\r\n #autocompleteTrigger=\"matAutocompleteTrigger\"\r\n [attr.data-autoId]=\"autoId()\"\r\n aria-hidden=\"true\" />\r\n \r\n @if (!loading && formControl.value && !inputControl.disabled) {\r\n <mat-icon class=\"pointer sd-suffix-icon\" (click)=\"clear($event)\" matSuffix>cancel</mat-icon>\r\n } @else if (loading) {\r\n <mat-spinner [diameter]=\"20\" matSuffix></mat-spinner>\r\n } @else {\r\n <mat-icon class=\"pointer sd-suffix-icon\" matSuffix>search</mat-icon>\r\n }\r\n\r\n <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"onSelect($event.option.value)\" class=\"sd-autocomplete-panel\">\r\n @let itemsList = filteredItems | async;\r\n \r\n @if (itemsList?.length) {\r\n @for (item of itemsList; track $index) {\r\n <mat-option\r\n [value]=\"item\"\r\n matTooltipPosition=\"above\"\r\n [matTooltip]=\"displayField() ? item[displayField()!] : item\"\r\n [disabled]=\"disabledField() ? item[disabledField()] : false\">\r\n \r\n @if (itemDef()?.templateRef) {\r\n <ng-container *ngTemplateOutlet=\"itemDef()!.templateRef ?? null; context: { item: item }\"> </ng-container>\r\n } @else {\r\n {{ displayField() ? item[displayField()!] : item }}\r\n }\r\n </mat-option>\r\n }\r\n } @else if (!itemsList?.length && inputControl.value && !isTyping && !loading) {\r\n }\r\n \r\n @if (addable() && sdAdd.observed) {\r\n <mat-option class=\"sd__option--add\" (keyup.Space)=\"$event.stopPropagation()\" disabled=\"true\">\r\n <div (click)=\"onAdd($event)\">\r\n <mat-icon class=\"mr-1\">add</mat-icon>\r\n {{ 'New item' }}\r\n </div>\r\n </mat-option>\r\n }\r\n </mat-autocomplete>\r\n\r\n @if (formControl.errors?.['required']) {\r\n <mat-error>\r\n @if (!hideInlineError()) {\r\n Vui l\u00F2ng nh\u1EADp th\u00F4ng tin\r\n }\r\n </mat-error>\r\n }\r\n @if (formControl.errors?.['customValidator']) {\r\n <mat-error>\r\n @if (!hideInlineError()) {\r\n {{ formControl.errors?.['customValidator'] }}\r\n }\r\n </mat-error>\r\n }\r\n </mat-form-field>\r\n }\r\n </div>\r\n}", styles: [".text-primary{color:var(--sd-primary)!important}.bg-primary{background:var(--sd-primary)!important}.border-primary{border-color:var(--sd-primary)!important}.text-primary-light{color:var(--sd-primary-light)!important}.bg-primary-light{background:var(--sd-primary-light)!important}.border-primary-light{border-color:var(--sd-primary-light)!important}.text-primary-dark{color:var(--sd-primary-dark)!important}.bg-primary-dark{background:var(--sd-primary-dark)!important}.border-primary-dark{border-color:var(--sd-primary-dark)!important}.text-info{color:var(--sd-info)!important}.bg-info{background:var(--sd-info)!important}.border-info{border-color:var(--sd-info)!important}.text-info-light{color:var(--sd-info-light)!important}.bg-info-light{background:var(--sd-info-light)!important}.border-info-light{border-color:var(--sd-info-light)!important}.text-info-dark{color:var(--sd-info-dark)!important}.bg-info-dark{background:var(--sd-info-dark)!important}.border-info-dark{border-color:var(--sd-info-dark)!important}.text-success{color:var(--sd-success)!important}.bg-success{background:var(--sd-success)!important}.border-success{border-color:var(--sd-success)!important}.text-success-light{color:var(--sd-success-light)!important}.bg-success-light{background:var(--sd-success-light)!important}.border-success-light{border-color:var(--sd-success-light)!important}.text-success-dark{color:var(--sd-success-dark)!important}.bg-success-dark{background:var(--sd-success-dark)!important}.border-success-dark{border-color:var(--sd-success-dark)!important}.text-warning{color:var(--sd-warning)!important}.bg-warning{background:var(--sd-warning)!important}.border-warning{border-color:var(--sd-warning)!important}.text-warning-light{color:var(--sd-warning-light)!important}.bg-warning-light{background:var(--sd-warning-light)!important}.border-warning-light{border-color:var(--sd-warning-light)!important}.text-warning-dark{color:var(--sd-warning-dark)!important}.bg-warning-dark{background:var(--sd-warning-dark)!important}.border-warning-dark{border-color:var(--sd-warning-dark)!important}.text-error{color:var(--sd-error)!important}.bg-error{background:var(--sd-error)!important}.border-error{border-color:var(--sd-error)!important}.text-error-light{color:var(--sd-error-light)!important}.bg-error-light{background:var(--sd-error-light)!important}.border-error-light{border-color:var(--sd-error-light)!important}.text-error-dark{color:var(--sd-error-dark)!important}.bg-error-dark{background:var(--sd-error-dark)!important}.border-error-dark{border-color:var(--sd-error-dark)!important}.text-secondary{color:var(--sd-secondary)!important}.bg-secondary{background:var(--sd-secondary)!important}.border-secondary{border-color:var(--sd-secondary)!important}.text-secondary-light{color:var(--sd-secondary-light)!important}.bg-secondary-light{background:var(--sd-secondary-light)!important}.border-secondary-light{border-color:var(--sd-secondary-light)!important}.text-secondary-dark{color:var(--sd-secondary-dark)!important}.bg-secondary-dark{background:var(--sd-secondary-dark)!important}.border-secondary-dark{border-color:var(--sd-secondary-dark)!important}.text-light{color:var(--sd-light)!important}.bg-light{background:var(--sd-light)!important}.border-light{border-color:var(--sd-light)!important}.text-dark{color:var(--sd-dark)!important}.bg-dark{background:var(--sd-dark)!important}.border-dark{border-color:var(--sd-dark)!important}.text-black500{color:var(--sd-black500)!important}.bg-black500{background:var(--sd-black500)!important}.border-black500{border-color:var(--sd-black500)!important}.text-black400{color:var(--sd-black400)!important}.bg-black400{background:var(--sd-black400)!important}.border-black400{border-color:var(--sd-black400)!important}.text-black300{color:var(--sd-black300)!important}.bg-black300{background:var(--sd-black300)!important}.border-black300{border-color:var(--sd-black300)!important}.text-black200{color:var(--sd-black200)!important}.bg-black200{background:var(--sd-black200)!important}.border-black200{border-color:var(--sd-black200)!important}.text-black100{color:var(--sd-black100)!important}.bg-black100{background:var(--sd-black100)!important}.border-black100{border-color:var(--sd-black100)!important}.text-white{color:#fff!important}.bg-white{background:#fff!important}.border-white{border-color:#fff!important}.text-black{color:#000!important}.bg-black{background:#000!important}.border-black{border-color:#000!important}:host{padding-top:5px;display:block}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-black100)}:host ::ng-deep .mat-mdc-form-field input.c-selected::placeholder{color:#000;opacity:1}:host ::ng-deep .mat-mdc-form-field input.c-selected:-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.c-selected::-ms-input-placeholder{color:#000}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected:-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled.c-selected::-ms-input-placeholder{color:var(--sd-black400)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}:host ::ng-deep .mat-mdc-form-field:hover .icon-copy{opacity:1}:host ::ng-deep .mat-mdc-form-field .icon-copy{cursor:pointer;width:.9em;height:.9em;fill:#00000080;transition:opacity .2s linear;opacity:0}::ng-deep .sd-autocomplete-panel .mat-mdc-option{min-height:36px!important;padding:8px 12px!important}::ng-deep .sd-autocomplete-panel .mdc-list-item__primary-text{font-size:14px!important;line-height:normal}::ng-deep .sd-autocomplete-panel .mat-pseudo-checkbox{transform:scale(.75);margin-right:8px!important}.sd-view:not(.c-focused):not(.c-disabled):hover{background-color:#ebecf0}.sd__option--add{position:sticky;bottom:0;background-color:#fff;z-index:10;color:#000000de;cursor:pointer!important}.c-loading-icon{position:absolute;right:5px;top:5px}\n"] }]
347
+ }], ctorParameters: () => [], propDecorators: { sdAdd: [{
485
348
  type: Output
486
- }], disabled: [{
487
- type: Input
488
- }], _viewed: [{
489
- type: Input,
490
- args: ['viewed']
491
- }], hyperlink: [{
492
- type: Input
493
- }], _required: [{
494
- type: Input,
495
- args: ['required']
496
- }], _validator: [{
497
- type: Input,
498
- args: ['validator']
499
- }], _inlineError: [{
500
- type: Input,
501
- args: ['inlineError']
502
- }], _hideInlineError: [{
503
- type: Input,
504
- args: ['hideInlineError']
505
- }], input: [{
506
- type: ViewChild,
507
- args: ['input']
508
- }], sdViewDef: [{
509
- type: ContentChild,
510
- args: [SdViewDefDirective]
511
349
  }] } });
512
350
 
513
351
  /**