@sdcorejs/angular 21.1.2 → 21.1.4

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 (177) hide show
  1. package/README.md +127 -807
  2. package/fesm2022/sdcorejs-angular-components-anchor.mjs +14 -14
  3. package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
  4. package/fesm2022/sdcorejs-angular-components-audit-diff.mjs +332 -0
  5. package/fesm2022/sdcorejs-angular-components-audit-diff.mjs.map +1 -0
  6. package/fesm2022/sdcorejs-angular-components-badge.mjs +1 -0
  7. package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
  8. package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs +121 -0
  9. package/fesm2022/sdcorejs-angular-components-breadcrumb.mjs.map +1 -0
  10. package/fesm2022/sdcorejs-angular-components-data-state.mjs +68 -0
  11. package/fesm2022/sdcorejs-angular-components-data-state.mjs.map +1 -0
  12. package/fesm2022/sdcorejs-angular-components-document-builder.mjs +18 -23
  13. package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
  14. package/fesm2022/sdcorejs-angular-components-editor.mjs +6 -4
  15. package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
  16. package/fesm2022/sdcorejs-angular-components-form-generic.mjs +633 -886
  17. package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
  18. package/fesm2022/sdcorejs-angular-components-import-excel.mjs +26 -41
  19. package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
  20. package/fesm2022/sdcorejs-angular-components-job-progress.mjs +97 -0
  21. package/fesm2022/sdcorejs-angular-components-job-progress.mjs.map +1 -0
  22. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +10 -20
  23. package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -1
  24. package/fesm2022/sdcorejs-angular-components-modal.mjs +61 -4
  25. package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
  26. package/fesm2022/sdcorejs-angular-components-preview.mjs +1438 -218
  27. package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
  28. package/fesm2022/sdcorejs-angular-components-query-bar.mjs +9 -17
  29. package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
  30. package/fesm2022/sdcorejs-angular-components-query-builder.mjs +1 -1
  31. package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -1
  32. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +39 -2
  33. package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
  34. package/fesm2022/sdcorejs-angular-components-tab-router.mjs +76 -52
  35. package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -1
  36. package/fesm2022/sdcorejs-angular-components-tab.mjs +48 -4
  37. package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -1
  38. package/fesm2022/sdcorejs-angular-components-table.mjs +123 -89
  39. package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
  40. package/fesm2022/sdcorejs-angular-components-tree.mjs +188 -18
  41. package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
  42. package/fesm2022/sdcorejs-angular-components-upload-file.mjs +17 -23
  43. package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
  44. package/fesm2022/sdcorejs-angular-components.mjs +4 -0
  45. package/fesm2022/sdcorejs-angular-components.mjs.map +1 -1
  46. package/fesm2022/sdcorejs-angular-directives.mjs +29 -41
  47. package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -1
  48. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +9 -8
  49. package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
  50. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +20 -71
  51. package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
  52. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +8 -4
  53. package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
  54. package/fesm2022/sdcorejs-angular-forms-chip.mjs +8 -4
  55. package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
  56. package/fesm2022/sdcorejs-angular-forms-date-range.mjs +18 -14
  57. package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
  58. package/fesm2022/sdcorejs-angular-forms-date.mjs +48 -70
  59. package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
  60. package/fesm2022/sdcorejs-angular-forms-datetime.mjs +62 -528
  61. package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
  62. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs +384 -0
  63. package/fesm2022/sdcorejs-angular-forms-entity-picker.mjs.map +1 -0
  64. package/fesm2022/sdcorejs-angular-forms-input-color.mjs +5 -3
  65. package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -1
  66. package/fesm2022/sdcorejs-angular-forms-input-number.mjs +16 -11
  67. package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
  68. package/fesm2022/sdcorejs-angular-forms-input.mjs +297 -59
  69. package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
  70. package/fesm2022/sdcorejs-angular-forms-models.mjs +155 -2
  71. package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -1
  72. package/fesm2022/sdcorejs-angular-forms-radio.mjs +44 -66
  73. package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
  74. package/fesm2022/sdcorejs-angular-forms-select.mjs +8 -21
  75. package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
  76. package/fesm2022/sdcorejs-angular-forms-switch.mjs +19 -64
  77. package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
  78. package/fesm2022/sdcorejs-angular-forms-textarea.mjs +8 -6
  79. package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
  80. package/fesm2022/sdcorejs-angular-forms-time-range.mjs +277 -0
  81. package/fesm2022/sdcorejs-angular-forms-time-range.mjs.map +1 -0
  82. package/fesm2022/sdcorejs-angular-forms-time.mjs +307 -0
  83. package/fesm2022/sdcorejs-angular-forms-time.mjs.map +1 -0
  84. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs +210 -0
  85. package/fesm2022/sdcorejs-angular-forms-tree-select.mjs.map +1 -0
  86. package/fesm2022/sdcorejs-angular-forms.mjs +73 -4
  87. package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -1
  88. package/fesm2022/sdcorejs-angular-i18n.mjs +355 -10
  89. package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -1
  90. package/fesm2022/sdcorejs-angular-interceptors.mjs +12 -17
  91. package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -1
  92. package/fesm2022/sdcorejs-angular-modules-icon.mjs.map +1 -1
  93. package/fesm2022/sdcorejs-angular-modules-layout.mjs +861 -80
  94. package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
  95. package/fesm2022/sdcorejs-angular-modules.mjs +0 -1
  96. package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -1
  97. package/fesm2022/sdcorejs-angular-pipes.mjs +5 -7
  98. package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -1
  99. package/fesm2022/sdcorejs-angular-services-api.mjs +407 -137
  100. package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
  101. package/fesm2022/sdcorejs-angular-services-cache.mjs +515 -105
  102. package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -1
  103. package/fesm2022/sdcorejs-angular-services-confirm.mjs +5 -7
  104. package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
  105. package/fesm2022/sdcorejs-angular-services-docx.mjs +7 -10
  106. package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -1
  107. package/fesm2022/sdcorejs-angular-services-loading.mjs +340 -66
  108. package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -1
  109. package/fesm2022/sdcorejs-angular-services-notify.mjs +7 -10
  110. package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -1
  111. package/fesm2022/sdcorejs-angular-services-persistence.mjs +899 -0
  112. package/fesm2022/sdcorejs-angular-services-persistence.mjs.map +1 -0
  113. package/fesm2022/sdcorejs-angular-services-storage.mjs +324 -122
  114. package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -1
  115. package/fesm2022/sdcorejs-angular-services-task.mjs +389 -0
  116. package/fesm2022/sdcorejs-angular-services-task.mjs.map +1 -0
  117. package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs +255 -0
  118. package/fesm2022/sdcorejs-angular-services-unsaved-changes.mjs.map +1 -0
  119. package/fesm2022/sdcorejs-angular-services-viewport.mjs +76 -0
  120. package/fesm2022/sdcorejs-angular-services-viewport.mjs.map +1 -0
  121. package/fesm2022/sdcorejs-angular-services.mjs +4 -0
  122. package/fesm2022/sdcorejs-angular-services.mjs.map +1 -1
  123. package/package.json +50 -5
  124. package/types/sdcorejs-angular-components-audit-diff.d.ts +74 -0
  125. package/types/sdcorejs-angular-components-badge.d.ts +1 -1
  126. package/types/sdcorejs-angular-components-breadcrumb.d.ts +53 -0
  127. package/types/sdcorejs-angular-components-data-state.d.ts +44 -0
  128. package/types/sdcorejs-angular-components-document-builder.d.ts +5 -5
  129. package/types/sdcorejs-angular-components-form-generic.d.ts +89 -103
  130. package/types/sdcorejs-angular-components-import-excel.d.ts +4 -14
  131. package/types/sdcorejs-angular-components-job-progress.d.ts +38 -0
  132. package/types/sdcorejs-angular-components-mini-editor.d.ts +9 -9
  133. package/types/sdcorejs-angular-components-modal.d.ts +7 -1
  134. package/types/sdcorejs-angular-components-preview.d.ts +181 -28
  135. package/types/sdcorejs-angular-components-side-drawer.d.ts +7 -1
  136. package/types/sdcorejs-angular-components-tab.d.ts +9 -2
  137. package/types/sdcorejs-angular-components-table.d.ts +8 -7
  138. package/types/sdcorejs-angular-components-tree.d.ts +24 -2
  139. package/types/sdcorejs-angular-components-upload-file.d.ts +5 -4
  140. package/types/sdcorejs-angular-components.d.ts +4 -0
  141. package/types/sdcorejs-angular-directives.d.ts +10 -8
  142. package/types/sdcorejs-angular-forms-autocomplete.d.ts +3 -4
  143. package/types/sdcorejs-angular-forms-checkbox.d.ts +4 -8
  144. package/types/sdcorejs-angular-forms-date-range.d.ts +6 -7
  145. package/types/sdcorejs-angular-forms-date.d.ts +3 -3
  146. package/types/sdcorejs-angular-forms-datetime.d.ts +3 -3
  147. package/types/sdcorejs-angular-forms-entity-picker.d.ts +128 -0
  148. package/types/sdcorejs-angular-forms-input-color.d.ts +3 -1
  149. package/types/sdcorejs-angular-forms-input-number.d.ts +4 -2
  150. package/types/sdcorejs-angular-forms-input.d.ts +76 -11
  151. package/types/sdcorejs-angular-forms-models.d.ts +86 -3
  152. package/types/sdcorejs-angular-forms-radio.d.ts +12 -8
  153. package/types/sdcorejs-angular-forms-switch.d.ts +4 -7
  154. package/types/sdcorejs-angular-forms-time-range.d.ts +98 -0
  155. package/types/sdcorejs-angular-forms-time.d.ts +117 -0
  156. package/types/sdcorejs-angular-forms-tree-select.d.ts +76 -0
  157. package/types/sdcorejs-angular-forms.d.ts +15 -5
  158. package/types/sdcorejs-angular-i18n.d.ts +68 -2
  159. package/types/sdcorejs-angular-interceptors.d.ts +5 -6
  160. package/types/sdcorejs-angular-modules-icon.d.ts +2 -3
  161. package/types/sdcorejs-angular-modules-layout.d.ts +288 -15
  162. package/types/sdcorejs-angular-modules.d.ts +0 -1
  163. package/types/sdcorejs-angular-pipes.d.ts +2 -2
  164. package/types/sdcorejs-angular-services-api.d.ts +68 -24
  165. package/types/sdcorejs-angular-services-cache.d.ts +52 -16
  166. package/types/sdcorejs-angular-services-confirm.d.ts +3 -2
  167. package/types/sdcorejs-angular-services-docx.d.ts +2 -3
  168. package/types/sdcorejs-angular-services-loading.d.ts +16 -8
  169. package/types/sdcorejs-angular-services-persistence.d.ts +159 -0
  170. package/types/sdcorejs-angular-services-storage.d.ts +26 -8
  171. package/types/sdcorejs-angular-services-task.d.ts +104 -0
  172. package/types/sdcorejs-angular-services-unsaved-changes.d.ts +83 -0
  173. package/types/sdcorejs-angular-services-viewport.d.ts +42 -0
  174. package/types/sdcorejs-angular-services.d.ts +4 -0
  175. package/fesm2022/sdcorejs-angular-modules-authom.mjs +0 -360
  176. package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +0 -1
  177. package/types/sdcorejs-angular-modules-authom.d.ts +0 -70
