@cute-widgets/base 20.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/LICENSE.md +191 -0
  3. package/README.md +190 -0
  4. package/abstract/index.d.ts +327 -0
  5. package/alert/index.d.ts +68 -0
  6. package/autocomplete/index.d.ts +442 -0
  7. package/badge/index.d.ts +26 -0
  8. package/bottom-sheet/index.d.ts +231 -0
  9. package/button/index.d.ts +182 -0
  10. package/button-toggle/index.d.ts +225 -0
  11. package/card/index.d.ts +163 -0
  12. package/checkbox/index.d.ts +174 -0
  13. package/chips/index.d.ts +963 -0
  14. package/collapse/index.d.ts +97 -0
  15. package/core/animation/index.d.ts +43 -0
  16. package/core/datetime/index.d.ts +404 -0
  17. package/core/directives/index.d.ts +168 -0
  18. package/core/error/index.d.ts +74 -0
  19. package/core/index.d.ts +1039 -0
  20. package/core/interfaces/index.d.ts +114 -0
  21. package/core/layout/index.d.ts +53 -0
  22. package/core/line/index.d.ts +37 -0
  23. package/core/nav/index.d.ts +321 -0
  24. package/core/observers/index.d.ts +124 -0
  25. package/core/option/index.d.ts +185 -0
  26. package/core/pipes/index.d.ts +53 -0
  27. package/core/ripple/index.d.ts +66 -0
  28. package/core/testing/index.d.ts +154 -0
  29. package/core/theming/index.d.ts +118 -0
  30. package/core/types/index.d.ts +53 -0
  31. package/core/utils/index.d.ts +129 -0
  32. package/cute-widgets-base-20.0.1.tgz +0 -0
  33. package/datepicker/index.d.ts +1817 -0
  34. package/dialog/index.d.ts +484 -0
  35. package/divider/index.d.ts +24 -0
  36. package/expansion/README.md +8 -0
  37. package/expansion/index.d.ts +308 -0
  38. package/fesm2022/cute-widgets-base-abstract.mjs +547 -0
  39. package/fesm2022/cute-widgets-base-abstract.mjs.map +1 -0
  40. package/fesm2022/cute-widgets-base-alert.mjs +198 -0
  41. package/fesm2022/cute-widgets-base-alert.mjs.map +1 -0
  42. package/fesm2022/cute-widgets-base-autocomplete.mjs +1217 -0
  43. package/fesm2022/cute-widgets-base-autocomplete.mjs.map +1 -0
  44. package/fesm2022/cute-widgets-base-badge.mjs +75 -0
  45. package/fesm2022/cute-widgets-base-badge.mjs.map +1 -0
  46. package/fesm2022/cute-widgets-base-bottom-sheet.mjs +416 -0
  47. package/fesm2022/cute-widgets-base-bottom-sheet.mjs.map +1 -0
  48. package/fesm2022/cute-widgets-base-button-toggle.mjs +640 -0
  49. package/fesm2022/cute-widgets-base-button-toggle.mjs.map +1 -0
  50. package/fesm2022/cute-widgets-base-button.mjs +546 -0
  51. package/fesm2022/cute-widgets-base-button.mjs.map +1 -0
  52. package/fesm2022/cute-widgets-base-card.mjs +471 -0
  53. package/fesm2022/cute-widgets-base-card.mjs.map +1 -0
  54. package/fesm2022/cute-widgets-base-checkbox.mjs +390 -0
  55. package/fesm2022/cute-widgets-base-checkbox.mjs.map +1 -0
  56. package/fesm2022/cute-widgets-base-chips.mjs +2360 -0
  57. package/fesm2022/cute-widgets-base-chips.mjs.map +1 -0
  58. package/fesm2022/cute-widgets-base-collapse.mjs +259 -0
  59. package/fesm2022/cute-widgets-base-collapse.mjs.map +1 -0
  60. package/fesm2022/cute-widgets-base-core-animation.mjs +53 -0
  61. package/fesm2022/cute-widgets-base-core-animation.mjs.map +1 -0
  62. package/fesm2022/cute-widgets-base-core-datetime.mjs +568 -0
  63. package/fesm2022/cute-widgets-base-core-datetime.mjs.map +1 -0
  64. package/fesm2022/cute-widgets-base-core-directives.mjs +404 -0
  65. package/fesm2022/cute-widgets-base-core-directives.mjs.map +1 -0
  66. package/fesm2022/cute-widgets-base-core-error.mjs +105 -0
  67. package/fesm2022/cute-widgets-base-core-error.mjs.map +1 -0
  68. package/fesm2022/cute-widgets-base-core-interfaces.mjs +22 -0
  69. package/fesm2022/cute-widgets-base-core-interfaces.mjs.map +1 -0
  70. package/fesm2022/cute-widgets-base-core-layout.mjs +74 -0
  71. package/fesm2022/cute-widgets-base-core-layout.mjs.map +1 -0
  72. package/fesm2022/cute-widgets-base-core-line.mjs +87 -0
  73. package/fesm2022/cute-widgets-base-core-line.mjs.map +1 -0
  74. package/fesm2022/cute-widgets-base-core-nav.mjs +863 -0
  75. package/fesm2022/cute-widgets-base-core-nav.mjs.map +1 -0
  76. package/fesm2022/cute-widgets-base-core-observers.mjs +304 -0
  77. package/fesm2022/cute-widgets-base-core-observers.mjs.map +1 -0
  78. package/fesm2022/cute-widgets-base-core-option.mjs +373 -0
  79. package/fesm2022/cute-widgets-base-core-option.mjs.map +1 -0
  80. package/fesm2022/cute-widgets-base-core-pipes.mjs +97 -0
  81. package/fesm2022/cute-widgets-base-core-pipes.mjs.map +1 -0
  82. package/fesm2022/cute-widgets-base-core-ripple.mjs +172 -0
  83. package/fesm2022/cute-widgets-base-core-ripple.mjs.map +1 -0
  84. package/fesm2022/cute-widgets-base-core-testing.mjs +210 -0
  85. package/fesm2022/cute-widgets-base-core-testing.mjs.map +1 -0
  86. package/fesm2022/cute-widgets-base-core-theming.mjs +314 -0
  87. package/fesm2022/cute-widgets-base-core-theming.mjs.map +1 -0
  88. package/fesm2022/cute-widgets-base-core-types.mjs +22 -0
  89. package/fesm2022/cute-widgets-base-core-types.mjs.map +1 -0
  90. package/fesm2022/cute-widgets-base-core-utils.mjs +257 -0
  91. package/fesm2022/cute-widgets-base-core-utils.mjs.map +1 -0
  92. package/fesm2022/cute-widgets-base-core.mjs +1600 -0
  93. package/fesm2022/cute-widgets-base-core.mjs.map +1 -0
  94. package/fesm2022/cute-widgets-base-datepicker.mjs +4827 -0
  95. package/fesm2022/cute-widgets-base-datepicker.mjs.map +1 -0
  96. package/fesm2022/cute-widgets-base-dialog.mjs +1046 -0
  97. package/fesm2022/cute-widgets-base-dialog.mjs.map +1 -0
  98. package/fesm2022/cute-widgets-base-divider.mjs +86 -0
  99. package/fesm2022/cute-widgets-base-divider.mjs.map +1 -0
  100. package/fesm2022/cute-widgets-base-expansion.mjs +623 -0
  101. package/fesm2022/cute-widgets-base-expansion.mjs.map +1 -0
  102. package/fesm2022/cute-widgets-base-form-field.mjs +969 -0
  103. package/fesm2022/cute-widgets-base-form-field.mjs.map +1 -0
  104. package/fesm2022/cute-widgets-base-grid-list.mjs +715 -0
  105. package/fesm2022/cute-widgets-base-grid-list.mjs.map +1 -0
  106. package/fesm2022/cute-widgets-base-icon.mjs +1105 -0
  107. package/fesm2022/cute-widgets-base-icon.mjs.map +1 -0
  108. package/fesm2022/cute-widgets-base-input.mjs +726 -0
  109. package/fesm2022/cute-widgets-base-input.mjs.map +1 -0
  110. package/fesm2022/cute-widgets-base-layout-container.mjs +95 -0
  111. package/fesm2022/cute-widgets-base-layout-container.mjs.map +1 -0
  112. package/fesm2022/cute-widgets-base-layout-stack.mjs +166 -0
  113. package/fesm2022/cute-widgets-base-layout-stack.mjs.map +1 -0
  114. package/fesm2022/cute-widgets-base-layout.mjs +250 -0
  115. package/fesm2022/cute-widgets-base-layout.mjs.map +1 -0
  116. package/fesm2022/cute-widgets-base-list.mjs +1557 -0
  117. package/fesm2022/cute-widgets-base-list.mjs.map +1 -0
  118. package/fesm2022/cute-widgets-base-menu.mjs +1283 -0
  119. package/fesm2022/cute-widgets-base-menu.mjs.map +1 -0
  120. package/fesm2022/cute-widgets-base-navbar.mjs +359 -0
  121. package/fesm2022/cute-widgets-base-navbar.mjs.map +1 -0
  122. package/fesm2022/cute-widgets-base-paginator.mjs +485 -0
  123. package/fesm2022/cute-widgets-base-paginator.mjs.map +1 -0
  124. package/fesm2022/cute-widgets-base-progress.mjs +321 -0
  125. package/fesm2022/cute-widgets-base-progress.mjs.map +1 -0
  126. package/fesm2022/cute-widgets-base-radio.mjs +637 -0
  127. package/fesm2022/cute-widgets-base-radio.mjs.map +1 -0
  128. package/fesm2022/cute-widgets-base-select.mjs +1208 -0
  129. package/fesm2022/cute-widgets-base-select.mjs.map +1 -0
  130. package/fesm2022/cute-widgets-base-sidenav.mjs +1095 -0
  131. package/fesm2022/cute-widgets-base-sidenav.mjs.map +1 -0
  132. package/fesm2022/cute-widgets-base-slider.mjs +99 -0
  133. package/fesm2022/cute-widgets-base-slider.mjs.map +1 -0
  134. package/fesm2022/cute-widgets-base-snack-bar.mjs +897 -0
  135. package/fesm2022/cute-widgets-base-snack-bar.mjs.map +1 -0
  136. package/fesm2022/cute-widgets-base-sort.mjs +639 -0
  137. package/fesm2022/cute-widgets-base-sort.mjs.map +1 -0
  138. package/fesm2022/cute-widgets-base-spinner.mjs +154 -0
  139. package/fesm2022/cute-widgets-base-spinner.mjs.map +1 -0
  140. package/fesm2022/cute-widgets-base-stepper.mjs +673 -0
  141. package/fesm2022/cute-widgets-base-stepper.mjs.map +1 -0
  142. package/fesm2022/cute-widgets-base-table.mjs +1023 -0
  143. package/fesm2022/cute-widgets-base-table.mjs.map +1 -0
  144. package/fesm2022/cute-widgets-base-tabs.mjs +729 -0
  145. package/fesm2022/cute-widgets-base-tabs.mjs.map +1 -0
  146. package/fesm2022/cute-widgets-base-timepicker.mjs +965 -0
  147. package/fesm2022/cute-widgets-base-timepicker.mjs.map +1 -0
  148. package/fesm2022/cute-widgets-base-toolbar.mjs +120 -0
  149. package/fesm2022/cute-widgets-base-toolbar.mjs.map +1 -0
  150. package/fesm2022/cute-widgets-base-tooltip.mjs +947 -0
  151. package/fesm2022/cute-widgets-base-tooltip.mjs.map +1 -0
  152. package/fesm2022/cute-widgets-base-tree.mjs +598 -0
  153. package/fesm2022/cute-widgets-base-tree.mjs.map +1 -0
  154. package/fesm2022/cute-widgets-base.mjs +68 -0
  155. package/fesm2022/cute-widgets-base.mjs.map +1 -0
  156. package/form-field/index.d.ts +401 -0
  157. package/grid-list/index.d.ts +361 -0
  158. package/icon/index.d.ts +477 -0
  159. package/index.d.ts +3 -0
  160. package/input/index.d.ts +256 -0
  161. package/layout/container/index.d.ts +31 -0
  162. package/layout/index.d.ts +78 -0
  163. package/layout/stack/index.d.ts +52 -0
  164. package/list/index.d.ts +659 -0
  165. package/menu/index.d.ts +497 -0
  166. package/navbar/index.d.ts +91 -0
  167. package/package.json +279 -0
  168. package/paginator/index.d.ts +216 -0
  169. package/progress/index.d.ts +130 -0
  170. package/radio/index.d.ts +259 -0
  171. package/select/index.d.ts +426 -0
  172. package/sidenav/index.d.ts +369 -0
  173. package/slider/index.d.ts +48 -0
  174. package/snack-bar/index.d.ts +374 -0
  175. package/sort/index.d.ts +334 -0
  176. package/spinner/index.d.ts +70 -0
  177. package/stepper/index.d.ts +295 -0
  178. package/table/index.d.ts +395 -0
  179. package/tabs/index.d.ts +307 -0
  180. package/timepicker/index.d.ts +350 -0
  181. package/toolbar/index.d.ts +36 -0
  182. package/tooltip/index.d.ts +299 -0
  183. package/tree/index.d.ts +314 -0