@@ -1,7 +1,7 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { viewChild, contentChild, input, computed, inject, ChangeDetectorRef, booleanAttribute, model, output, EventEmitter, effect, untracked, Output, ChangeDetectionStrategy, Component } from '@angular/core';
4
+ import { viewChild, contentChild, input, computed, inject, ChangeDetectorRef, booleanAttribute, model, output, EventEmitter, signal, effect, untracked, Output, ChangeDetectionStrategy, Component } from '@angular/core';
5
5
  import { Utilities } from '@sdcorejs/utils/fns';
6
6
  import * as i2 from '@angular/forms';
7
7
  import { NgForm, FormGroup, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
@@ -16,13 +16,157 @@ import { SdView } from '@sdcorejs/angular/components/view';
16
16
  import { SdInlineText } from '@sdcorejs/angular/forms/inline-text';
17
17
  import { SdSuffixDefDirective, SdViewDefDirective } from '@sdcorejs/angular/forms/directives';
18
18
  import { SdLabel } from '@sdcorejs/angular/forms/label';
19
- import { sdFormControlState, SD_FORM_CONFIGURATION, sdViewedTransform, sdViewedInline, SdFormControl, SdInlineErrorValidator, HandleSdCustomValidator } from '@sdcorejs/angular/forms/models';
19
+ import { sdFormControlState, SD_FORM_CONFIGURATION, sdViewedTransform, SdFormControl, SdInlineErrorValidator, HandleSdCustomValidator, ɵsdFormControlConnector as _sdFormControlConnector, sdViewedInline } from '@sdcorejs/angular/forms/models';
20
20
  import { sdIsEmpty, sdSerializeDataValue } from '@sdcorejs/angular/utilities/data-state';
21
21
  import { I18nService, TranslatePipe } from '@sdcorejs/angular/i18n';
22
22
  import { VALIDATION_PATTERNS } from '@sdcorejs/utils/constants';
23
23
  import { Subscription } from 'rxjs';
24
24
  import { SdIcon } from '@sdcorejs/angular/modules/icon';
25
25
 
26
+ const DEFAULT_TOKENS = {
27
+ '#': { pattern: /[0-9]/ },
28
+ '9': { pattern: /[0-9]/, optional: true },
29
+ A: { pattern: /[A-Za-z]/ },
30
+ a: { pattern: /[A-Za-z]/, optional: true },
31
+ '*': { pattern: /[A-Za-z0-9]/ },
32
+ '?': { pattern: /[A-Za-z0-9]/, optional: true },
33
+ };
34
+ function tokenAccepts(token, value) {
35
+ token.pattern.lastIndex = 0;
36
+ const accepted = token.pattern.test(value);
37
+ token.pattern.lastIndex = 0;
38
+ return accepted;
39
+ }
40
+ /**
41
+ * Creates a dependency-free slot mask.
42
+ *
43
+ * Default tokens: `#` required digit, `9` optional digit, `A`/`a` required/optional
44
+ * letter, and `*`/`?` required/optional alphanumeric. Every other character is a
45
+ * display literal and never leaks into the raw model.
46
+ */
47
+ function sdCreateInputMask(pattern, options = {}) {
48
+ if (!pattern)
49
+ throw new Error('Input mask pattern must not be empty.');
50
+ const tokens = { ...DEFAULT_TOKENS, ...options.tokens };
51
+ const slots = [];
52
+ const literals = [];
53
+ const units = Array.from(pattern, (value, unitIndex) => {
54
+ const token = tokens[value];
55
+ if (token) {
56
+ const slot = { unitIndex, slotIndex: slots.length, token };
57
+ slots.push(slot);
58
+ return slot;
59
+ }
60
+ const literal = { unitIndex, value };
61
+ literals.push(literal);
62
+ return literal;
63
+ });
64
+ if (slots.length === 0)
65
+ throw new Error('Input mask pattern must contain at least one token.');
66
+ const literalValues = new Set(literals.map(item => item.value));
67
+ const convert = (source, sourceSelectionStart, sourceSelectionEnd, sourceIsDisplay) => {
68
+ const assigned = [];
69
+ let unitCursor = 0;
70
+ let invalid = false;
71
+ for (let sourceIndex = 0; sourceIndex < source.length; sourceIndex += 1) {
72
+ const value = source[sourceIndex];
73
+ let consumed = false;
74
+ // why: literals are consumed at the pattern cursor, not filtered globally;
75
+ // a global filter would corrupt raw digits in masks with prefixes such as `+84`.
76
+ while (unitCursor < units.length) {
77
+ const unit = units[unitCursor];
78
+ if ('value' in unit) {
79
+ unitCursor += 1;
80
+ if (sourceIsDisplay && value === unit.value) {
81
+ consumed = true;
82
+ break;
83
+ }
84
+ continue;
85
+ }
86
+ if (tokenAccepts(unit.token, value)) {
87
+ assigned.push({
88
+ slotIndex: unit.slotIndex,
89
+ unitIndex: unit.unitIndex,
90
+ value: unit.token.transform?.(value) ?? value,
91
+ sourceIndex,
92
+ });
93
+ unitCursor += 1;
94
+ consumed = true;
95
+ break;
96
+ }
97
+ if (sourceIsDisplay && literalValues.has(value)) {
98
+ consumed = true;
99
+ break;
100
+ }
101
+ if (unit.token.optional) {
102
+ unitCursor += 1;
103
+ continue;
104
+ }
105
+ invalid = true;
106
+ consumed = true;
107
+ break;
108
+ }
109
+ if (!consumed)
110
+ invalid = true;
111
+ }
112
+ const assignedByUnit = new Map(assigned.map(item => [item.unitIndex, item]));
113
+ const lastFilledUnit = assigned.at(-1)?.unitIndex ?? -1;
114
+ let display = '';
115
+ let acceptedCount = 0;
116
+ const displayPositionByAcceptedCount = new Map([[0, 0]]);
117
+ for (const unit of units) {
118
+ if ('token' in unit) {
119
+ const item = assignedByUnit.get(unit.unitIndex);
120
+ if (!item)
121
+ continue;
122
+ display += item.value;
123
+ acceptedCount += 1;
124
+ displayPositionByAcceptedCount.set(acceptedCount, display.length);
125
+ }
126
+ else if (unit.unitIndex < lastFilledUnit) {
127
+ display += unit.value;
128
+ }
129
+ }
130
+ const raw = assigned.map(item => item.value).join('');
131
+ const hasEveryRequiredSlot = slots.every((slot, index) => slot.token.optional || assigned.some(item => item.slotIndex === index));
132
+ const status = invalid ? 'invalid' : raw.length === 0 ? 'empty' : hasEveryRequiredSlot ? 'valid' : 'incomplete';
133
+ const acceptedBefore = (position) => assigned.filter(item => item.sourceIndex < Math.max(0, position)).length;
134
+ const mapSelection = (position) => {
135
+ const count = acceptedBefore(position);
136
+ return displayPositionByAcceptedCount.get(count) ?? display.length;
137
+ };
138
+ return {
139
+ raw,
140
+ display,
141
+ status,
142
+ selectionStart: mapSelection(sourceSelectionStart),
143
+ selectionEnd: mapSelection(sourceSelectionEnd),
144
+ };
145
+ };
146
+ return {
147
+ inputMode: options.inputMode ?? (slots.every(slot => tokenAccepts(slot.token, '0')) ? 'numeric' : 'text'),
148
+ maxDisplayLength: pattern.length,
149
+ format: raw => {
150
+ const source = raw == null ? '' : String(raw);
151
+ return convert(source, source.length, source.length, false);
152
+ },
153
+ parse: (display, selectionStart = display.length, selectionEnd = selectionStart) => convert(display, selectionStart ?? display.length, selectionEnd ?? selectionStart ?? display.length, true),
154
+ };
155
+ }
156
+ /** Common business masks. Models remain raw strings; separators are display-only. */
157
+ const SD_INPUT_MASKS = {
158
+ VN_PHONE: sdCreateInputMask('#### ### ###', { inputMode: 'tel' }),
159
+ VN_ID: sdCreateInputMask('#### #### ####', { inputMode: 'numeric' }),
160
+ VN_TAX_CODE: sdCreateInputMask('##########-999', { inputMode: 'numeric' }),
161
+ BANK_ACCOUNT: sdCreateInputMask('######99999999999999', { inputMode: 'numeric' }),
162
+ BUSINESS_CODE: sdCreateInputMask('****-????????????', { inputMode: 'text' }),
163
+ };
164
+ function sdResolveInputMask(mask) {
165
+ if (!mask)
166
+ return undefined;
167
+ return typeof mask === 'string' ? SD_INPUT_MASKS[mask] : mask;
168
+ }
169
+
26
170
  // Back-compat: SdPatternType cũ → ValidationPatternType mới.
27
171
  // 3 key đã đổi tên trong @sdcorejs/utils v1.x.
28
172
  const LEGACY_PATTERN_ALIAS = {
@@ -104,16 +248,20 @@ class SdInput {
104
248
  helperText = input(...(ngDevMode ? [undefined, { debugName: "helperText" }] : /* istanbul ignore next */ []));
105
249
  placeholder = input(...(ngDevMode ? [undefined, { debugName: "placeholder" }] : /* istanbul ignore next */ []));
106
250
  type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
251
+ mask = input(...(ngDevMode ? [undefined, { debugName: "mask" }] : /* istanbul ignore next */ []));
252
+ maskAdapter = computed(() => sdResolveInputMask(this.mask()), ...(ngDevMode ? [{ debugName: "maskAdapter" }] : /* istanbul ignore next */ []));
253
+ effectiveType = computed(() => (this.maskAdapter() ? 'text' : this.type()), ...(ngDevMode ? [{ debugName: "effectiveType" }] : /* istanbul ignore next */ []));
254
+ inputMode = computed(() => this.maskAdapter()?.inputMode, ...(ngDevMode ? [{ debugName: "inputMode" }] : /* istanbul ignore next */ []));
255
+ maxDisplayLength = computed(() => this.maskAdapter()?.maxDisplayLength, ...(ngDevMode ? [{ debugName: "maxDisplayLength" }] : /* istanbul ignore next */ []));
107
256
  hideInlineError = input(false, { ...(ngDevMode ? { debugName: "hideInlineError" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
108
257
  blurOnEnter = input(false, { ...(ngDevMode ? { debugName: "blurOnEnter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
258
+ /** Whether to show the value-gated clear button in edit and inline modes. */
259
+ clearable = input(false, { ...(ngDevMode ? { debugName: "clearable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
109
260
  required = input(false, { ...(ngDevMode ? { debugName: "required" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
110
261
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
111
262
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
112
263
  /** Display mode: `false` edit · `true` static view · `'inline'` borderless inline-edit (no panel — the input IS the face). */
113
264
  viewed = input(false, { ...(ngDevMode ? { debugName: "viewed" } : /* istanbul ignore next */ {}), transform: sdViewedTransform });
114
- // Tri-state `viewed` — shared primitive. Input has NO panel; in `'inline'` the input is rendered
115
- // borderless/transparent (looks like text), always editable — clicking/focusing it edits directly.
116
- #viewedState = sdViewedInline(this.viewed, () => this.#focusActiveInput(), this.disabled);
117
265
  /** Focus whichever input is live: the inline primitive in `'inline'` mode, else the mat input. */
118
266
  #focusActiveInput = () => {
119
267
  const inline = this.inlineRef();
@@ -122,12 +270,6 @@ class SdInput {
122
270
  else
123
271
  this.control()?.nativeElement?.focus();
124
272
  };
125
- /** `true` when `viewed === 'inline'`. */
126
- isInline = this.#viewedState.isInline;
127
- /** `true` when `viewed === true` (static view, no input). */
128
- isViewed = this.#viewedState.isViewed;
129
- /** Focus the inline input. No-op unless `viewed='inline'`. */
130
- enterInlineEdit = () => this.#viewedState.enterInlineEdit();
131
273
  /** View display template: `sdViewDef` overrides the projected `#sdValue` for the static view (unified). */
132
274
  viewTemplate = computed(() => this.sdViewDef()?.templateRef ?? this.sdValueTemplate(), ...(ngDevMode ? [{ debugName: "viewTemplate" }] : /* istanbul ignore next */ []));
133
275
  minlength = input(undefined, { ...(ngDevMode ? { debugName: "minlength" } : /* istanbul ignore next */ {}), transform: v => (v == null ? undefined : Number(v)) });
@@ -171,6 +313,10 @@ class SdInput {
171
313
  return this.#i18n.t('core.form.input.required');
172
314
  if (errors['maxlength'])
173
315
  return this.#i18n.t('core.form.input.maxlength', { max: this.maxlength() ?? '' });
316
+ if (errors['maskIncomplete'])
317
+ return this.#i18n.t('core.form.input.mask-incomplete');
318
+ if (errors['maskInvalid'])
319
+ return this.#i18n.t('core.form.input.mask-invalid');
174
320
  if (errors['pattern'])
175
321
  return this.resolvedPatternErrorMsg() || this.#i18n.t('core.form.input.invalid-pattern');
176
322
  if (errors['customValidator'])
@@ -194,37 +340,105 @@ class SdInput {
194
340
  // "commit filter" (sẽ over-reload). `cleared` là intent rõ ràng cho action
195
341
  // X (clear button) — consumer như column-filter dùng để fire reload ngay.
196
342
  cleared = output();
197
- // 🚨 GIỮ LẠI EVENT_EMITTER DUY NHẤT CẦN CHECK OBSERVERED
343
+ // why: focus handling reads EventEmitter.observed before emitting a forced blur event.
198
344
  sdFocusForceBlur = new EventEmitter();
199
345
  formControl = new SdFormControl();
346
+ /** Display-only control used by the input element while a mask is active. */
347
+ displayControl = new SdFormControl();
348
+ activeControl = computed(() => (this.maskAdapter() ? this.displayControl : this.formControl), ...(ngDevMode ? [{ debugName: "activeControl" }] : /* istanbul ignore next */ []));
349
+ maskStatus = signal('empty', ...(ngDevMode ? [{ debugName: "maskStatus" }] : /* istanbul ignore next */ []));
350
+ displayValue = computed(() => {
351
+ const adapter = this.maskAdapter();
352
+ return adapter ? adapter.format(this.formControl.value == null ? '' : String(this.formControl.value)).display : this.formControl.value;
353
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
200
354
  #subscription = new Subscription();
355
+ #isComposing = false;
356
+ #pendingMaskResult;
201
357
  isFocused = false;
358
+ #validators = computed(() => {
359
+ const validators = [];
360
+ const min = this.minlength();
361
+ const max = this.maxlength();
362
+ const pattern = this.resolvedPattern();
363
+ if (min && min > 0)
364
+ validators.push(Validators.minLength(min));
365
+ if (max && max > 0)
366
+ validators.push(Validators.maxLength(max));
367
+ if (pattern)
368
+ validators.push(Validators.pattern(pattern));
369
+ if (this.maskAdapter()) {
370
+ const maskStatus = this.maskStatus();
371
+ validators.push(() => {
372
+ if (maskStatus === 'invalid')
373
+ return { maskInvalid: true };
374
+ if (maskStatus === 'incomplete')
375
+ return { maskIncomplete: true };
376
+ return null;
377
+ });
378
+ }
379
+ if (this.inlineError())
380
+ validators.push(SdInlineErrorValidator);
381
+ return validators;
382
+ }, ...(ngDevMode ? [{ debugName: "#validators" }] : /* istanbul ignore next */ []));
383
+ #asyncValidators = computed(() => {
384
+ const validator = this.validator();
385
+ return validator ? [HandleSdCustomValidator(validator)] : [];
386
+ }, ...(ngDevMode ? [{ debugName: "#asyncValidators" }] : /* istanbul ignore next */ []));
387
+ #formConnector = _sdFormControlConnector({
388
+ form: this.form,
389
+ name: this.name,
390
+ control: computed(() => this.formControl),
391
+ validators: this.#validators,
392
+ asyncValidators: this.#asyncValidators,
393
+ required: this.required,
394
+ disabled: this.disabled,
395
+ readonly: this.readonly,
396
+ viewed: this.viewed,
397
+ validationError: computed(() => this.errorMessage()),
398
+ });
399
+ /** Shared reactive form policy consumed by template-facing state below. */
400
+ connectorState = this.#formConnector.state;
401
+ isReadonly = computed(() => this.connectorState().readonly, ...(ngDevMode ? [{ debugName: "isReadonly" }] : /* istanbul ignore next */ []));
402
+ visibleErrorMessage = computed(() => this.connectorState().validationError, ...(ngDevMode ? [{ debugName: "visibleErrorMessage" }] : /* istanbul ignore next */ []));
403
+ // Tri-state `viewed` — shared primitive. Input has NO panel; in `'inline'` the input is rendered
404
+ // borderless/transparent (looks like text), always editable — clicking/focusing it edits directly.
405
+ #viewedState = sdViewedInline(computed(() => this.connectorState().viewed), () => this.#focusActiveInput(), this.disabled);
406
+ /** `true` when `viewed === 'inline'`. */
407
+ isInline = this.#viewedState.isInline;
408
+ /** `true` when `viewed === true` (static view, no input). */
409
+ isViewed = this.#viewedState.isViewed;
410
+ /** Focus the inline input. No-op unless `viewed='inline'`. */
411
+ enterInlineEdit = () => this.#viewedState.enterInlineEdit();
202
412
  constructor() {
203
413
  effect(() => {
204
414
  const val = this.valueModel();
415
+ const adapter = this.maskAdapter();
205
416
  untracked(() => {
206
417
  if (this.formControl.value !== val) {
207
418
  this.formControl.setValue(val, { emitEvent: false });
208
419
  }
420
+ if (adapter) {
421
+ const rawValue = val == null ? '' : String(val);
422
+ const result = this.#pendingMaskResult?.raw === rawValue ? this.#pendingMaskResult : adapter.format(rawValue);
423
+ this.#pendingMaskResult = undefined;
424
+ this.maskStatus.set(result.status);
425
+ if (this.displayControl.value !== result.display) {
426
+ this.displayControl.setValue(result.display, { emitEvent: false });
427
+ }
428
+ }
429
+ else {
430
+ this.maskStatus.set('empty');
431
+ }
209
432
  });
210
433
  });
211
434
  effect(() => {
212
- if (this.disabled()) {
213
- this.formControl.disable({ emitEvent: false });
214
- }
215
- else {
216
- this.formControl.enable({ emitEvent: false });
217
- }
218
- });
219
- effect(() => {
220
- const req = this.required();
221
- const min = this.minlength();
222
- const max = this.maxlength();
223
- const pat = this.resolvedPattern();
224
- const inl = this.inlineError();
225
- const val = this.validator();
435
+ const masked = !!this.maskAdapter();
436
+ const disabled = this.disabled();
226
437
  untracked(() => {
227
- this.#updateValidator(req, min, max, pat, inl, val);
438
+ if (masked && disabled)
439
+ this.displayControl.disable({ emitEvent: false });
440
+ else
441
+ this.displayControl.enable({ emitEvent: false });
228
442
  });
229
443
  });
230
444
  }
@@ -235,37 +449,15 @@ class SdInput {
235
449
  }
236
450
  ngAfterViewInit() {
237
451
  this.#subscription.add(this.formControl.valueChanges.subscribe(this.#onChange));
238
- const formGroup = this.form();
239
- formGroup?.addControl(this.name(), this.formControl);
452
+ this.#subscription.add(this.displayControl.valueChanges.subscribe(value => this.#onMaskedDisplayChange(value)));
240
453
  this.#ref.detectChanges();
241
454
  }
242
455
  ngOnDestroy() {
243
- const formGroup = this.form();
244
- formGroup?.removeControl(this.name());
245
456
  this.#subscription.unsubscribe();
246
457
  }
247
458
  reValidate = () => {
248
459
  this.formControl.updateValueAndValidity();
249
460
  };
250
- #updateValidator = (req, min, max, pat, inl, val) => {
251
- const validators = [];
252
- const asyncValidators = [];
253
- if (req)
254
- validators.push(Validators.required);
255
- if (min && min > 0)
256
- validators.push(Validators.minLength(min));
257
- if (max && max > 0)
258
- validators.push(Validators.maxLength(max));
259
- if (pat)
260
- validators.push(Validators.pattern(pat));
261
- if (inl)
262
- validators.push(SdInlineErrorValidator);
263
- if (val)
264
- asyncValidators.push(HandleSdCustomValidator(val));
265
- this.formControl.setValidators(validators.length ? validators : null);
266
- this.formControl.setAsyncValidators(asyncValidators.length ? asyncValidators : null);
267
- this.formControl.updateValueAndValidity({ emitEvent: false });
268
- };
269
461
  getCurrentLength = () => {
270
462
  return (this.formControl.value ?? '').toString().length;
271
463
  };
@@ -278,12 +470,55 @@ class SdInput {
278
470
  this.valueModel.set(value);
279
471
  this.sdChange.emit(value);
280
472
  };
473
+ #onMaskedDisplayChange(value) {
474
+ const adapter = this.maskAdapter();
475
+ if (!adapter || this.#isComposing)
476
+ return;
477
+ const nativeInput = this.control()?.nativeElement;
478
+ const display = value == null ? '' : String(value);
479
+ const result = adapter.parse(display, nativeInput?.selectionStart, nativeInput?.selectionEnd);
480
+ this.#applyMaskResult(result);
481
+ }
482
+ #applyMaskResult(result) {
483
+ this.maskStatus.set(result.status);
484
+ if (this.displayControl.value !== result.display) {
485
+ this.displayControl.setValue(result.display, { emitEvent: false });
486
+ }
487
+ if (this.formControl.value !== result.raw) {
488
+ this.#pendingMaskResult = this.valueModel() === result.raw ? undefined : result;
489
+ this.formControl.setValue(result.raw);
490
+ }
491
+ else {
492
+ this.#pendingMaskResult = undefined;
493
+ this.formControl.updateValueAndValidity({ emitEvent: false });
494
+ }
495
+ queueMicrotask(() => {
496
+ const nativeInput = this.control()?.nativeElement;
497
+ if (nativeInput) {
498
+ nativeInput.setSelectionRange(result.selectionStart, result.selectionEnd);
499
+ }
500
+ });
501
+ }
502
+ onCompositionStart() {
503
+ if (this.maskAdapter())
504
+ this.#isComposing = true;
505
+ }
506
+ onCompositionEnd(event) {
507
+ const adapter = this.maskAdapter();
508
+ if (!adapter)
509
+ return;
510
+ this.#isComposing = false;
511
+ const target = event.target;
512
+ const display = target?.value ?? String(this.displayControl.value ?? '');
513
+ this.#applyMaskResult(adapter.parse(display, target?.selectionStart, target?.selectionEnd));
514
+ }
281
515
  // why: dựa trên valueModel() (signal model-input) thay vì formControl.value —
282
516
  // khi bị wrap (vd <sd-input-color>) effect set formControl chạy SAU lúc template
283
517
  // eval nên formControl.value chưa kịp có; valueModel() thì có ngay. Method (không
284
- // computed) để re-eval mỗi CD. Required không được clear; disabled/readonly ẩn nút.
518
+ // computed) để re-eval mỗi CD. clearable là opt-in; required không được clear;
519
+ // disabled/readonly ẩn nút.
285
520
  showClear = () => {
286
- if (this.required() || this.disabled() || this.readonly())
521
+ if (!this.clearable() || this.required() || this.disabled() || this.readonly())
287
522
  return false;
288
523
  return !sdIsEmpty(this.valueModel());
289
524
  };
@@ -294,13 +529,15 @@ class SdInput {
294
529
  // why: clear là thao tác chủ động → model về null (không phải '' hay undefined).
295
530
  // undefined chỉ dành cho trạng thái pristine chưa từng nhập.
296
531
  this.formControl.setValue(null, { emitEvent: false });
532
+ this.displayControl.setValue('', { emitEvent: false });
533
+ this.maskStatus.set('empty');
297
534
  this.valueModel.set(null);
298
535
  this.sdChange.emit(null);
299
536
  this.cleared.emit();
300
537
  };
301
538
  onKeyupEnter = () => {
302
539
  const val = (this.formControl.value ?? '').toString();
303
- if (val.length > val.trim().length) {
540
+ if (!this.maskAdapter() && val.length > val.trim().length) {
304
541
  this.formControl.setValue(val.trim());
305
542
  }
306
543
  this.keyupEnter.emit(this.formControl.value);
@@ -319,7 +556,7 @@ class SdInput {
319
556
  onBlur = () => {
320
557
  this.isFocused = false;
321
558
  const val = (this.formControl.value ?? '').toString();
322
- if (val.length > val.trim().length) {
559
+ if (!this.maskAdapter() && val.length > val.trim().length) {
323
560
  this.formControl.setValue(val.trim());
324
561
  }
325
562
  this.sdBlur.emit(this.formControl.value);
@@ -347,11 +584,12 @@ class SdInput {
347
584
  }, 100);
348
585
  };
349
586
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
350
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SdInput, isStandalone: true, selector: "sd-input", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, appearanceInput: { classPropertyName: "appearanceInput", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, floatLabel: { classPropertyName: "floatLabel", publicName: "floatLabel", 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 }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, hideInlineError: { classPropertyName: "hideInlineError", publicName: "hideInlineError", isSignal: true, isRequired: false, transformFunction: null }, blurOnEnter: { classPropertyName: "blurOnEnter", publicName: "blurOnEnter", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", 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 }, minlength: { classPropertyName: "minlength", publicName: "minlength", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null }, patternErrorMessage: { classPropertyName: "patternErrorMessage", publicName: "patternErrorMessage", 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 }, hyperlink: { classPropertyName: "hyperlink", publicName: "hyperlink", isSignal: true, isRequired: false, transformFunction: null }, valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange", sdChange: "sdChange", sdFocus: "sdFocus", sdBlur: "sdBlur", keyupEnter: "keyupEnter", cleared: "cleared", sdFocusForceBlur: "sdFocusForceBlur" }, host: { properties: { "class.sd-has-label": "!!label()", "class.sd-viewed": "isViewed() || isInline()" } }, queries: [{ propertyName: "sdLabelTemplate", first: true, predicate: ["sdLabel"], descendants: true, isSignal: true }, { propertyName: "sdValueTemplate", first: true, predicate: ["sdValue"], descendants: true, isSignal: true }, { propertyName: "sdSuffixDef", first: true, predicate: SdSuffixDefDirective, descendants: true, isSignal: true }, { propertyName: "sdViewDef", first: true, predicate: SdViewDefDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "control", first: true, predicate: ["control"], descendants: true, isSignal: true }, { propertyName: "inlineRef", first: true, predicate: SdInlineText, descendants: true, isSignal: true }], ngImport: i0, template: "@let _label = label();\n@let _appearance = appearance();\n@let _hideInlineError = hideInlineError();\n@let _helperText = helperText();\n@let _maxLength = maxlength();\n@let _errorMessage = errorMessage();\n@let _required = required();\n@let _isInline = isInline();\n\n@if (isViewed()) {\n <sd-view\n [label]=\"_label\"\n [labelTemplate]=\"sdLabelTemplate()\"\n [value]=\"formControl.value\"\n [display]=\"formControl.value\"\n [hyperlink]=\"hyperlink()\"\n [valueTemplate]=\"viewTemplate()\">\n </sd-view>\n} @else if (_isInline) {\n <sd-inline-text\n [control]=\"formControl\"\n [placeholder]=\"placeholder() || _label || ''\"\n [clearable]=\"!_required\"\n [autoId]=\"autoId()\"\n [state]=\"formControl.invalid && formControl.touched ? 'error' : 'auto'\"\n (sdFocus)=\"onFocus()\"\n (sdBlur)=\"onBlur()\"\n (keyupEnter)=\"onKeyupEnter()\"\n (cleared)=\"cleared.emit()\">\n </sd-inline-text>\n} @else {\n @if (!_appearance) {\n <ng-content select=\"[sdLabel]\">\n @if (_label) {\n <sd-label [label]=\"_label\" [required]=\"_required\"></sd-label>\n }\n </ng-content>\n }\n\n <div\n class=\"d-flex align-items-center sd-input-container\"\n [class.c-focused]=\"isFocused\"\n [class.c-disabled]=\"formControl.disabled\"\n (click)=\"onClick()\"\n aria-hidden=\"true\">\n <div class=\"sd-input-field-wrap\">\n <mat-form-field\n [class.sd-md]=\"size() === 'md'\"\n [class.sd-sm]=\"size() === 'sm'\"\n [class.hide-inline-error]=\"_hideInlineError\"\n [appearance]=\"_appearance!\"\n [floatLabel]=\"floatLabel()\">\n @if (_appearance && _label) {\n <mat-label class=\"sd-form-field-label\">\n <span>{{ _label }}</span>\n @if (_helperText) {\n <sd-icon [matTooltip]=\"_helperText\" matTooltipPosition=\"below\" name=\"info\"></sd-icon>\n }\n </mat-label>\n }\n\n <input\n aria-hidden=\"true\"\n [id]=\"id\"\n [formControl]=\"formControl\"\n [type]=\"type()\"\n #control\n matInput\n [placeholder]=\"placeholder() || _label || ''\"\n (keyup.enter)=\"onKeyupEnter()\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [required]=\"_required\"\n [readonly]=\"readonly()\"\n [autocomplete]=\"id\"\n autocorrect=\"off\"\n [step]=\"1\"\n [attr.data-autoId]=\"autoId()\"\n [attr.data-disabled]=\"dataDisabled()\"\n [attr.data-invalid]=\"dataInvalid()\"\n [attr.data-empty]=\"dataEmpty()\"\n [attr.data-value]=\"dataValue()\"\n [attr.data-required]=\"dataRequired()\"\n [attr.data-maxlength]=\"dataMaxLength()\"\n [attr.data-minlength]=\"dataMinLength()\"\n [attr.data-pattern]=\"dataPattern()\"\n [attr.data-error-message]=\"dataErrorMessage()\" />\n\n @if (!_hideInlineError && _errorMessage && formControl.touched) {\n <mat-error>{{ _errorMessage }}</mat-error>\n }\n\n <!-- why: n\u00FAt clear render TR\u01AF\u1EDAC error icon. Clear hover-gated (visibility:hidden) v\u1EABn\n chi\u1EBFm ch\u1ED7 trong layout \u2192 n\u1EBFu \u0111\u1EE9ng sau s\u1EBD \u0111\u1EA9y error icon \"t\u1EE5t v\u00E0o trong\". \u0110\u1EE9ng tr\u01B0\u1EDBc\n th\u00EC error icon n\u1EB1m s\u00E1t m\u00E9p ph\u1EA3i, clear gi\u1EEF slot v\u00F4 h\u00ECnh b\u00EAn tr\u00E1i. -->\n @if (showClear()) {\n <button type=\"button\" class=\"sd-clear-btn sd-hover\" matSuffix (click)=\"clear($event)\" title=\"X\u00F3a\" aria-label=\"X\u00F3a\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n\n @if (_hideInlineError && _errorMessage && formControl.touched) {\n <sd-icon matSuffix class=\"sd-error-icon\" [matTooltip]=\"_errorMessage\" matTooltipPosition=\"above\" name=\"error\"></sd-icon>\n }\n\n @if (sdSuffixDef()?.templateRef; as suffixRef) {\n <ng-container matSuffix>\n <ng-container *ngTemplateOutlet=\"suffixRef\"></ng-container>\n </ng-container>\n }\n <!-- <ng-container matSuffix>\n <ng-content select=\"[sdSuffix]\"></ng-content>\n </ng-container> -->\n </mat-form-field>\n\n @if (_maxLength && !_hideInlineError && !formControl.disabled) {\n <div\n class=\"sd-maxlength-counter\"\n [class.sd-maxlength-counter--visible]=\"isFocused\"\n [class.sd-maxlength-counter--exceeded]=\"isMaxlengthExceeded()\"\n [attr.title]=\"isMaxlengthExceeded() ? ('core.form.input.exceeded' | translate) : null\">\n {{ getCurrentLength() }}/{{ _maxLength }}\n </div>\n }\n </div>\n </div>\n}\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-primary-contrast{color:var(--sd-primary-contrast)!important}.bg-primary-contrast{background:var(--sd-primary-contrast)!important}.border-primary-contrast{border-color:var(--sd-primary-contrast)!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-secondary-contrast{color:var(--sd-secondary-contrast)!important}.bg-secondary-contrast{background:var(--sd-secondary-contrast)!important}.border-secondary-contrast{border-color:var(--sd-secondary-contrast)!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-info-contrast{color:var(--sd-info-contrast)!important}.bg-info-contrast{background:var(--sd-info-contrast)!important}.border-info-contrast{border-color:var(--sd-info-contrast)!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-success-contrast{color:var(--sd-success-contrast)!important}.bg-success-contrast{background:var(--sd-success-contrast)!important}.border-success-contrast{border-color:var(--sd-success-contrast)!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-warning-contrast{color:var(--sd-warning-contrast)!important}.bg-warning-contrast{background:var(--sd-warning-contrast)!important}.border-warning-contrast{border-color:var(--sd-warning-contrast)!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-error-contrast{color:var(--sd-error-contrast)!important}.bg-error-contrast{background:var(--sd-error-contrast)!important}.border-error-contrast{border-color:var(--sd-error-contrast)!important}.text-surface{color:var(--sd-surface)!important}.bg-surface{background:var(--sd-surface)!important}.border-surface{border-color:var(--sd-surface)!important}.text-surface-muted{color:var(--sd-surface-muted)!important}.bg-surface-muted{background:var(--sd-surface-muted)!important}.border-surface-muted{border-color:var(--sd-surface-muted)!important}.text-text{color:var(--sd-text)!important}.bg-text{background:var(--sd-text)!important}.border-text{border-color:var(--sd-text)!important}.text-text-secondary{color:var(--sd-text-secondary)!important}.bg-text-secondary{background:var(--sd-text-secondary)!important}.border-text-secondary{border-color:var(--sd-text-secondary)!important}.text-text-muted{color:var(--sd-text-muted)!important}.bg-text-muted{background:var(--sd-text-muted)!important}.border-text-muted{border-color:var(--sd-text-muted)!important}.text-border{color:var(--sd-border)!important}.bg-border{background:var(--sd-border)!important}.border-border{border-color:var(--sd-border)!important}.text-border-strong{color:var(--sd-border-strong)!important}.bg-border-strong{background:var(--sd-border-strong)!important}.border-border-strong{border-color:var(--sd-border-strong)!important}.text-disabled-bg{color:var(--sd-disabled-bg)!important}.bg-disabled-bg{background:var(--sd-disabled-bg)!important}.border-disabled-bg{border-color:var(--sd-disabled-bg)!important}.text-disabled-text{color:var(--sd-disabled-text)!important}.bg-disabled-text{background:var(--sd-disabled-text)!important}.border-disabled-text{border-color:var(--sd-disabled-text)!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}.text-secondary{color:var(--sd-text-secondary)!important}.text-muted{color:var(--sd-text-muted)!important}.text-body{color:var(--sd-text)!important}.bg-muted{background:var(--sd-surface-muted)!important}:host{display:block}:host(.sd-has-label){padding-top:4px}:host(.sd-viewed){padding-top:0}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-disabled-bg)}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-disabled-text)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}.sd-input-field-wrap{position:relative;flex:1;min-width:0}.sd-maxlength-counter{position:absolute;right:4px;top:calc(100% - 16px);opacity:0;font-size:10px;line-height:1.1;color:#00000061;pointer-events:none;transition:opacity .12s ease;z-index:1}.sd-maxlength-counter--exceeded{color:var(--sd-error);font-weight:600}:host ::ng-deep .sd-input-container.c-focused .sd-maxlength-counter,:host ::ng-deep .sd-input-container:hover .sd-maxlength-counter,:host ::ng-deep .sd-input-container .sd-maxlength-counter.sd-maxlength-counter--visible{opacity:1}.sd-md:hover .btn-copy{visibility:visible}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: MatFormFieldModule }, { 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: MatInputModule }, { kind: "directive", type: i4.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: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { 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", "selectedItems"] }, { kind: "component", type: SdInlineText, selector: "sd-inline-text", inputs: ["value", "control", "placeholder", "disabled", "clearable", "state", "chrome", "autoId", "autofocus", "minSize"], outputs: ["valueChange", "cleared", "keyupEnter", "keydownEscape", "sdFocus", "sdBlur", "sdKeydown", "sdPaste", "sdCompositionStart", "sdCompositionEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SdInput, isStandalone: true, selector: "sd-input", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, appearanceInput: { classPropertyName: "appearanceInput", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, floatLabel: { classPropertyName: "floatLabel", publicName: "floatLabel", 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 }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null }, hideInlineError: { classPropertyName: "hideInlineError", publicName: "hideInlineError", isSignal: true, isRequired: false, transformFunction: null }, blurOnEnter: { classPropertyName: "blurOnEnter", publicName: "blurOnEnter", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", 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 }, minlength: { classPropertyName: "minlength", publicName: "minlength", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null }, patternErrorMessage: { classPropertyName: "patternErrorMessage", publicName: "patternErrorMessage", 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 }, hyperlink: { classPropertyName: "hyperlink", publicName: "hyperlink", isSignal: true, isRequired: false, transformFunction: null }, valueModel: { classPropertyName: "valueModel", publicName: "model", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueModel: "modelChange", sdChange: "sdChange", sdFocus: "sdFocus", sdBlur: "sdBlur", keyupEnter: "keyupEnter", cleared: "cleared", sdFocusForceBlur: "sdFocusForceBlur" }, host: { properties: { "class.sd-has-label": "!!label()", "class.sd-viewed": "isViewed() || isInline()" } }, queries: [{ propertyName: "sdLabelTemplate", first: true, predicate: ["sdLabel"], descendants: true, isSignal: true }, { propertyName: "sdValueTemplate", first: true, predicate: ["sdValue"], descendants: true, isSignal: true }, { propertyName: "sdSuffixDef", first: true, predicate: SdSuffixDefDirective, descendants: true, isSignal: true }, { propertyName: "sdViewDef", first: true, predicate: SdViewDefDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "control", first: true, predicate: ["control"], descendants: true, isSignal: true }, { propertyName: "inlineRef", first: true, predicate: SdInlineText, descendants: true, isSignal: true }], ngImport: i0, template: "@let _label = label();\n@let _appearance = appearance();\n@let _hideInlineError = hideInlineError();\n@let _helperText = helperText();\n@let _maxLength = maxlength();\n@let _errorMessage = visibleErrorMessage();\n@let _required = required();\n@let _isInline = isInline();\n\n@if (isViewed()) {\n <sd-view\n [label]=\"_label\"\n [labelTemplate]=\"sdLabelTemplate()\"\n [value]=\"formControl.value\"\n [display]=\"displayValue()\"\n [hyperlink]=\"hyperlink()\"\n [valueTemplate]=\"viewTemplate()\">\n </sd-view>\n} @else if (_isInline) {\n <sd-inline-text\n [control]=\"activeControl()\"\n [placeholder]=\"placeholder() || _label || ''\"\n [clearable]=\"clearable() && !_required\"\n [autoId]=\"autoId()\"\n [state]=\"connectorState().invalid ? 'error' : 'auto'\"\n (sdFocus)=\"onFocus()\"\n (sdBlur)=\"onBlur()\"\n (keyupEnter)=\"onKeyupEnter()\"\n (cleared)=\"cleared.emit()\">\n </sd-inline-text>\n} @else {\n @if (!_appearance) {\n <ng-content select=\"[sdLabel]\">\n @if (_label) {\n <sd-label [label]=\"_label\" [required]=\"_required\"></sd-label>\n }\n </ng-content>\n }\n\n <div\n class=\"d-flex align-items-center sd-input-container\"\n [class.c-focused]=\"isFocused\"\n [class.c-disabled]=\"formControl.disabled\"\n (click)=\"onClick()\"\n aria-hidden=\"true\">\n <div class=\"sd-input-field-wrap\">\n <mat-form-field\n [class.sd-md]=\"size() === 'md'\"\n [class.sd-sm]=\"size() === 'sm'\"\n [class.hide-inline-error]=\"_hideInlineError\"\n [appearance]=\"_appearance!\"\n [floatLabel]=\"floatLabel()\">\n @if (_appearance && _label) {\n <mat-label class=\"sd-form-field-label\">\n <span>{{ _label }}</span>\n @if (_helperText) {\n <sd-icon [matTooltip]=\"_helperText\" matTooltipPosition=\"below\" name=\"info\"></sd-icon>\n }\n </mat-label>\n }\n\n <input\n aria-hidden=\"true\"\n [id]=\"id\"\n [formControl]=\"activeControl()\"\n [type]=\"effectiveType()\"\n #control\n matInput\n [placeholder]=\"placeholder() || _label || ''\"\n (keyup.enter)=\"onKeyupEnter()\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [required]=\"_required\"\n [readonly]=\"isReadonly()\"\n [autocomplete]=\"id\"\n autocorrect=\"off\"\n [step]=\"1\"\n [attr.inputmode]=\"inputMode()\"\n [attr.maxlength]=\"maxDisplayLength()\"\n [attr.data-autoId]=\"autoId()\"\n [attr.data-disabled]=\"dataDisabled()\"\n [attr.data-invalid]=\"dataInvalid()\"\n [attr.data-empty]=\"dataEmpty()\"\n [attr.data-value]=\"dataValue()\"\n [attr.data-required]=\"dataRequired()\"\n [attr.data-maxlength]=\"dataMaxLength()\"\n [attr.data-minlength]=\"dataMinLength()\"\n [attr.data-pattern]=\"dataPattern()\"\n [attr.data-error-message]=\"dataErrorMessage()\"\n (compositionstart)=\"onCompositionStart()\"\n (compositionend)=\"onCompositionEnd($event)\" />\n\n @if (!_hideInlineError && _errorMessage) {\n <mat-error>{{ _errorMessage }}</mat-error>\n }\n\n <!-- why: n\u00FAt clear render TR\u01AF\u1EDAC error icon. Clear hover-gated (visibility:hidden) v\u1EABn\n chi\u1EBFm ch\u1ED7 trong layout \u2192 n\u1EBFu \u0111\u1EE9ng sau s\u1EBD \u0111\u1EA9y error icon \"t\u1EE5t v\u00E0o trong\". \u0110\u1EE9ng tr\u01B0\u1EDBc\n th\u00EC error icon n\u1EB1m s\u00E1t m\u00E9p ph\u1EA3i, clear gi\u1EEF slot v\u00F4 h\u00ECnh b\u00EAn tr\u00E1i. -->\n @if (showClear()) {\n <button type=\"button\" class=\"sd-clear-btn sd-hover\" matSuffix (click)=\"clear($event)\" title=\"X\u00F3a\" aria-label=\"X\u00F3a\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n\n @if (_hideInlineError && _errorMessage) {\n <sd-icon matSuffix class=\"sd-error-icon\" [matTooltip]=\"_errorMessage\" matTooltipPosition=\"above\" name=\"error\"></sd-icon>\n }\n\n @if (sdSuffixDef()?.templateRef; as suffixRef) {\n <ng-container matSuffix>\n <ng-container *ngTemplateOutlet=\"suffixRef\"></ng-container>\n </ng-container>\n }\n <!-- <ng-container matSuffix>\n <ng-content select=\"[sdSuffix]\"></ng-content>\n </ng-container> -->\n </mat-form-field>\n\n @if (_maxLength && !_hideInlineError && !formControl.disabled) {\n <div\n class=\"sd-maxlength-counter\"\n [class.sd-maxlength-counter--visible]=\"isFocused\"\n [class.sd-maxlength-counter--exceeded]=\"isMaxlengthExceeded()\"\n [attr.title]=\"isMaxlengthExceeded() ? ('core.form.input.exceeded' | translate) : null\">\n {{ getCurrentLength() }}/{{ _maxLength }}\n </div>\n }\n </div>\n </div>\n}\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-primary-contrast{color:var(--sd-primary-contrast)!important}.bg-primary-contrast{background:var(--sd-primary-contrast)!important}.border-primary-contrast{border-color:var(--sd-primary-contrast)!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-secondary-contrast{color:var(--sd-secondary-contrast)!important}.bg-secondary-contrast{background:var(--sd-secondary-contrast)!important}.border-secondary-contrast{border-color:var(--sd-secondary-contrast)!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-info-contrast{color:var(--sd-info-contrast)!important}.bg-info-contrast{background:var(--sd-info-contrast)!important}.border-info-contrast{border-color:var(--sd-info-contrast)!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-success-contrast{color:var(--sd-success-contrast)!important}.bg-success-contrast{background:var(--sd-success-contrast)!important}.border-success-contrast{border-color:var(--sd-success-contrast)!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-warning-contrast{color:var(--sd-warning-contrast)!important}.bg-warning-contrast{background:var(--sd-warning-contrast)!important}.border-warning-contrast{border-color:var(--sd-warning-contrast)!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-error-contrast{color:var(--sd-error-contrast)!important}.bg-error-contrast{background:var(--sd-error-contrast)!important}.border-error-contrast{border-color:var(--sd-error-contrast)!important}.text-surface{color:var(--sd-surface)!important}.bg-surface{background:var(--sd-surface)!important}.border-surface{border-color:var(--sd-surface)!important}.text-surface-muted{color:var(--sd-surface-muted)!important}.bg-surface-muted{background:var(--sd-surface-muted)!important}.border-surface-muted{border-color:var(--sd-surface-muted)!important}.text-text{color:var(--sd-text)!important}.bg-text{background:var(--sd-text)!important}.border-text{border-color:var(--sd-text)!important}.text-text-secondary{color:var(--sd-text-secondary)!important}.bg-text-secondary{background:var(--sd-text-secondary)!important}.border-text-secondary{border-color:var(--sd-text-secondary)!important}.text-text-muted{color:var(--sd-text-muted)!important}.bg-text-muted{background:var(--sd-text-muted)!important}.border-text-muted{border-color:var(--sd-text-muted)!important}.text-border{color:var(--sd-border)!important}.bg-border{background:var(--sd-border)!important}.border-border{border-color:var(--sd-border)!important}.text-border-strong{color:var(--sd-border-strong)!important}.bg-border-strong{background:var(--sd-border-strong)!important}.border-border-strong{border-color:var(--sd-border-strong)!important}.text-disabled-bg{color:var(--sd-disabled-bg)!important}.bg-disabled-bg{background:var(--sd-disabled-bg)!important}.border-disabled-bg{border-color:var(--sd-disabled-bg)!important}.text-disabled-text{color:var(--sd-disabled-text)!important}.bg-disabled-text{background:var(--sd-disabled-text)!important}.border-disabled-text{border-color:var(--sd-disabled-text)!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}.text-secondary{color:var(--sd-text-secondary)!important}.text-muted{color:var(--sd-text-muted)!important}.text-body{color:var(--sd-text)!important}.bg-muted{background:var(--sd-surface-muted)!important}:host{display:block}:host(.sd-has-label){padding-top:4px}:host(.sd-viewed){padding-top:0}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-disabled-bg)}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-disabled-text)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}.sd-input-field-wrap{position:relative;flex:1;min-width:0}.sd-maxlength-counter{position:absolute;right:4px;top:calc(100% - 16px);opacity:0;font-size:10px;line-height:1.1;color:#00000061;pointer-events:none;transition:opacity .12s ease;z-index:1}.sd-maxlength-counter--exceeded{color:var(--sd-error);font-weight:600}:host ::ng-deep .sd-input-container.c-focused .sd-maxlength-counter,:host ::ng-deep .sd-input-container:hover .sd-maxlength-counter,:host ::ng-deep .sd-input-container .sd-maxlength-counter.sd-maxlength-counter--visible{opacity:1}.sd-md:hover .btn-copy{visibility:visible}\n"], dependencies: [{ kind: "component", type: SdIcon, selector: "sd-icon", inputs: ["name", "fontIcon", "color", "set", "fontSet", "size", "strokeWidth", "absoluteStrokeWidth", "ariaLabel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { 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: MatFormFieldModule }, { 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: MatInputModule }, { kind: "directive", type: i4.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: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatButtonModule }, { 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", "selectedItems"] }, { kind: "component", type: SdInlineText, selector: "sd-inline-text", inputs: ["value", "control", "placeholder", "disabled", "clearable", "state", "chrome", "autoId", "autofocus", "minSize"], outputs: ["valueChange", "cleared", "keyupEnter", "keydownEscape", "sdFocus", "sdBlur", "sdKeydown", "sdPaste", "sdCompositionStart", "sdCompositionEnd"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
351
588
  }
352
589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SdInput, decorators: [{
353
590
  type: Component,
354
- args: [{ selector: 'sd-input', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, host: { '[class.sd-has-label]': '!!label()', '[class.sd-viewed]': 'isViewed() || isInline()' }, imports: [SdIcon,
591
+ args: [{ selector: 'sd-input', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, host: { '[class.sd-has-label]': '!!label()', '[class.sd-viewed]': 'isViewed() || isInline()' }, imports: [
592
+ SdIcon,
355
593
  CommonModule,
356
594
  FormsModule,
357
595
  ReactiveFormsModule,
@@ -363,8 +601,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
363
601
  SdView,
364
602
  SdInlineText,
365
603
  TranslatePipe,
366
- ], template: "@let _label = label();\n@let _appearance = appearance();\n@let _hideInlineError = hideInlineError();\n@let _helperText = helperText();\n@let _maxLength = maxlength();\n@let _errorMessage = errorMessage();\n@let _required = required();\n@let _isInline = isInline();\n\n@if (isViewed()) {\n <sd-view\n [label]=\"_label\"\n [labelTemplate]=\"sdLabelTemplate()\"\n [value]=\"formControl.value\"\n [display]=\"formControl.value\"\n [hyperlink]=\"hyperlink()\"\n [valueTemplate]=\"viewTemplate()\">\n </sd-view>\n} @else if (_isInline) {\n <sd-inline-text\n [control]=\"formControl\"\n [placeholder]=\"placeholder() || _label || ''\"\n [clearable]=\"!_required\"\n [autoId]=\"autoId()\"\n [state]=\"formControl.invalid && formControl.touched ? 'error' : 'auto'\"\n (sdFocus)=\"onFocus()\"\n (sdBlur)=\"onBlur()\"\n (keyupEnter)=\"onKeyupEnter()\"\n (cleared)=\"cleared.emit()\">\n </sd-inline-text>\n} @else {\n @if (!_appearance) {\n <ng-content select=\"[sdLabel]\">\n @if (_label) {\n <sd-label [label]=\"_label\" [required]=\"_required\"></sd-label>\n }\n </ng-content>\n }\n\n <div\n class=\"d-flex align-items-center sd-input-container\"\n [class.c-focused]=\"isFocused\"\n [class.c-disabled]=\"formControl.disabled\"\n (click)=\"onClick()\"\n aria-hidden=\"true\">\n <div class=\"sd-input-field-wrap\">\n <mat-form-field\n [class.sd-md]=\"size() === 'md'\"\n [class.sd-sm]=\"size() === 'sm'\"\n [class.hide-inline-error]=\"_hideInlineError\"\n [appearance]=\"_appearance!\"\n [floatLabel]=\"floatLabel()\">\n @if (_appearance && _label) {\n <mat-label class=\"sd-form-field-label\">\n <span>{{ _label }}</span>\n @if (_helperText) {\n <sd-icon [matTooltip]=\"_helperText\" matTooltipPosition=\"below\" name=\"info\"></sd-icon>\n }\n </mat-label>\n }\n\n <input\n aria-hidden=\"true\"\n [id]=\"id\"\n [formControl]=\"formControl\"\n [type]=\"type()\"\n #control\n matInput\n [placeholder]=\"placeholder() || _label || ''\"\n (keyup.enter)=\"onKeyupEnter()\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [required]=\"_required\"\n [readonly]=\"readonly()\"\n [autocomplete]=\"id\"\n autocorrect=\"off\"\n [step]=\"1\"\n [attr.data-autoId]=\"autoId()\"\n [attr.data-disabled]=\"dataDisabled()\"\n [attr.data-invalid]=\"dataInvalid()\"\n [attr.data-empty]=\"dataEmpty()\"\n [attr.data-value]=\"dataValue()\"\n [attr.data-required]=\"dataRequired()\"\n [attr.data-maxlength]=\"dataMaxLength()\"\n [attr.data-minlength]=\"dataMinLength()\"\n [attr.data-pattern]=\"dataPattern()\"\n [attr.data-error-message]=\"dataErrorMessage()\" />\n\n @if (!_hideInlineError && _errorMessage && formControl.touched) {\n <mat-error>{{ _errorMessage }}</mat-error>\n }\n\n <!-- why: n\u00FAt clear render TR\u01AF\u1EDAC error icon. Clear hover-gated (visibility:hidden) v\u1EABn\n chi\u1EBFm ch\u1ED7 trong layout \u2192 n\u1EBFu \u0111\u1EE9ng sau s\u1EBD \u0111\u1EA9y error icon \"t\u1EE5t v\u00E0o trong\". \u0110\u1EE9ng tr\u01B0\u1EDBc\n th\u00EC error icon n\u1EB1m s\u00E1t m\u00E9p ph\u1EA3i, clear gi\u1EEF slot v\u00F4 h\u00ECnh b\u00EAn tr\u00E1i. -->\n @if (showClear()) {\n <button type=\"button\" class=\"sd-clear-btn sd-hover\" matSuffix (click)=\"clear($event)\" title=\"X\u00F3a\" aria-label=\"X\u00F3a\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n\n @if (_hideInlineError && _errorMessage && formControl.touched) {\n <sd-icon matSuffix class=\"sd-error-icon\" [matTooltip]=\"_errorMessage\" matTooltipPosition=\"above\" name=\"error\"></sd-icon>\n }\n\n @if (sdSuffixDef()?.templateRef; as suffixRef) {\n <ng-container matSuffix>\n <ng-container *ngTemplateOutlet=\"suffixRef\"></ng-container>\n </ng-container>\n }\n <!-- <ng-container matSuffix>\n <ng-content select=\"[sdSuffix]\"></ng-content>\n </ng-container> -->\n </mat-form-field>\n\n @if (_maxLength && !_hideInlineError && !formControl.disabled) {\n <div\n class=\"sd-maxlength-counter\"\n [class.sd-maxlength-counter--visible]=\"isFocused\"\n [class.sd-maxlength-counter--exceeded]=\"isMaxlengthExceeded()\"\n [attr.title]=\"isMaxlengthExceeded() ? ('core.form.input.exceeded' | translate) : null\">\n {{ getCurrentLength() }}/{{ _maxLength }}\n </div>\n }\n </div>\n </div>\n}\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-primary-contrast{color:var(--sd-primary-contrast)!important}.bg-primary-contrast{background:var(--sd-primary-contrast)!important}.border-primary-contrast{border-color:var(--sd-primary-contrast)!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-secondary-contrast{color:var(--sd-secondary-contrast)!important}.bg-secondary-contrast{background:var(--sd-secondary-contrast)!important}.border-secondary-contrast{border-color:var(--sd-secondary-contrast)!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-info-contrast{color:var(--sd-info-contrast)!important}.bg-info-contrast{background:var(--sd-info-contrast)!important}.border-info-contrast{border-color:var(--sd-info-contrast)!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-success-contrast{color:var(--sd-success-contrast)!important}.bg-success-contrast{background:var(--sd-success-contrast)!important}.border-success-contrast{border-color:var(--sd-success-contrast)!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-warning-contrast{color:var(--sd-warning-contrast)!important}.bg-warning-contrast{background:var(--sd-warning-contrast)!important}.border-warning-contrast{border-color:var(--sd-warning-contrast)!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-error-contrast{color:var(--sd-error-contrast)!important}.bg-error-contrast{background:var(--sd-error-contrast)!important}.border-error-contrast{border-color:var(--sd-error-contrast)!important}.text-surface{color:var(--sd-surface)!important}.bg-surface{background:var(--sd-surface)!important}.border-surface{border-color:var(--sd-surface)!important}.text-surface-muted{color:var(--sd-surface-muted)!important}.bg-surface-muted{background:var(--sd-surface-muted)!important}.border-surface-muted{border-color:var(--sd-surface-muted)!important}.text-text{color:var(--sd-text)!important}.bg-text{background:var(--sd-text)!important}.border-text{border-color:var(--sd-text)!important}.text-text-secondary{color:var(--sd-text-secondary)!important}.bg-text-secondary{background:var(--sd-text-secondary)!important}.border-text-secondary{border-color:var(--sd-text-secondary)!important}.text-text-muted{color:var(--sd-text-muted)!important}.bg-text-muted{background:var(--sd-text-muted)!important}.border-text-muted{border-color:var(--sd-text-muted)!important}.text-border{color:var(--sd-border)!important}.bg-border{background:var(--sd-border)!important}.border-border{border-color:var(--sd-border)!important}.text-border-strong{color:var(--sd-border-strong)!important}.bg-border-strong{background:var(--sd-border-strong)!important}.border-border-strong{border-color:var(--sd-border-strong)!important}.text-disabled-bg{color:var(--sd-disabled-bg)!important}.bg-disabled-bg{background:var(--sd-disabled-bg)!important}.border-disabled-bg{border-color:var(--sd-disabled-bg)!important}.text-disabled-text{color:var(--sd-disabled-text)!important}.bg-disabled-text{background:var(--sd-disabled-text)!important}.border-disabled-text{border-color:var(--sd-disabled-text)!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}.text-secondary{color:var(--sd-text-secondary)!important}.text-muted{color:var(--sd-text-muted)!important}.text-body{color:var(--sd-text)!important}.bg-muted{background:var(--sd-surface-muted)!important}:host{display:block}:host(.sd-has-label){padding-top:4px}:host(.sd-viewed){padding-top:0}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-disabled-bg)}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-disabled-text)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}.sd-input-field-wrap{position:relative;flex:1;min-width:0}.sd-maxlength-counter{position:absolute;right:4px;top:calc(100% - 16px);opacity:0;font-size:10px;line-height:1.1;color:#00000061;pointer-events:none;transition:opacity .12s ease;z-index:1}.sd-maxlength-counter--exceeded{color:var(--sd-error);font-weight:600}:host ::ng-deep .sd-input-container.c-focused .sd-maxlength-counter,:host ::ng-deep .sd-input-container:hover .sd-maxlength-counter,:host ::ng-deep .sd-input-container .sd-maxlength-counter.sd-maxlength-counter--visible{opacity:1}.sd-md:hover .btn-copy{visibility:visible}\n"] }]
367
- }], ctorParameters: () => [], propDecorators: { control: [{ type: i0.ViewChild, args: ['control', { isSignal: true }] }], inlineRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdInlineText), { isSignal: true }] }], sdLabelTemplate: [{ type: i0.ContentChild, args: ['sdLabel', { isSignal: true }] }], sdValueTemplate: [{ type: i0.ContentChild, args: ['sdValue', { isSignal: true }] }], sdSuffixDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdSuffixDefDirective), { isSignal: true }] }], sdViewDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdViewDefDirective), { isSignal: true }] }], autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], appearanceInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], floatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], hideInlineError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideInlineError", required: false }] }], blurOnEnter: [{ type: i0.Input, args: [{ isSignal: true, alias: "blurOnEnter", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], viewed: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewed", required: false }] }], minlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minlength", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], patternErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "patternErrorMessage", required: false }] }], validator: [{ type: i0.Input, args: [{ isSignal: true, alias: "validator", required: false }] }], inlineError: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineError", required: false }] }], hyperlink: [{ type: i0.Input, args: [{ isSignal: true, alias: "hyperlink", required: false }] }], valueModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }, { type: i0.Output, args: ["modelChange"] }], sdChange: [{ type: i0.Output, args: ["sdChange"] }], sdFocus: [{ type: i0.Output, args: ["sdFocus"] }], sdBlur: [{ type: i0.Output, args: ["sdBlur"] }], keyupEnter: [{ type: i0.Output, args: ["keyupEnter"] }], cleared: [{ type: i0.Output, args: ["cleared"] }], sdFocusForceBlur: [{
604
+ ], template: "@let _label = label();\n@let _appearance = appearance();\n@let _hideInlineError = hideInlineError();\n@let _helperText = helperText();\n@let _maxLength = maxlength();\n@let _errorMessage = visibleErrorMessage();\n@let _required = required();\n@let _isInline = isInline();\n\n@if (isViewed()) {\n <sd-view\n [label]=\"_label\"\n [labelTemplate]=\"sdLabelTemplate()\"\n [value]=\"formControl.value\"\n [display]=\"displayValue()\"\n [hyperlink]=\"hyperlink()\"\n [valueTemplate]=\"viewTemplate()\">\n </sd-view>\n} @else if (_isInline) {\n <sd-inline-text\n [control]=\"activeControl()\"\n [placeholder]=\"placeholder() || _label || ''\"\n [clearable]=\"clearable() && !_required\"\n [autoId]=\"autoId()\"\n [state]=\"connectorState().invalid ? 'error' : 'auto'\"\n (sdFocus)=\"onFocus()\"\n (sdBlur)=\"onBlur()\"\n (keyupEnter)=\"onKeyupEnter()\"\n (cleared)=\"cleared.emit()\">\n </sd-inline-text>\n} @else {\n @if (!_appearance) {\n <ng-content select=\"[sdLabel]\">\n @if (_label) {\n <sd-label [label]=\"_label\" [required]=\"_required\"></sd-label>\n }\n </ng-content>\n }\n\n <div\n class=\"d-flex align-items-center sd-input-container\"\n [class.c-focused]=\"isFocused\"\n [class.c-disabled]=\"formControl.disabled\"\n (click)=\"onClick()\"\n aria-hidden=\"true\">\n <div class=\"sd-input-field-wrap\">\n <mat-form-field\n [class.sd-md]=\"size() === 'md'\"\n [class.sd-sm]=\"size() === 'sm'\"\n [class.hide-inline-error]=\"_hideInlineError\"\n [appearance]=\"_appearance!\"\n [floatLabel]=\"floatLabel()\">\n @if (_appearance && _label) {\n <mat-label class=\"sd-form-field-label\">\n <span>{{ _label }}</span>\n @if (_helperText) {\n <sd-icon [matTooltip]=\"_helperText\" matTooltipPosition=\"below\" name=\"info\"></sd-icon>\n }\n </mat-label>\n }\n\n <input\n aria-hidden=\"true\"\n [id]=\"id\"\n [formControl]=\"activeControl()\"\n [type]=\"effectiveType()\"\n #control\n matInput\n [placeholder]=\"placeholder() || _label || ''\"\n (keyup.enter)=\"onKeyupEnter()\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [required]=\"_required\"\n [readonly]=\"isReadonly()\"\n [autocomplete]=\"id\"\n autocorrect=\"off\"\n [step]=\"1\"\n [attr.inputmode]=\"inputMode()\"\n [attr.maxlength]=\"maxDisplayLength()\"\n [attr.data-autoId]=\"autoId()\"\n [attr.data-disabled]=\"dataDisabled()\"\n [attr.data-invalid]=\"dataInvalid()\"\n [attr.data-empty]=\"dataEmpty()\"\n [attr.data-value]=\"dataValue()\"\n [attr.data-required]=\"dataRequired()\"\n [attr.data-maxlength]=\"dataMaxLength()\"\n [attr.data-minlength]=\"dataMinLength()\"\n [attr.data-pattern]=\"dataPattern()\"\n [attr.data-error-message]=\"dataErrorMessage()\"\n (compositionstart)=\"onCompositionStart()\"\n (compositionend)=\"onCompositionEnd($event)\" />\n\n @if (!_hideInlineError && _errorMessage) {\n <mat-error>{{ _errorMessage }}</mat-error>\n }\n\n <!-- why: n\u00FAt clear render TR\u01AF\u1EDAC error icon. Clear hover-gated (visibility:hidden) v\u1EABn\n chi\u1EBFm ch\u1ED7 trong layout \u2192 n\u1EBFu \u0111\u1EE9ng sau s\u1EBD \u0111\u1EA9y error icon \"t\u1EE5t v\u00E0o trong\". \u0110\u1EE9ng tr\u01B0\u1EDBc\n th\u00EC error icon n\u1EB1m s\u00E1t m\u00E9p ph\u1EA3i, clear gi\u1EEF slot v\u00F4 h\u00ECnh b\u00EAn tr\u00E1i. -->\n @if (showClear()) {\n <button type=\"button\" class=\"sd-clear-btn sd-hover\" matSuffix (click)=\"clear($event)\" title=\"X\u00F3a\" aria-label=\"X\u00F3a\">\n <sd-icon name=\"close\"></sd-icon>\n </button>\n }\n\n @if (_hideInlineError && _errorMessage) {\n <sd-icon matSuffix class=\"sd-error-icon\" [matTooltip]=\"_errorMessage\" matTooltipPosition=\"above\" name=\"error\"></sd-icon>\n }\n\n @if (sdSuffixDef()?.templateRef; as suffixRef) {\n <ng-container matSuffix>\n <ng-container *ngTemplateOutlet=\"suffixRef\"></ng-container>\n </ng-container>\n }\n <!-- <ng-container matSuffix>\n <ng-content select=\"[sdSuffix]\"></ng-content>\n </ng-container> -->\n </mat-form-field>\n\n @if (_maxLength && !_hideInlineError && !formControl.disabled) {\n <div\n class=\"sd-maxlength-counter\"\n [class.sd-maxlength-counter--visible]=\"isFocused\"\n [class.sd-maxlength-counter--exceeded]=\"isMaxlengthExceeded()\"\n [attr.title]=\"isMaxlengthExceeded() ? ('core.form.input.exceeded' | translate) : null\">\n {{ getCurrentLength() }}/{{ _maxLength }}\n </div>\n }\n </div>\n </div>\n}\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-primary-contrast{color:var(--sd-primary-contrast)!important}.bg-primary-contrast{background:var(--sd-primary-contrast)!important}.border-primary-contrast{border-color:var(--sd-primary-contrast)!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-secondary-contrast{color:var(--sd-secondary-contrast)!important}.bg-secondary-contrast{background:var(--sd-secondary-contrast)!important}.border-secondary-contrast{border-color:var(--sd-secondary-contrast)!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-info-contrast{color:var(--sd-info-contrast)!important}.bg-info-contrast{background:var(--sd-info-contrast)!important}.border-info-contrast{border-color:var(--sd-info-contrast)!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-success-contrast{color:var(--sd-success-contrast)!important}.bg-success-contrast{background:var(--sd-success-contrast)!important}.border-success-contrast{border-color:var(--sd-success-contrast)!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-warning-contrast{color:var(--sd-warning-contrast)!important}.bg-warning-contrast{background:var(--sd-warning-contrast)!important}.border-warning-contrast{border-color:var(--sd-warning-contrast)!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-error-contrast{color:var(--sd-error-contrast)!important}.bg-error-contrast{background:var(--sd-error-contrast)!important}.border-error-contrast{border-color:var(--sd-error-contrast)!important}.text-surface{color:var(--sd-surface)!important}.bg-surface{background:var(--sd-surface)!important}.border-surface{border-color:var(--sd-surface)!important}.text-surface-muted{color:var(--sd-surface-muted)!important}.bg-surface-muted{background:var(--sd-surface-muted)!important}.border-surface-muted{border-color:var(--sd-surface-muted)!important}.text-text{color:var(--sd-text)!important}.bg-text{background:var(--sd-text)!important}.border-text{border-color:var(--sd-text)!important}.text-text-secondary{color:var(--sd-text-secondary)!important}.bg-text-secondary{background:var(--sd-text-secondary)!important}.border-text-secondary{border-color:var(--sd-text-secondary)!important}.text-text-muted{color:var(--sd-text-muted)!important}.bg-text-muted{background:var(--sd-text-muted)!important}.border-text-muted{border-color:var(--sd-text-muted)!important}.text-border{color:var(--sd-border)!important}.bg-border{background:var(--sd-border)!important}.border-border{border-color:var(--sd-border)!important}.text-border-strong{color:var(--sd-border-strong)!important}.bg-border-strong{background:var(--sd-border-strong)!important}.border-border-strong{border-color:var(--sd-border-strong)!important}.text-disabled-bg{color:var(--sd-disabled-bg)!important}.bg-disabled-bg{background:var(--sd-disabled-bg)!important}.border-disabled-bg{border-color:var(--sd-disabled-bg)!important}.text-disabled-text{color:var(--sd-disabled-text)!important}.bg-disabled-text{background:var(--sd-disabled-text)!important}.border-disabled-text{border-color:var(--sd-disabled-text)!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}.text-secondary{color:var(--sd-text-secondary)!important}.text-muted{color:var(--sd-text-muted)!important}.text-body{color:var(--sd-text)!important}.bg-muted{background:var(--sd-surface-muted)!important}:host{display:block}:host(.sd-has-label){padding-top:4px}:host(.sd-viewed){padding-top:0}:host ::ng-deep .mat-mdc-form-field.mat-form-field-appearance-outline.mat-form-field-disabled .mat-mdc-text-field-wrapper{background:var(--sd-disabled-bg)}:host ::ng-deep .mat-mdc-form-field input.mat-mdc-input-element:disabled{color:var(--sd-disabled-text)!important}:host ::ng-deep .mat-mdc-form-field .mat-mdc-placeholder-required{color:var(--sd-error)}.sd-input-field-wrap{position:relative;flex:1;min-width:0}.sd-maxlength-counter{position:absolute;right:4px;top:calc(100% - 16px);opacity:0;font-size:10px;line-height:1.1;color:#00000061;pointer-events:none;transition:opacity .12s ease;z-index:1}.sd-maxlength-counter--exceeded{color:var(--sd-error);font-weight:600}:host ::ng-deep .sd-input-container.c-focused .sd-maxlength-counter,:host ::ng-deep .sd-input-container:hover .sd-maxlength-counter,:host ::ng-deep .sd-input-container .sd-maxlength-counter.sd-maxlength-counter--visible{opacity:1}.sd-md:hover .btn-copy{visibility:visible}\n"] }]
605
+ }], ctorParameters: () => [], propDecorators: { control: [{ type: i0.ViewChild, args: ['control', { isSignal: true }] }], inlineRef: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdInlineText), { isSignal: true }] }], sdLabelTemplate: [{ type: i0.ContentChild, args: ['sdLabel', { isSignal: true }] }], sdValueTemplate: [{ type: i0.ContentChild, args: ['sdValue', { isSignal: true }] }], sdSuffixDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdSuffixDefDirective), { isSignal: true }] }], sdViewDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdViewDefDirective), { isSignal: true }] }], autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], appearanceInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], floatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], helperText: [{ type: i0.Input, args: [{ isSignal: true, alias: "helperText", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], hideInlineError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideInlineError", required: false }] }], blurOnEnter: [{ type: i0.Input, args: [{ isSignal: true, alias: "blurOnEnter", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], viewed: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewed", required: false }] }], minlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minlength", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], patternErrorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "patternErrorMessage", required: false }] }], validator: [{ type: i0.Input, args: [{ isSignal: true, alias: "validator", required: false }] }], inlineError: [{ type: i0.Input, args: [{ isSignal: true, alias: "inlineError", required: false }] }], hyperlink: [{ type: i0.Input, args: [{ isSignal: true, alias: "hyperlink", required: false }] }], valueModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }, { type: i0.Output, args: ["modelChange"] }], sdChange: [{ type: i0.Output, args: ["sdChange"] }], sdFocus: [{ type: i0.Output, args: ["sdFocus"] }], sdBlur: [{ type: i0.Output, args: ["sdBlur"] }], keyupEnter: [{ type: i0.Output, args: ["keyupEnter"] }], cleared: [{ type: i0.Output, args: ["cleared"] }], sdFocusForceBlur: [{
368
606
  type: Output
369
607
  }] } });
370
608
 
@@ -372,5 +610,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
372
610
  * Generated bundle index. Do not edit.
373
611
  */
374
612
 
375
- export { SdInput };
613
+ export { SD_INPUT_MASKS, SdInput, sdCreateInputMask, sdResolveInputMask };
376
614
  //# sourceMappingURL=sdcorejs-angular-forms-input.mjs.map