@@ -0,0 +1,726 @@
1
+ import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
+ import { getSupportedInputTypes, Platform } from '@angular/cdk/platform';
3
+ import { AutofillMonitor } from '@angular/cdk/text-field';
4
+ import * as i0 from '@angular/core';
5
+ import { InjectionToken, inject, ElementRef, NgZone, isSignal, effect, isDevMode, booleanAttribute, Input, HostBinding, Directive, NgModule } from '@angular/core';
6
+ import { Validators, NgControl, NgForm, FormGroupDirective } from '@angular/forms';
7
+ import { ErrorStateMatcher, _ErrorStateTracker } from '@cute-widgets/base/core/error';
8
+ import { CUTE_FORM_FIELD, CuteFormFieldControl, CuteFormFieldModule } from '@cute-widgets/base/form-field';
9
+ import { CuteInputControl } from '@cute-widgets/base/abstract';
10
+ import { Subject } from 'rxjs';
11
+ import { CommonModule } from '@angular/common';
12
+
13
+ /**
14
+ * @license Apache-2.0
15
+ *
16
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
17
+ *
18
+ * You may not use this file except in compliance with the License
19
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
20
+ *
21
+ * This code is a modification of the `@angular/material` original
22
+ * code licensed under MIT-style License (https://angular.dev/license).
23
+ */
24
+ function getCuteInputUnsupportedTypeError(type) {
25
+ return Error(`Input type "${type}" isn't supported by 'cuteInput' directive.`);
26
+ }
27
+
28
+ /**
29
+ * @license Apache-2.0
30
+ *
31
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
32
+ *
33
+ * You may not use this file except in compliance with the License
34
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
35
+ *
36
+ * This code is a modification of the `@angular/material` original
37
+ * code licensed under MIT-style License (https://angular.dev/license).
38
+ */
39
+ /**
40
+ * This token is used to inject the object whose value should be set into `CuteInput`. If none is
41
+ * provided, the native `HTMLInputElement` is used. Directives like `CuteDatepickerInput` can provide
42
+ * themselves for this token, in order to make `CuteInput` delegate the getting and setting of the
43
+ * value to them.
44
+ */
45
+ const CUTE_INPUT_VALUE_ACCESSOR = new InjectionToken('CUTE_INPUT_VALUE_ACCESSOR');
46
+
47
+ /**
48
+ * @license Apache-2.0
49
+ *
50
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
51
+ *
52
+ * You may not use this file except in compliance with the License
53
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
54
+ */
55
+ /** This token is used to inject an object that will be applied to format a raw input value */
56
+ const CUTE_INPUT_VALUE_FORMATTER = new InjectionToken('CUTE_INPUT_VALUE_FORMATTER');
57
+
58
+ /**
59
+ * @license Apache-2.0
60
+ *
61
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
62
+ *
63
+ * You may not use this file except in compliance with the License
64
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
65
+ */
66
+ /**
67
+ * This token is used to inject an object with special methods that will be invoked before _ControlValueAccessor_'s methods do.
68
+ * The typical example of such object is a _CuteEditMask_, that needs to get masked value before assign it to the view and
69
+ * get cleaned value before send it to the model (form control).
70
+ */
71
+ const CUTE_INPUT_VALUE_PREDECESSOR = new InjectionToken('CUTE_INPUT_VALUE_PREDECESSOR');
72
+
73
+ /**
74
+ * @license Apache-2.0
75
+ *
76
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
77
+ *
78
+ * You may not use this file except in compliance with the License
79
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
80
+ *
81
+ * This code is a modification of the `@angular/material` original
82
+ * code licensed under MIT-style License (https://angular.dev/license).
83
+ */
84
+ // Invalid input type. Using one of these will throw an CuteInputUnsupportedTypeError.
85
+ const CUTE_INPUT_INVALID_TYPES = [
86
+ 'button',
87
+ 'checkbox',
88
+ //'file',
89
+ 'hidden',
90
+ 'image',
91
+ 'radio',
92
+ //'range',
93
+ 'reset',
94
+ 'submit',
95
+ ];
96
+ /** Injection token that can be used to provide the default options for the input. */
97
+ const CUTE_INPUT_CONFIG = new InjectionToken('CUTE_INPUT_CONFIG');
98
+ let nextUniqueId = 0;
99
+ /**
100
+ * We must check whether the agent is Android because composition events
101
+ * behave differently between iOS and Android.
102
+ */
103
+ // function _isAndroid(): boolean {
104
+ // const userAgent = getDOM() ? getDOM().getUserAgent() : '';
105
+ // return /android (\d+)/.test(userAgent.toLowerCase());
106
+ // }
107
+ class CuteInput extends CuteInputControl {
108
+ /** Implemented as part of CuteFormFieldControl. */
109
+ get controlElementRef() { return this._elementRef; }
110
+ generateId() {
111
+ return `cute-input-${nextUniqueId++}`;
112
+ }
113
+ get classList() {
114
+ if (["range"].indexOf(this.type) >= 0) {
115
+ return "";
116
+ }
117
+ let classes = (this._isNativeSelect ? "form-select" : "form-control" + (this.plainText ? "-plaintext" : ""));
118
+ if (this.magnitude && this.magnitude !== "middle") {
119
+ classes += " " + (this._isNativeSelect ? "form-select" : "form-control") + this.cssClassSizeSuffix;
120
+ }
121
+ return classes;
122
+ }
123
+ /** Implemented as part of CuteFormFieldControl. */
124
+ setDisabledState(value) {
125
+ const changed = super.setDisabledState(value, false);
126
+ if (changed) {
127
+ // Browsers may not fire the blur event if the input is disabled too quickly.
128
+ // Reset from here to ensure that the element doesn't become stuck.
129
+ if (this.focused) {
130
+ this.focused = false;
131
+ this.stateChanges.next();
132
+ }
133
+ }
134
+ return changed;
135
+ }
136
+ /** Implemented as part of CuteFormFieldControl. */
137
+ get required() {
138
+ return super.required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
139
+ }
140
+ set required(value) {
141
+ super.required = coerceBooleanProperty(value);
142
+ }
143
+ /** Input type of the element. */
144
+ get type() { return this._type; }
145
+ set type(value) {
146
+ const prevType = this._type;
147
+ this._type = value || 'text';
148
+ this._validateType();
149
+ // When using Angular inputs, developers are no longer able to set the properties on the native
150
+ // input element. To ensure that bindings for `type` work, we need to sync the setter
151
+ // with the native property. Textarea elements don't support the type property or attribute.
152
+ if (!this._isTextarea && getSupportedInputTypes().has(this._type)) {
153
+ this._elementRef.nativeElement.type = this._type;
154
+ }
155
+ if (this._type !== prevType) {
156
+ this._ensureWheelDefaultBehavior();
157
+ }
158
+ }
159
+ /** An object used to control when error messages are shown. */
160
+ get errorStateMatcher() { return this._errorStateTracker.matcher; }
161
+ set errorStateMatcher(value) {
162
+ this._errorStateTracker.matcher = value;
163
+ }
164
+ /** Implemented as part of CuteFormFieldControl. */
165
+ get value() {
166
+ return this._signalBasedValueAccessor
167
+ ? this._signalBasedValueAccessor.value()
168
+ : this._inputValueAccessor.value;
169
+ }
170
+ set value(value) {
171
+ if (value !== this.value) {
172
+ if (this._signalBasedValueAccessor) {
173
+ this._signalBasedValueAccessor.value.set(value);
174
+ }
175
+ else {
176
+ this._inputValueAccessor.value = value;
177
+ }
178
+ this.stateChanges.next();
179
+ }
180
+ }
181
+ /** Whether the element is readonly. */
182
+ get readonly() { return this._readonly; }
183
+ set readonly(value) {
184
+ this._readonly = coerceBooleanProperty(value);
185
+ }
186
+ /** Whether the input control is styled as a plain text. Use it with `readonly` property. */
187
+ get plainText() { return this._plainText; }
188
+ set plainText(value) {
189
+ if (!this._isNativeSelect) {
190
+ this._plainText = value;
191
+ }
192
+ }
193
+ /** Whether the input is in an error state. */
194
+ get errorState() { return this._errorStateTracker.errorState; }
195
+ set errorState(value) { this._errorStateTracker.errorState = value; }
196
+ /** Returns bootstrap's size suffix for CSS classes */
197
+ get cssClassSizeSuffix() {
198
+ if (this.magnitude == "small") {
199
+ return "-sm";
200
+ }
201
+ else if (this.magnitude == "large") {
202
+ return "-lg";
203
+ }
204
+ return "";
205
+ }
206
+ constructor() {
207
+ super();
208
+ this._elementRef = inject(ElementRef);
209
+ this._platform = inject(Platform);
210
+ this.ngControl = inject(NgControl, { optional: true, self: true });
211
+ this._autofillMonitor = inject(AutofillMonitor);
212
+ this._ngZone = inject(NgZone);
213
+ this._formField = inject(CUTE_FORM_FIELD, { optional: true });
214
+ this._valueFormatter = inject(CUTE_INPUT_VALUE_FORMATTER, { optional: true, self: true });
215
+ this._inputValuePredecessor = inject(CUTE_INPUT_VALUE_PREDECESSOR, { optional: true, self: true });
216
+ this._inputValueAccessor = { value: undefined };
217
+ this._previousPlaceholder = null;
218
+ this._config = inject(CUTE_INPUT_CONFIG, { optional: true });
219
+ this._destroyed$ = new Subject();
220
+ this._compositionMode = false;
221
+ /** Whether the user is creating a composition string (IME events). */
222
+ this._composing = false;
223
+ /** Implemented as part of CuteFormFieldControl. */
224
+ this.focused = false;
225
+ /** Implemented as part of CuteFormFieldControl. */
226
+ this.controlType = 'cute-input';
227
+ /** Implemented as part of CuteFormFieldControl. */
228
+ this.autofilled = false;
229
+ this._type = 'text';
230
+ this._readonly = false;
231
+ /** Whether the input should remain interactive when it is disabled. */
232
+ this.disabledInteractive = false;
233
+ this._plainText = false;
234
+ this._neverEmptyInputTypes = [
235
+ 'date',
236
+ 'datetime',
237
+ 'datetime-local',
238
+ 'month',
239
+ 'time',
240
+ 'week',
241
+ ].filter(t => getSupportedInputTypes().has(t));
242
+ this._iOSKeyupListener = (event) => {
243
+ const el = event.target;
244
+ // Note: We specifically check for 0, rather than `!el.selectionStart`, because the two
245
+ // indicate different things. If the value is 0, it means that the caret is at the start
246
+ // of the input, whereas a value of `null` means that the input doesn't support
247
+ // manipulating the selection range. Inputs that don't support setting the selection range
248
+ // will throw an error, so we want to avoid calling `setSelectionRange` on them. See:
249
+ // https://html.spec.whatwg.org/multipage/input.html#do-not-apply
250
+ if (!el.value && el.selectionStart === 0 && el.selectionEnd === 0) {
251
+ // Note: Just setting `0, 0` doesn't fix the issue. Setting
252
+ // `1, 1` fixes it for the first time that you type text and
253
+ // then hold delete. Toggling to `1, 1` and then back to
254
+ // `0, 0` seems to completely fix it.
255
+ el.setSelectionRange(1, 1);
256
+ el.setSelectionRange(0, 0);
257
+ }
258
+ };
259
+ this._webkitBlinkWheelListener = () => {
260
+ // This is a noop function and is used to enable mouse wheel input
261
+ // on number inputs
262
+ // on blink and webkit browsers.
263
+ };
264
+ const parentForm = inject(NgForm, { optional: true });
265
+ const parentFormGroup = inject(FormGroupDirective, { optional: true });
266
+ const defaultErrorStateMatcher = inject(ErrorStateMatcher);
267
+ const accessor = inject(CUTE_INPUT_VALUE_ACCESSOR, { optional: true, self: true });
268
+ const element = this._elementRef.nativeElement;
269
+ const nodeName = element.nodeName.toLowerCase();
270
+ if (accessor) {
271
+ if (isSignal(accessor.value)) {
272
+ this._signalBasedValueAccessor = accessor;
273
+ }
274
+ else {
275
+ this._inputValueAccessor = accessor;
276
+ }
277
+ }
278
+ else {
279
+ // If no input value accessor was explicitly specified, use the element as the input value
280
+ // accessor.
281
+ this._inputValueAccessor = element;
282
+ }
283
+ this._previousNativeValue = this.value;
284
+ // Force setter to be called in case id was not specified.
285
+ this.id = this.id;
286
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
287
+ // We are changing the valueAccessor from the DefaultValueAccessor object to our class!!!
288
+ //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
289
+ // if (this.ngControl) {
290
+ // // Note: we provide the value accessor through here, instead of
291
+ // // the `providers` to avoid running into a circular import.
292
+ // this.ngControl.valueAccessor = this;
293
+ //
294
+ // // This is a snippet code that we need to prevent the loss of functionality implemented in
295
+ // // DefaultValueAccessor class.
296
+ // this._compositionMode = inject(COMPOSITION_BUFFER_MODE, {optional: true});
297
+ // if (this._compositionMode == null) {
298
+ // this._compositionMode = !_isAndroid();
299
+ // }
300
+ // }
301
+ //-------------------------------------------------------------------------------------
302
+ // On some versions of iOS, the caret gets stuck in the wrong place when holding down the delete
303
+ // key. In order to get around this, we need to "jiggle" the caret loose. Since this bug only
304
+ // exists on iOS, we only bother to install the listener on iOS.
305
+ if (this._platform.IOS) {
306
+ this._ngZone.runOutsideAngular(() => {
307
+ this._cleanupIosKeyup = this._renderer.listen(element, 'keyup', this._iOSKeyupListener);
308
+ });
309
+ }
310
+ this._errorStateTracker = new _ErrorStateTracker(defaultErrorStateMatcher, this.ngControl, parentFormGroup, parentForm, this.stateChanges);
311
+ this._isServer = !this._platform.isBrowser;
312
+ this._isNativeSelect = nodeName === 'select';
313
+ this._isTextarea = nodeName === 'textarea';
314
+ this._isInFormField = !!this._formField;
315
+ this.disabledInteractive = this._config?.disabledInteractive || false;
316
+ if (this._isNativeSelect) {
317
+ this.controlType = element.multiple
318
+ ? 'cute-native-select-multiple'
319
+ : 'cute-native-select';
320
+ }
321
+ if (this._signalBasedValueAccessor) {
322
+ effect(() => {
323
+ // Read the value so the effect can register the dependency.
324
+ this._signalBasedValueAccessor.value();
325
+ this.stateChanges.next();
326
+ });
327
+ }
328
+ //++
329
+ // Promise.resolve().then(()=>{
330
+ // this.ngControl?.valueChanges?.pipe(takeUntil(this._destroyed$)).subscribe((v)=> {
331
+ // this.writeValue(v);
332
+ // });
333
+ // });
334
+ //--
335
+ }
336
+ registerOnChange(fn) {
337
+ this._onChange = (value) => {
338
+ if (this._inputValuePredecessor) {
339
+ value = this._inputValuePredecessor.beforeOnChange(value);
340
+ }
341
+ fn(value);
342
+ };
343
+ }
344
+ writeValue(newValue) {
345
+ const element = this._nativeElement;
346
+ element.type = this.type;
347
+ if (this.focused) {
348
+ if (this._inputValuePredecessor) {
349
+ newValue = this._inputValuePredecessor.beforeWriteValue(newValue);
350
+ }
351
+ }
352
+ else {
353
+ if (this._valueFormatter) {
354
+ const srcValue = newValue;
355
+ newValue = this._valueFormatter.format(newValue);
356
+ if (srcValue !== newValue) {
357
+ element.type = "text";
358
+ }
359
+ }
360
+ else if (this._inputValuePredecessor) {
361
+ newValue = this._inputValuePredecessor.beforeWriteValue(newValue);
362
+ }
363
+ }
364
+ this.value = newValue ?? "";
365
+ }
366
+ ngAfterViewInit() {
367
+ super.ngAfterViewInit();
368
+ if (this._platform.isBrowser) {
369
+ this._autofillMonitor.monitor(this._elementRef.nativeElement).subscribe(event => {
370
+ this.autofilled = event.isAutofilled;
371
+ this.stateChanges.next();
372
+ });
373
+ }
374
+ }
375
+ ngOnChanges(changes) {
376
+ super.ngOnChanges(changes);
377
+ this.stateChanges.next();
378
+ }
379
+ ngOnDestroy() {
380
+ super.ngOnDestroy();
381
+ if (this._platform.isBrowser) {
382
+ this._autofillMonitor.stopMonitoring(this._elementRef.nativeElement);
383
+ }
384
+ this._cleanupIosKeyup?.();
385
+ this._cleanupWebkitWheel?.();
386
+ this._destroyed$.next();
387
+ this._destroyed$.complete();
388
+ }
389
+ ngDoCheck() {
390
+ if (this.ngControl) {
391
+ // We need to re-evaluate this on every change detection cycle, because there are some
392
+ // error triggers that we can't subscribe to (e.g. parent form submissions). This means
393
+ // that whatever logic is in here has to be super lean, or we risk destroying the performance.
394
+ this.updateErrorState();
395
+ // Since the input isn't a `ControlValueAccessor`, we don't have a good way of knowing when
396
+ // the disabled state has changed. We can't use the `ngControl.statusChanges`, because it
397
+ // won't fire if the input is disabled with `emitEvents = false`, despite the input becoming
398
+ // disabled.
399
+ if (this.ngControl.disabled !== null && this.ngControl.disabled !== this.disabled) {
400
+ this.disabled = this.ngControl.disabled;
401
+ this.stateChanges.next();
402
+ }
403
+ }
404
+ // We need to dirty-check the native element's value, because there are some cases where
405
+ // we won't be notified when it changes (e.g., the consumer isn't using forms, or they're
406
+ // updating the value using `emitEvent: false`).
407
+ this._dirtyCheckNativeValue();
408
+ // We need to dirty-check and set the placeholder attribute ourselves, because whether it's
409
+ // present or not depends on a query which is prone to "changed after checked" errors.
410
+ this._dirtyCheckPlaceholder();
411
+ }
412
+ /** Refreshes the error state of the input. */
413
+ updateErrorState() {
414
+ this._errorStateTracker.updateErrorState();
415
+ }
416
+ /** Callback for the cases where the focused state of the input changes. */
417
+ _focusChanged(isFocused) {
418
+ if (isFocused === this.focused) {
419
+ return;
420
+ }
421
+ const element = this._elementRef.nativeElement;
422
+ if (!this._isNativeSelect && isFocused && this.disabled && this.disabledInteractive) {
423
+ // Focusing an input that has text will cause all the text to be selected. Clear it since
424
+ // the user won't be able to change it. This is based on the internal implementation.
425
+ if (element.type === 'number') {
426
+ // setSelectionRange doesn't work on number inputs, so it needs to be set briefly to text.
427
+ element.type = 'text';
428
+ element.setSelectionRange(0, 0);
429
+ element.type = 'number';
430
+ }
431
+ else {
432
+ element.setSelectionRange(0, 0);
433
+ }
434
+ }
435
+ this.focused = isFocused;
436
+ if (!isFocused) {
437
+ this._onTouched();
438
+ }
439
+ //++
440
+ // if (this.ngControl) {
441
+ // this.writeValue(this.ngControl.value);
442
+ // }
443
+ //--
444
+ this.stateChanges.next();
445
+ }
446
+ _onInput(event) {
447
+ // This is a noop function and is used to let Angular know whenever the value changes.
448
+ // Angular will run new change detection each time the `input` event has been dispatched.
449
+ // It's necessary that Angular recognizes the value change, because when floatingLabel
450
+ // is set to false and Angular forms aren't used, the placeholder won't recognize the
451
+ // value changes and will not disappear.
452
+ // Listening to the input event wouldn't be necessary when the input is using the
453
+ // FormsModule or ReactiveFormsModule, because Angular forms also listen to input events.
454
+ if (!this._compositionMode || (this._compositionMode && !this._composing)) {
455
+ const inputElem = event.target;
456
+ this._onChange(inputElem.value);
457
+ }
458
+ }
459
+ /** Does some manual dirty checking on the native input `value` property. */
460
+ _dirtyCheckNativeValue() {
461
+ const newValue = this._elementRef.nativeElement.value;
462
+ if (this._previousNativeValue !== newValue) {
463
+ this._previousNativeValue = newValue;
464
+ //this.writeValue(newValue); //++ Don't use!!! `Datepicker` broking!
465
+ this.stateChanges.next();
466
+ }
467
+ }
468
+ /** Does some manual dirty checking on the native input `placeholder` attribute. */
469
+ _dirtyCheckPlaceholder() {
470
+ const placeholder = this._getPlaceholder();
471
+ if (placeholder !== this._previousPlaceholder) {
472
+ const element = this._elementRef.nativeElement;
473
+ this._previousPlaceholder = placeholder;
474
+ placeholder
475
+ ? element.setAttribute('placeholder', placeholder)
476
+ : element.removeAttribute('placeholder');
477
+ }
478
+ }
479
+ /** Gets the current placeholder of the form field. */
480
+ _getPlaceholder() {
481
+ if (this._formField && this._formField._isFloatLabel) {
482
+ // Bootstrap floating labels always NEED a `placeholder` attribute
483
+ return this.placeholder || " ";
484
+ }
485
+ return this.placeholder || null;
486
+ }
487
+ /** Make sure the input is a supported type. */
488
+ _validateType() {
489
+ if (CUTE_INPUT_INVALID_TYPES.indexOf(this._type) > -1 && isDevMode()) {
490
+ throw getCuteInputUnsupportedTypeError(this._type);
491
+ }
492
+ }
493
+ /** Checks whether the input type is one of the types that are never empty. */
494
+ _isNeverEmpty() {
495
+ return this._neverEmptyInputTypes.indexOf(this._type) > -1;
496
+ }
497
+ /** Checks whether the input is invalid based on the native validation. */
498
+ _isBadInput() {
499
+ // The `validity` property won't be present on platform-server.
500
+ let validity = this._elementRef.nativeElement.validity;
501
+ return validity && validity.badInput;
502
+ }
503
+ /**
504
+ * Implemented as part of CuteFormFieldControl.
505
+ */
506
+ get empty() {
507
+ return (!this._isNeverEmpty() &&
508
+ !this._elementRef.nativeElement.value &&
509
+ !this._isBadInput() &&
510
+ !this.autofilled);
511
+ }
512
+ /**
513
+ * Implemented as part of CuteFormFieldControl.
514
+ */
515
+ get shouldLabelFloat() {
516
+ if (this._isNativeSelect) {
517
+ // For a single-selection `<select>`, the label should float when the selected option has
518
+ // a non-empty display value. For a `<select multiple>`, the label *always* floats to avoid
519
+ // overlapping the label with the options.
520
+ const selectElement = this._elementRef.nativeElement;
521
+ const firstOption = selectElement.options[0];
522
+ // On most browsers the `selectedIndex` will always be 0, however on IE and Edge it'll be
523
+ // -1 if the `value` is set to something, that isn't in the list of options, at a later point.
524
+ return (this.focused ||
525
+ selectElement.multiple ||
526
+ !this.empty ||
527
+ !!(selectElement.selectedIndex > -1 && firstOption && firstOption.label));
528
+ }
529
+ else {
530
+ return (this.focused && !this.disabled) || !this.empty;
531
+ }
532
+ }
533
+ /**
534
+ * Implemented as part of CuteFormFieldControl.
535
+ */
536
+ setDescribedByIds(ids) {
537
+ const element = this._elementRef.nativeElement;
538
+ const existingDescribedBy = element.getAttribute('aria-describedby');
539
+ let toAssign;
540
+ // In some cases, there might be some `aria-describedby` IDs that were assigned directly,
541
+ // like by the `AriaDescriber` (see #30011). Attempt to preserve them by taking the previous
542
+ // attribute value and filtering out the IDs that came from the previous `setDescribedByIds`
543
+ // call. Note the `|| ids` here allows us to avoid duplicating IDs on the first render.
544
+ if (existingDescribedBy) {
545
+ const exclude = this._formFieldDescribedBy || ids;
546
+ toAssign = ids.concat(existingDescribedBy.split(' ').filter(id => id && !exclude.includes(id)));
547
+ }
548
+ else {
549
+ toAssign = ids;
550
+ }
551
+ this._formFieldDescribedBy = ids;
552
+ if (toAssign.length) {
553
+ element.setAttribute('aria-describedby', toAssign.join(' '));
554
+ }
555
+ else {
556
+ element.removeAttribute('aria-describedby');
557
+ }
558
+ }
559
+ /**
560
+ * Implemented as part of CuteFormFieldControl.
561
+ */
562
+ onContainerClick() {
563
+ // Do not re-focus the input element if the element is already focused. Otherwise, it can happen
564
+ // that someone clicks on a time input and the cursor resets to the "hours" field while the
565
+ // "minutes" field was actually clicked. See: https://github.com/angular/components/issues/12849
566
+ if (!this.focused) {
567
+ this.focus();
568
+ }
569
+ }
570
+ /** Whether the form control is native select that is displayed inline. */
571
+ _isInlineSelect() {
572
+ const element = this._elementRef.nativeElement;
573
+ return this._isNativeSelect && (element.multiple || element.size > 1);
574
+ }
575
+ /**
576
+ * In blink and webkit browsers, a focused number input does not increment or decrement its value
577
+ * on mouse wheel interaction unless a wheel event listener is attached to it or one of its ancestors or a passive-wheel listener is attached somewhere in the DOM.
578
+ * For example, Hitting a tooltip once enables the mouse wheel input for all number inputs as long as it exists.
579
+ * In order to get reliable and intuitive behavior, we apply a wheel event on our own,
580
+ * thus making sure increment and decrement by mouse wheel works every time.
581
+ * @docs-private
582
+ */
583
+ _ensureWheelDefaultBehavior() {
584
+ this._cleanupWebkitWheel?.();
585
+ if (this._type === 'number' && (this._platform.BLINK || this._platform.WEBKIT)) {
586
+ this._cleanupWebkitWheel = this._renderer.listen(this._elementRef.nativeElement, 'wheel', this._webkitBlinkWheelListener);
587
+ }
588
+ }
589
+ /** Gets the value to set on the `readonly` attribute. */
590
+ _getReadonlyAttribute() {
591
+ if (this._isNativeSelect) {
592
+ return null;
593
+ }
594
+ if (this.readonly || (this.disabled && this.disabledInteractive)) {
595
+ return 'true';
596
+ }
597
+ return null;
598
+ }
599
+ /**
600
+ * This handler is only needed if DefaultValueAccessor is not applied.
601
+ * @internal
602
+ */
603
+ _compositionStart() {
604
+ this._composing = true;
605
+ }
606
+ /**
607
+ * This handler is only needed if DefaultValueAccessor is not applied.
608
+ * @internal
609
+ */
610
+ _compositionEnd(value) {
611
+ this._composing = false;
612
+ this._compositionMode && this._onChange(value);
613
+ }
614
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
615
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.15", type: CuteInput, isStandalone: true, selector: "\n input[cuteInput],\n textarea[cuteInput],\n select[cuteNativeControl],\n input[cuteNativeControl],\n textarea[cuteNativeControl],\n ", inputs: { placeholder: "placeholder", magnitude: "magnitude", type: "type", errorStateMatcher: "errorStateMatcher", userAriaDescribedBy: ["aria-describedby", "userAriaDescribedBy"], value: "value", readonly: "readonly", disabledInteractive: ["disabledInteractive", "disabledInteractive", booleanAttribute], plainText: ["plainText", "plainText", booleanAttribute] }, host: { listeners: { "focus": "_focusChanged(true)", "blur": "_focusChanged(false)", "input": "_onInput($event)", "compositionstart": "_compositionStart()", "compositionend": "_compositionEnd($any($event.target).value)" }, properties: { "class.form-control-plaintext": "plainText && _getReadonlyAttribute()==\"true\"", "class.form-range": "type==\"range\"", "class.form-control-color": "type==\"color\"", "class.cute-input-server": "_isServer", "class.cute-form-field-textarea-control": "_isInFormField && _isTextarea", "class.cute-form-field-input-control": "_isInFormField", "class.cute-input-disabled-interactive": "disabledInteractive", "class.cute-text-field__input": "_isInFormField", "class.cute-native-select-inline": "_isInlineSelect()", "id": "id", "disabled": "disabled && !disabledInteractive", "required": "required", "attr.name": "name || null", "attr.readonly": "_getReadonlyAttribute()", "attr.aria-disabled": "disabled && disabledInteractive ? \"true\" : null", "attr.aria-invalid": "(empty && required) ? null : errorState", "attr.aria-required": "required", "attr.id": "id", "class": "this.classList" }, classAttribute: "cute-input" }, providers: [
616
+ { provide: CuteFormFieldControl, useExisting: CuteInput },
617
+ ], exportAs: ["cuteInput"], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); }
618
+ }
619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteInput, decorators: [{
620
+ type: Directive,
621
+ args: [{
622
+ selector: `
623
+ input[cuteInput],
624
+ textarea[cuteInput],
625
+ select[cuteNativeControl],
626
+ input[cuteNativeControl],
627
+ textarea[cuteNativeControl],
628
+ `,
629
+ exportAs: 'cuteInput',
630
+ host: {
631
+ 'class': 'cute-input',
632
+ '[class.form-control-plaintext]': 'plainText && _getReadonlyAttribute()=="true"',
633
+ '[class.form-range]': 'type=="range"',
634
+ '[class.form-control-color]': 'type=="color"',
635
+ '[class.cute-input-server]': '_isServer',
636
+ '[class.cute-form-field-textarea-control]': '_isInFormField && _isTextarea',
637
+ '[class.cute-form-field-input-control]': '_isInFormField',
638
+ '[class.cute-input-disabled-interactive]': 'disabledInteractive',
639
+ '[class.cute-text-field__input]': '_isInFormField',
640
+ '[class.cute-native-select-inline]': '_isInlineSelect()',
641
+ // Native input properties that are overwritten by Angular inputs need to be synced with
642
+ // the native input element. Otherwise, property bindings for those don't work.
643
+ '[id]': 'id',
644
+ '[disabled]': 'disabled && !disabledInteractive',
645
+ '[required]': 'required',
646
+ '[attr.name]': 'name || null',
647
+ '[attr.readonly]': '_getReadonlyAttribute()',
648
+ '[attr.aria-disabled]': 'disabled && disabledInteractive ? "true" : null',
649
+ // Only mark the input as invalid for assistive technology if it has a value since the
650
+ // state usually overlaps with `aria-required` when the input is empty and can be redundant.
651
+ '[attr.aria-invalid]': '(empty && required) ? null : errorState',
652
+ '[attr.aria-required]': 'required',
653
+ // Native input properties that are overwritten by Angular inputs need to be synced with
654
+ // the native input element. Otherwise, property bindings for those don't work.
655
+ '[attr.id]': 'id',
656
+ '(focus)': '_focusChanged(true)',
657
+ '(blur)': '_focusChanged(false)',
658
+ '(input)': '_onInput($event)',
659
+ '(compositionstart)': '_compositionStart()',
660
+ '(compositionend)': '_compositionEnd($any($event.target).value)',
661
+ },
662
+ providers: [
663
+ { provide: CuteFormFieldControl, useExisting: CuteInput },
664
+ ],
665
+ standalone: true,
666
+ }]
667
+ }], ctorParameters: () => [], propDecorators: { classList: [{
668
+ type: HostBinding,
669
+ args: ["class"]
670
+ }], placeholder: [{
671
+ type: Input
672
+ }], magnitude: [{
673
+ type: Input
674
+ }], type: [{
675
+ type: Input
676
+ }], errorStateMatcher: [{
677
+ type: Input
678
+ }], userAriaDescribedBy: [{
679
+ type: Input,
680
+ args: ['aria-describedby']
681
+ }], value: [{
682
+ type: Input
683
+ }], readonly: [{
684
+ type: Input
685
+ }], disabledInteractive: [{
686
+ type: Input,
687
+ args: [{ transform: booleanAttribute }]
688
+ }], plainText: [{
689
+ type: Input,
690
+ args: [{ transform: booleanAttribute }]
691
+ }] } });
692
+
693
+ /**
694
+ * @license Apache-2.0
695
+ *
696
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
697
+ *
698
+ * You may not use this file except in compliance with the License
699
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
700
+ */
701
+ const TYPES = [
702
+ CuteInput,
703
+ CuteFormFieldModule,
704
+ ];
705
+ class CuteInputModule {
706
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
707
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: CuteInputModule, imports: [CommonModule, CuteInput,
708
+ CuteFormFieldModule], exports: [CuteInput,
709
+ CuteFormFieldModule] }); }
710
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteInputModule, imports: [CommonModule, CuteFormFieldModule, CuteFormFieldModule] }); }
711
+ }
712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteInputModule, decorators: [{
713
+ type: NgModule,
714
+ args: [{
715
+ imports: [CommonModule, ...TYPES],
716
+ exports: TYPES,
717
+ declarations: [],
718
+ }]
719
+ }] });
720
+
721
+ /**
722
+ * Generated bundle index. Do not edit.
723
+ */
724
+
725
+ export { CUTE_INPUT_CONFIG, CUTE_INPUT_VALUE_ACCESSOR, CUTE_INPUT_VALUE_FORMATTER, CUTE_INPUT_VALUE_PREDECESSOR, CuteInput, CuteInputModule };
726
+ //# sourceMappingURL=cute-widgets-base-input.mjs.map