@shival99/z-ui 1.0.1 → 1.0.2
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.
- package/assets/css/animations.css +207 -0
- package/assets/css/base.css +76 -0
- package/assets/css/tailwind.css +53 -0
- package/assets/css/themes/gray.css +73 -0
- package/assets/css/themes/green.css +75 -0
- package/assets/css/themes/hospital.css +79 -0
- package/assets/css/themes/neutral.css +73 -0
- package/assets/css/themes/orange.css +73 -0
- package/assets/css/themes/slate.css +73 -0
- package/assets/css/themes/stone.css +73 -0
- package/assets/css/themes/violet.css +73 -0
- package/assets/css/themes/zinc.css +73 -0
- package/assets/images/avatar.svg +6 -0
- package/assets/images/logo.svg +6 -0
- package/fesm2022/shival99-z-ui-components-z-accordion.mjs +148 -0
- package/fesm2022/shival99-z-ui-components-z-accordion.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-breadcrumb.mjs +74 -0
- package/fesm2022/shival99-z-ui-components-z-breadcrumb.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-button.mjs +155 -0
- package/fesm2022/shival99-z-ui-components-z-button.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs +2335 -0
- package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-checkbox.mjs +240 -0
- package/fesm2022/shival99-z-ui-components-z-checkbox.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-code.mjs +139 -0
- package/fesm2022/shival99-z-ui-components-z-code.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-drawer.mjs +664 -0
- package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs +55 -0
- package/fesm2022/shival99-z-ui-components-z-dropdown-menu.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-editor.mjs +411 -0
- package/fesm2022/shival99-z-ui-components-z-editor.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-filter.mjs +794 -0
- package/fesm2022/shival99-z-ui-components-z-filter.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-icon.mjs +451 -0
- package/fesm2022/shival99-z-ui-components-z-icon.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-input.mjs +804 -0
- package/fesm2022/shival99-z-ui-components-z-input.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-loading.mjs +105 -0
- package/fesm2022/shival99-z-ui-components-z-loading.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-menu.mjs +351 -0
- package/fesm2022/shival99-z-ui-components-z-menu.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-modal.mjs +722 -0
- package/fesm2022/shival99-z-ui-components-z-modal.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs +131 -0
- package/fesm2022/shival99-z-ui-components-z-pagination.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-popover.mjs +917 -0
- package/fesm2022/shival99-z-ui-components-z-popover.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-radio.mjs +154 -0
- package/fesm2022/shival99-z-ui-components-z-radio.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-select.mjs +998 -0
- package/fesm2022/shival99-z-ui-components-z-select.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-skeleton.mjs +139 -0
- package/fesm2022/shival99-z-ui-components-z-skeleton.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-switch.mjs +127 -0
- package/fesm2022/shival99-z-ui-components-z-switch.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-table.mjs +2628 -0
- package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-tabs.mjs +259 -0
- package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-timeline.mjs +335 -0
- package/fesm2022/shival99-z-ui-components-z-timeline.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-toast.mjs +93 -0
- package/fesm2022/shival99-z-ui-components-z-toast.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-tooltip.mjs +660 -0
- package/fesm2022/shival99-z-ui-components-z-tooltip.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-components-z-upload.mjs +504 -0
- package/fesm2022/shival99-z-ui-components-z-upload.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-i18n.mjs +258 -0
- package/fesm2022/shival99-z-ui-i18n.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-pipes.mjs +116 -0
- package/fesm2022/shival99-z-ui-pipes.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-providers.mjs +203 -0
- package/fesm2022/shival99-z-ui-providers.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-services.mjs +919 -0
- package/fesm2022/shival99-z-ui-services.mjs.map +1 -0
- package/fesm2022/shival99-z-ui-utils.mjs +591 -0
- package/fesm2022/shival99-z-ui-utils.mjs.map +1 -0
- package/fesm2022/z-ui.mjs +3 -19924
- package/fesm2022/z-ui.mjs.map +1 -1
- package/package.json +129 -1
- package/types/shival99-z-ui-components-z-accordion.d.ts +55 -0
- package/types/shival99-z-ui-components-z-breadcrumb.d.ts +36 -0
- package/types/shival99-z-ui-components-z-button.d.ts +41 -0
- package/types/shival99-z-ui-components-z-calendar.d.ts +300 -0
- package/types/shival99-z-ui-components-z-checkbox.d.ts +84 -0
- package/types/shival99-z-ui-components-z-code.d.ts +35 -0
- package/types/shival99-z-ui-components-z-drawer.d.ts +232 -0
- package/types/shival99-z-ui-components-z-dropdown-menu.d.ts +50 -0
- package/types/shival99-z-ui-components-z-editor.d.ts +115 -0
- package/types/shival99-z-ui-components-z-filter.d.ts +268 -0
- package/types/shival99-z-ui-components-z-icon.d.ts +291 -0
- package/types/shival99-z-ui-components-z-input.d.ts +188 -0
- package/types/shival99-z-ui-components-z-loading.d.ts +46 -0
- package/types/shival99-z-ui-components-z-menu.d.ts +116 -0
- package/types/shival99-z-ui-components-z-modal.d.ts +270 -0
- package/types/shival99-z-ui-components-z-pagination.d.ts +52 -0
- package/types/shival99-z-ui-components-z-popover.d.ts +134 -0
- package/types/shival99-z-ui-components-z-radio.d.ts +63 -0
- package/types/shival99-z-ui-components-z-select.d.ts +268 -0
- package/types/shival99-z-ui-components-z-skeleton.d.ts +55 -0
- package/types/shival99-z-ui-components-z-switch.d.ts +48 -0
- package/types/shival99-z-ui-components-z-table.d.ts +482 -0
- package/types/shival99-z-ui-components-z-tabs.d.ts +75 -0
- package/types/shival99-z-ui-components-z-timeline.d.ts +98 -0
- package/types/shival99-z-ui-components-z-toast.d.ts +61 -0
- package/types/shival99-z-ui-components-z-tooltip.d.ts +85 -0
- package/types/shival99-z-ui-components-z-upload.d.ts +136 -0
- package/types/shival99-z-ui-i18n.d.ts +50 -0
- package/types/shival99-z-ui-pipes.d.ts +36 -0
- package/types/shival99-z-ui-providers.d.ts +132 -0
- package/types/shival99-z-ui-services.d.ts +364 -0
- package/types/shival99-z-ui-utils.d.ts +145 -0
- package/types/z-ui.d.ts +3 -4977
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { input, output, viewChild, signal, computed, inject, Injector, DestroyRef, TemplateRef, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
+
import * as i1 from '@angular/forms';
|
|
6
|
+
import { NgControl, NgModel, PristineChangeEvent, TouchedChangeEvent, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
7
|
+
import { NgxMaskDirective, provideNgxMask } from 'ngx-mask';
|
|
8
|
+
import { Subject, merge, filter, debounceTime, isObservable, takeUntil, catchError, of, firstValueFrom } from 'rxjs';
|
|
9
|
+
import { cva } from 'class-variance-authority';
|
|
10
|
+
import { ZCacheService } from '@shival99/z-ui/services';
|
|
11
|
+
import { zTransform, zGenerateId, zMergeClasses } from '@shival99/z-ui/utils';
|
|
12
|
+
import { ZIconComponent } from '@shival99/z-ui/components/z-icon';
|
|
13
|
+
import { ZToastService } from '@shival99/z-ui/components/z-toast';
|
|
14
|
+
|
|
15
|
+
const ERROR_HANDLERS = [
|
|
16
|
+
['required', () => 'Trường này là bắt buộc'],
|
|
17
|
+
['min', e => `Giá trị tối thiểu là ${e['min'].min}`],
|
|
18
|
+
['max', e => `Giá trị tối đa là ${e['max'].max}`],
|
|
19
|
+
['minlength', e => `Tối thiểu ${e['minlength'].requiredLength} ký tự`],
|
|
20
|
+
['maxlength', e => `Tối đa ${e['maxlength'].requiredLength} ký tự`],
|
|
21
|
+
['email', () => 'Email không hợp lệ'],
|
|
22
|
+
['pattern', () => 'Định dạng không hợp lệ'],
|
|
23
|
+
];
|
|
24
|
+
const getDefaultErrorMessage = (errors) => ERROR_HANDLERS.find(([key]) => errors[key])?.[1](errors) ?? 'Giá trị không hợp lệ';
|
|
25
|
+
|
|
26
|
+
const zInputVariants = cva([
|
|
27
|
+
'flex w-full rounded-[6px] border border-input bg-white shadow-xs',
|
|
28
|
+
'transition-[border-color,box-shadow,background-color,color,opacity] duration-200',
|
|
29
|
+
'dark:bg-input/30 dark:border-input',
|
|
30
|
+
'file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground',
|
|
31
|
+
'outline-none',
|
|
32
|
+
'text-sm',
|
|
33
|
+
], {
|
|
34
|
+
variants: {
|
|
35
|
+
zSize: {
|
|
36
|
+
sm: 'h-8 px-2 gap-2 text-xs',
|
|
37
|
+
default: 'h-9 px-2 gap-2 text-sm',
|
|
38
|
+
lg: 'h-10 px-2 gap-2.5 text-sm',
|
|
39
|
+
},
|
|
40
|
+
zStatus: {
|
|
41
|
+
default: 'focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]',
|
|
42
|
+
error: 'border-destructive! ring-destructive/20 ring-[3px] focus-within:border-destructive! focus-within:ring-destructive/30',
|
|
43
|
+
disabled: 'opacity-50 cursor-not-allowed bg-muted! text-muted-foreground',
|
|
44
|
+
readonly: 'bg-muted/50! text-muted-foreground cursor-default',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
zSize: 'default',
|
|
49
|
+
zStatus: 'default',
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
const zTextareaVariants = cva([
|
|
53
|
+
'w-full rounded-[6px] border border-input bg-white shadow-xs transition-colors duration-200',
|
|
54
|
+
'dark:bg-input/30 dark:border-input',
|
|
55
|
+
'outline-none',
|
|
56
|
+
'text-sm',
|
|
57
|
+
], {
|
|
58
|
+
variants: {
|
|
59
|
+
zStatus: {
|
|
60
|
+
default: 'focus-within:border-ring focus-within:ring-ring/50 focus-within:ring-[3px]',
|
|
61
|
+
error: 'border-destructive! ring-destructive/20 ring-[3px] focus-within:border-destructive! focus-within:ring-destructive/30',
|
|
62
|
+
disabled: 'opacity-50 cursor-not-allowed bg-muted! text-muted-foreground',
|
|
63
|
+
readonly: 'bg-muted/50! text-muted-foreground cursor-default',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
defaultVariants: {
|
|
67
|
+
zStatus: 'default',
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
class ZInputComponent {
|
|
72
|
+
class = input('', ...(ngDevMode ? [{ debugName: "class" }] : []));
|
|
73
|
+
zType = input('text', ...(ngDevMode ? [{ debugName: "zType" }] : []));
|
|
74
|
+
zSize = input('default', ...(ngDevMode ? [{ debugName: "zSize" }] : []));
|
|
75
|
+
zLabel = input('', ...(ngDevMode ? [{ debugName: "zLabel" }] : []));
|
|
76
|
+
zLabelClass = input('', ...(ngDevMode ? [{ debugName: "zLabelClass" }] : []));
|
|
77
|
+
zPlaceholder = input('', ...(ngDevMode ? [{ debugName: "zPlaceholder" }] : []));
|
|
78
|
+
zRequired = input(false, { ...(ngDevMode ? { debugName: "zRequired" } : {}), transform: zTransform });
|
|
79
|
+
zDisabled = input(false, { ...(ngDevMode ? { debugName: "zDisabled" } : {}), transform: zTransform });
|
|
80
|
+
zReadonly = input(false, { ...(ngDevMode ? { debugName: "zReadonly" } : {}), transform: zTransform });
|
|
81
|
+
zPrefix = input('', ...(ngDevMode ? [{ debugName: "zPrefix" }] : []));
|
|
82
|
+
zSuffix = input('', ...(ngDevMode ? [{ debugName: "zSuffix" }] : []));
|
|
83
|
+
zMin = input(undefined, ...(ngDevMode ? [{ debugName: "zMin" }] : []));
|
|
84
|
+
zMax = input(undefined, ...(ngDevMode ? [{ debugName: "zMax" }] : []));
|
|
85
|
+
zStep = input(1, ...(ngDevMode ? [{ debugName: "zStep" }] : []));
|
|
86
|
+
zShowArrows = input(true, { ...(ngDevMode ? { debugName: "zShowArrows" } : {}), transform: zTransform });
|
|
87
|
+
zMask = input('', ...(ngDevMode ? [{ debugName: "zMask" }] : []));
|
|
88
|
+
zDecimalPlaces = input(undefined, ...(ngDevMode ? [{ debugName: "zDecimalPlaces" }] : []));
|
|
89
|
+
zAllowNegative = input(false, { ...(ngDevMode ? { debugName: "zAllowNegative" } : {}), transform: zTransform });
|
|
90
|
+
zThousandSeparator = input(' ', ...(ngDevMode ? [{ debugName: "zThousandSeparator" }] : []));
|
|
91
|
+
zDecimalMarker = input('.', ...(ngDevMode ? [{ debugName: "zDecimalMarker" }] : []));
|
|
92
|
+
zValidators = input([], ...(ngDevMode ? [{ debugName: "zValidators" }] : []));
|
|
93
|
+
zAsyncValidators = input([], ...(ngDevMode ? [{ debugName: "zAsyncValidators" }] : []));
|
|
94
|
+
zAsyncDebounce = input(300, ...(ngDevMode ? [{ debugName: "zAsyncDebounce" }] : []));
|
|
95
|
+
zAsyncValidateOn = input('change', ...(ngDevMode ? [{ debugName: "zAsyncValidateOn" }] : []));
|
|
96
|
+
zShowPasswordToggle = input(true, { ...(ngDevMode ? { debugName: "zShowPasswordToggle" } : {}), transform: zTransform });
|
|
97
|
+
zSearch = input(false, { ...(ngDevMode ? { debugName: "zSearch" } : {}), transform: zTransform });
|
|
98
|
+
zDebounce = input(300, ...(ngDevMode ? [{ debugName: "zDebounce" }] : []));
|
|
99
|
+
zAutofocus = input(false, { ...(ngDevMode ? { debugName: "zAutofocus" } : {}), transform: zTransform });
|
|
100
|
+
zAutoComplete = input('off', ...(ngDevMode ? [{ debugName: "zAutoComplete" }] : []));
|
|
101
|
+
zAllowClear = input(false, { ...(ngDevMode ? { debugName: "zAllowClear" } : {}), transform: zTransform });
|
|
102
|
+
zAutoSizeContent = input(false, { ...(ngDevMode ? { debugName: "zAutoSizeContent" } : {}), transform: zTransform });
|
|
103
|
+
zRows = input(3, ...(ngDevMode ? [{ debugName: "zRows" }] : []));
|
|
104
|
+
zResize = input(true, { ...(ngDevMode ? { debugName: "zResize" } : {}), transform: zTransform });
|
|
105
|
+
zMaxLength = input(undefined, ...(ngDevMode ? [{ debugName: "zMaxLength" }] : []));
|
|
106
|
+
zAutoSuggest = input(undefined, ...(ngDevMode ? [{ debugName: "zAutoSuggest" }] : []));
|
|
107
|
+
zOnSearch = output();
|
|
108
|
+
zOnChange = output();
|
|
109
|
+
zControl = output();
|
|
110
|
+
inputRef = viewChild('inputEl', ...(ngDevMode ? [{ debugName: "inputRef" }] : []));
|
|
111
|
+
inputId = zGenerateId('z-input');
|
|
112
|
+
passwordVisible = signal(false, ...(ngDevMode ? [{ debugName: "passwordVisible" }] : []));
|
|
113
|
+
isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
|
|
114
|
+
suggestHistory = signal([], ...(ngDevMode ? [{ debugName: "suggestHistory" }] : []));
|
|
115
|
+
suggestActiveIndex = signal(-1, ...(ngDevMode ? [{ debugName: "suggestActiveIndex" }] : []));
|
|
116
|
+
showSuggestPopover = signal(false, ...(ngDevMode ? [{ debugName: "showSuggestPopover" }] : []));
|
|
117
|
+
filteredSuggestHistory = computed(() => {
|
|
118
|
+
const history = this.suggestHistory();
|
|
119
|
+
const currentValue = String(this._value() ?? '')
|
|
120
|
+
.toLowerCase()
|
|
121
|
+
.trim();
|
|
122
|
+
if (!currentValue) {
|
|
123
|
+
return history;
|
|
124
|
+
}
|
|
125
|
+
const matching = [];
|
|
126
|
+
const nonMatching = [];
|
|
127
|
+
for (const item of history) {
|
|
128
|
+
const target = item.toLowerCase().includes(currentValue) ? matching : nonMatching;
|
|
129
|
+
target.push(item);
|
|
130
|
+
}
|
|
131
|
+
return [...matching, ...nonMatching];
|
|
132
|
+
}, ...(ngDevMode ? [{ debugName: "filteredSuggestHistory" }] : []));
|
|
133
|
+
_value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : []));
|
|
134
|
+
_touched = signal(false, ...(ngDevMode ? [{ debugName: "_touched" }] : []));
|
|
135
|
+
_disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
136
|
+
_dirty = signal(false, ...(ngDevMode ? [{ debugName: "_dirty" }] : []));
|
|
137
|
+
_formControl = signal(null, ...(ngDevMode ? [{ debugName: "_formControl" }] : []));
|
|
138
|
+
_formStateVersion = signal(0, ...(ngDevMode ? [{ debugName: "_formStateVersion" }] : []));
|
|
139
|
+
_isNgModel = signal(false, ...(ngDevMode ? [{ debugName: "_isNgModel" }] : []));
|
|
140
|
+
_injector = inject(Injector);
|
|
141
|
+
_destroyRef = inject(DestroyRef);
|
|
142
|
+
_toastService = inject(ZToastService);
|
|
143
|
+
_searchSubject = new Subject();
|
|
144
|
+
_changeSubject = new Subject();
|
|
145
|
+
_asyncValidationSubject = new Subject();
|
|
146
|
+
isValidating = signal(false, ...(ngDevMode ? [{ debugName: "isValidating" }] : []));
|
|
147
|
+
_asyncErrors = signal(new Map(), ...(ngDevMode ? [{ debugName: "_asyncErrors" }] : []));
|
|
148
|
+
_asyncCancelSubject = new Subject();
|
|
149
|
+
_asyncValidationAbortController = null;
|
|
150
|
+
_onChange = () => void 0;
|
|
151
|
+
_onTouched = () => void 0;
|
|
152
|
+
_ngControl = null;
|
|
153
|
+
_arrowInterval = null;
|
|
154
|
+
isDisabled = computed(() => this._disabled() || this.zDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
|
|
155
|
+
isPasswordType = computed(() => this.zType() === 'password', ...(ngDevMode ? [{ debugName: "isPasswordType" }] : []));
|
|
156
|
+
isColorType = computed(() => this.zType() === 'color', ...(ngDevMode ? [{ debugName: "isColorType" }] : []));
|
|
157
|
+
colorCopied = signal(false, ...(ngDevMode ? [{ debugName: "colorCopied" }] : []));
|
|
158
|
+
isPrefixTemplate = computed(() => this.zPrefix() instanceof TemplateRef, ...(ngDevMode ? [{ debugName: "isPrefixTemplate" }] : []));
|
|
159
|
+
isSuffixTemplate = computed(() => this.zSuffix() instanceof TemplateRef, ...(ngDevMode ? [{ debugName: "isSuffixTemplate" }] : []));
|
|
160
|
+
isTextarea = computed(() => this.zType() === 'textarea', ...(ngDevMode ? [{ debugName: "isTextarea" }] : []));
|
|
161
|
+
effectiveType = computed(() => {
|
|
162
|
+
if (this.zType() === 'password' && this.passwordVisible()) {
|
|
163
|
+
return 'text';
|
|
164
|
+
}
|
|
165
|
+
if (this.zType() === 'number' && this.effectiveMask()) {
|
|
166
|
+
return 'text';
|
|
167
|
+
}
|
|
168
|
+
return this.zType();
|
|
169
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveType" }] : []));
|
|
170
|
+
showArrows = computed(() => this.zType() === 'number' && this.zShowArrows(), ...(ngDevMode ? [{ debugName: "showArrows" }] : []));
|
|
171
|
+
effectiveMask = computed(() => {
|
|
172
|
+
if (this.zMask()) {
|
|
173
|
+
return this.zMask();
|
|
174
|
+
}
|
|
175
|
+
if (this.zType() === 'number') {
|
|
176
|
+
const decimalPlaces = this.zDecimalPlaces();
|
|
177
|
+
if (decimalPlaces !== undefined) {
|
|
178
|
+
return `separator.${decimalPlaces}`;
|
|
179
|
+
}
|
|
180
|
+
return 'separator.0';
|
|
181
|
+
}
|
|
182
|
+
return '';
|
|
183
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveMask" }] : []));
|
|
184
|
+
effectiveDecimalMarker = computed(() => {
|
|
185
|
+
const thousandSep = this.zThousandSeparator();
|
|
186
|
+
const decimalMark = this.zDecimalMarker();
|
|
187
|
+
if (thousandSep === '.') {
|
|
188
|
+
return ',';
|
|
189
|
+
}
|
|
190
|
+
if (thousandSep === ',') {
|
|
191
|
+
return '.';
|
|
192
|
+
}
|
|
193
|
+
return decimalMark;
|
|
194
|
+
}, ...(ngDevMode ? [{ debugName: "effectiveDecimalMarker" }] : []));
|
|
195
|
+
displayValue = computed(() => {
|
|
196
|
+
const val = this._value();
|
|
197
|
+
if (val === null || val === undefined) {
|
|
198
|
+
return '';
|
|
199
|
+
}
|
|
200
|
+
return String(val);
|
|
201
|
+
}, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
|
|
202
|
+
_shouldShowValidation = computed(() => {
|
|
203
|
+
const control = this._formControl();
|
|
204
|
+
this._formStateVersion();
|
|
205
|
+
if (this._isNgModel()) {
|
|
206
|
+
return this._dirty() || this._touched();
|
|
207
|
+
}
|
|
208
|
+
if (control) {
|
|
209
|
+
return control.dirty;
|
|
210
|
+
}
|
|
211
|
+
return this._dirty() || this._touched();
|
|
212
|
+
}, ...(ngDevMode ? [{ debugName: "_shouldShowValidation" }] : []));
|
|
213
|
+
hasError = computed(() => {
|
|
214
|
+
const asyncErrors = this._asyncErrors();
|
|
215
|
+
if (asyncErrors.size > 0 && this._shouldShowValidation()) {
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
const customErrors = this._getValidationErrors();
|
|
219
|
+
if (customErrors.length > 0) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
const control = this._formControl();
|
|
223
|
+
this._formStateVersion();
|
|
224
|
+
if (!control) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return control.invalid && this._shouldShowValidation();
|
|
228
|
+
}, ...(ngDevMode ? [{ debugName: "hasError" }] : []));
|
|
229
|
+
showError = computed(() => this.hasError(), ...(ngDevMode ? [{ debugName: "showError" }] : []));
|
|
230
|
+
errorMessage = computed(() => {
|
|
231
|
+
const asyncErrors = this._asyncErrors();
|
|
232
|
+
if (asyncErrors.size > 0) {
|
|
233
|
+
return asyncErrors.values().next().value;
|
|
234
|
+
}
|
|
235
|
+
const customErrors = this._getValidationErrors();
|
|
236
|
+
if (customErrors.length > 0) {
|
|
237
|
+
return customErrors[0];
|
|
238
|
+
}
|
|
239
|
+
const control = this._formControl();
|
|
240
|
+
const errors = control?.errors;
|
|
241
|
+
if (!errors) {
|
|
242
|
+
return '';
|
|
243
|
+
}
|
|
244
|
+
const validators = this.zValidators();
|
|
245
|
+
for (const validator of validators) {
|
|
246
|
+
if (errors[validator.error]) {
|
|
247
|
+
return validator.message;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return getDefaultErrorMessage(errors);
|
|
251
|
+
}, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
252
|
+
hasPrefix = computed(() => this.zSearch() || !!this.zPrefix(), ...(ngDevMode ? [{ debugName: "hasPrefix" }] : []));
|
|
253
|
+
hasSuffix = computed(() => !!this.zSuffix(), ...(ngDevMode ? [{ debugName: "hasSuffix" }] : []));
|
|
254
|
+
isTextPrefix = computed(() => {
|
|
255
|
+
const prefix = this.zPrefix();
|
|
256
|
+
return typeof prefix === 'string' && prefix.length > 0;
|
|
257
|
+
}, ...(ngDevMode ? [{ debugName: "isTextPrefix" }] : []));
|
|
258
|
+
isTextSuffix = computed(() => {
|
|
259
|
+
const suffix = this.zSuffix();
|
|
260
|
+
return typeof suffix === 'string' && suffix.length > 0;
|
|
261
|
+
}, ...(ngDevMode ? [{ debugName: "isTextSuffix" }] : []));
|
|
262
|
+
currentStatus = computed(() => {
|
|
263
|
+
if (this.isDisabled()) {
|
|
264
|
+
return 'disabled';
|
|
265
|
+
}
|
|
266
|
+
if (this.zReadonly()) {
|
|
267
|
+
return 'readonly';
|
|
268
|
+
}
|
|
269
|
+
if (this.hasError()) {
|
|
270
|
+
return 'error';
|
|
271
|
+
}
|
|
272
|
+
return 'default';
|
|
273
|
+
}, ...(ngDevMode ? [{ debugName: "currentStatus" }] : []));
|
|
274
|
+
inputClasses = computed(() => zMergeClasses(zInputVariants({
|
|
275
|
+
zSize: this.zSize(),
|
|
276
|
+
zStatus: this.currentStatus(),
|
|
277
|
+
}), this.class()), ...(ngDevMode ? [{ debugName: "inputClasses" }] : []));
|
|
278
|
+
textareaClasses = computed(() => zMergeClasses(zTextareaVariants({
|
|
279
|
+
zStatus: this.currentStatus(),
|
|
280
|
+
}), this.class()), ...(ngDevMode ? [{ debugName: "textareaClasses" }] : []));
|
|
281
|
+
hasAutoSuggest = computed(() => {
|
|
282
|
+
const key = this.zAutoSuggest();
|
|
283
|
+
return key !== undefined && key.length > 0;
|
|
284
|
+
}, ...(ngDevMode ? [{ debugName: "hasAutoSuggest" }] : []));
|
|
285
|
+
hasValue = computed(() => {
|
|
286
|
+
const value = this._value();
|
|
287
|
+
return value !== null && value !== undefined && value !== '';
|
|
288
|
+
}, ...(ngDevMode ? [{ debugName: "hasValue" }] : []));
|
|
289
|
+
showClearButton = computed(() => this.zAllowClear() && this.hasValue() && !this.isDisabled() && !this.zReadonly(), ...(ngDevMode ? [{ debugName: "showClearButton" }] : []));
|
|
290
|
+
ngOnInit() {
|
|
291
|
+
void Promise.resolve().then(() => {
|
|
292
|
+
try {
|
|
293
|
+
this._ngControl = this._injector.get(NgControl, null);
|
|
294
|
+
this._isNgModel.set(this._ngControl instanceof NgModel);
|
|
295
|
+
if (this._ngControl?.control) {
|
|
296
|
+
const { control } = this._ngControl;
|
|
297
|
+
this._formControl.set(control);
|
|
298
|
+
merge(control.statusChanges, control.valueChanges, control.events.pipe(filter(event => event instanceof PristineChangeEvent || event instanceof TouchedChangeEvent)))
|
|
299
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
300
|
+
.subscribe(() => {
|
|
301
|
+
this._formStateVersion.update(v => v + 1);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
this._ngControl = null;
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
this._searchSubject.pipe(debounceTime(this.zDebounce()), takeUntilDestroyed(this._destroyRef)).subscribe(value => {
|
|
310
|
+
this.zOnSearch.emit(value);
|
|
311
|
+
});
|
|
312
|
+
this._changeSubject.pipe(debounceTime(this.zDebounce()), takeUntilDestroyed(this._destroyRef)).subscribe(value => {
|
|
313
|
+
this.zOnChange.emit(value);
|
|
314
|
+
});
|
|
315
|
+
const asyncValidators = this.zAsyncValidators();
|
|
316
|
+
if (asyncValidators.length > 0) {
|
|
317
|
+
const debounceMs = this.zAsyncDebounce() || 300;
|
|
318
|
+
this._asyncValidationSubject
|
|
319
|
+
.pipe(debounceTime(debounceMs), takeUntilDestroyed(this._destroyRef))
|
|
320
|
+
.subscribe(value => {
|
|
321
|
+
void this._runAsyncValidation(value);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
setTimeout(() => this._emitControl());
|
|
325
|
+
if (this.zAutofocus()) {
|
|
326
|
+
setTimeout(() => {
|
|
327
|
+
this.focus();
|
|
328
|
+
}, 20);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async _runAsyncValidation(value) {
|
|
332
|
+
const asyncValidators = this.zAsyncValidators();
|
|
333
|
+
if (asyncValidators.length === 0) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if ((value === null || value === undefined || value === '') && !this.zRequired()) {
|
|
337
|
+
this._asyncErrors.set(new Map());
|
|
338
|
+
this.isValidating.set(false);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
this._cancelAsyncValidation();
|
|
342
|
+
this._asyncValidationAbortController = new AbortController();
|
|
343
|
+
const { signal } = this._asyncValidationAbortController;
|
|
344
|
+
this.isValidating.set(true);
|
|
345
|
+
const errors = new Map();
|
|
346
|
+
try {
|
|
347
|
+
const validationPromises = asyncValidators.map(async (validator) => {
|
|
348
|
+
if (signal.aborted) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
const result = validator.validate(value);
|
|
353
|
+
if (!isObservable(result)) {
|
|
354
|
+
const isValid = await result;
|
|
355
|
+
if (signal.aborted) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
return { validator, isValid };
|
|
359
|
+
}
|
|
360
|
+
const safeResult$ = result.pipe(takeUntil(this._asyncCancelSubject), catchError(err => {
|
|
361
|
+
console.error(`Async validation error for ${validator.error}:`, err);
|
|
362
|
+
return of(false);
|
|
363
|
+
}));
|
|
364
|
+
const isValid = await firstValueFrom(safeResult$);
|
|
365
|
+
if (signal.aborted) {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
return { validator, isValid };
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
if (!signal.aborted) {
|
|
372
|
+
console.error(`Async validation error for ${validator.error}:`, error);
|
|
373
|
+
return {
|
|
374
|
+
validator,
|
|
375
|
+
isValid: false,
|
|
376
|
+
error: true,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
const results = await Promise.all(validationPromises);
|
|
383
|
+
if (signal.aborted) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
for (const result of results) {
|
|
387
|
+
if (result && !result.isValid) {
|
|
388
|
+
errors.set(result.validator.error, result.validator.message);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
this._asyncErrors.set(errors);
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
if (!signal.aborted) {
|
|
395
|
+
console.error('Async validation error:', error);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
finally {
|
|
399
|
+
if (!signal.aborted) {
|
|
400
|
+
this.isValidating.set(false);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
_cancelAsyncValidation() {
|
|
405
|
+
if (this._asyncValidationAbortController) {
|
|
406
|
+
this._asyncValidationAbortController.abort();
|
|
407
|
+
this._asyncValidationAbortController = null;
|
|
408
|
+
}
|
|
409
|
+
this._asyncCancelSubject.next();
|
|
410
|
+
}
|
|
411
|
+
writeValue(value) {
|
|
412
|
+
this._value.set(value);
|
|
413
|
+
}
|
|
414
|
+
registerOnChange(fn) {
|
|
415
|
+
this._onChange = fn;
|
|
416
|
+
}
|
|
417
|
+
registerOnTouched(fn) {
|
|
418
|
+
this._onTouched = fn;
|
|
419
|
+
}
|
|
420
|
+
setDisabledState(isDisabled) {
|
|
421
|
+
this._disabled.set(isDisabled);
|
|
422
|
+
}
|
|
423
|
+
focus() {
|
|
424
|
+
this.inputRef()?.nativeElement.focus();
|
|
425
|
+
}
|
|
426
|
+
blur() {
|
|
427
|
+
this.inputRef()?.nativeElement.blur();
|
|
428
|
+
}
|
|
429
|
+
markAsTouched() {
|
|
430
|
+
this._touched.set(true);
|
|
431
|
+
this._onTouched();
|
|
432
|
+
}
|
|
433
|
+
markAsUntouched() {
|
|
434
|
+
this._touched.set(false);
|
|
435
|
+
}
|
|
436
|
+
markAsDirty() {
|
|
437
|
+
this._dirty.set(true);
|
|
438
|
+
}
|
|
439
|
+
markAsPristine() {
|
|
440
|
+
this._dirty.set(false);
|
|
441
|
+
}
|
|
442
|
+
validate() {
|
|
443
|
+
this._touched.set(true);
|
|
444
|
+
this._dirty.set(true);
|
|
445
|
+
this._onTouched();
|
|
446
|
+
if (this._ngControl?.control) {
|
|
447
|
+
this._ngControl.control.markAsDirty();
|
|
448
|
+
this._ngControl.control.markAsTouched();
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
reset() {
|
|
452
|
+
this._cancelAsyncValidation();
|
|
453
|
+
this.isValidating.set(false);
|
|
454
|
+
this._asyncErrors.set(new Map());
|
|
455
|
+
this._value.set(null);
|
|
456
|
+
this._touched.set(false);
|
|
457
|
+
this._dirty.set(false);
|
|
458
|
+
this._onChange(null);
|
|
459
|
+
if (this._ngControl?.control) {
|
|
460
|
+
this._ngControl.control.markAsPristine();
|
|
461
|
+
this._ngControl.control.markAsUntouched();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
setValue(value) {
|
|
465
|
+
this._value.set(value);
|
|
466
|
+
this._onChange(value);
|
|
467
|
+
}
|
|
468
|
+
getValue() {
|
|
469
|
+
return this._value();
|
|
470
|
+
}
|
|
471
|
+
clearValue(event) {
|
|
472
|
+
event.stopPropagation();
|
|
473
|
+
this._value.set(null);
|
|
474
|
+
this._dirty.set(true);
|
|
475
|
+
this._onChange(null);
|
|
476
|
+
this._changeSubject.next(null);
|
|
477
|
+
if (this.zSearch()) {
|
|
478
|
+
this._searchSubject.next(null);
|
|
479
|
+
}
|
|
480
|
+
this.focus();
|
|
481
|
+
}
|
|
482
|
+
_emitControl() {
|
|
483
|
+
this.zControl.emit({
|
|
484
|
+
validate: () => this.validate(),
|
|
485
|
+
reset: () => this.reset(),
|
|
486
|
+
focus: () => this.focus(),
|
|
487
|
+
blur: () => this.blur(),
|
|
488
|
+
markAsTouched: () => this.markAsTouched(),
|
|
489
|
+
markAsUntouched: () => this.markAsUntouched(),
|
|
490
|
+
markAsDirty: () => this.markAsDirty(),
|
|
491
|
+
markAsPristine: () => this.markAsPristine(),
|
|
492
|
+
setValue: (value) => this.setValue(value),
|
|
493
|
+
hasError: this.hasError,
|
|
494
|
+
isValidating: this.isValidating,
|
|
495
|
+
value: this._value.asReadonly(),
|
|
496
|
+
errorMessage: this.errorMessage,
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
onInput(event) {
|
|
500
|
+
const { value: rawValue } = event.target;
|
|
501
|
+
let value = rawValue;
|
|
502
|
+
if (this.zType() === 'number') {
|
|
503
|
+
const cleanValue = this._cleanNumberValue(value);
|
|
504
|
+
value = cleanValue === '' ? null : parseFloat(cleanValue);
|
|
505
|
+
if (value !== null && isNaN(value)) {
|
|
506
|
+
value = null;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
this._value.set(value);
|
|
510
|
+
this._dirty.set(true);
|
|
511
|
+
this._onChange(value);
|
|
512
|
+
if (this.zSearch()) {
|
|
513
|
+
this._searchSubject.next(value);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
onModelChange(rawValue) {
|
|
517
|
+
let value = rawValue;
|
|
518
|
+
if (this.zType() === 'number' && typeof rawValue === 'string') {
|
|
519
|
+
const cleanValue = this._cleanNumberValue(rawValue);
|
|
520
|
+
value = cleanValue === '' ? null : parseFloat(cleanValue);
|
|
521
|
+
if (value !== null && isNaN(value)) {
|
|
522
|
+
value = null;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
this._value.set(value);
|
|
526
|
+
this._dirty.set(true);
|
|
527
|
+
this._onChange(value);
|
|
528
|
+
// Emit debounced change event
|
|
529
|
+
this._changeSubject.next(value);
|
|
530
|
+
if (this.zSearch()) {
|
|
531
|
+
this._searchSubject.next(value);
|
|
532
|
+
}
|
|
533
|
+
if (this.zAsyncValidators().length > 0 && this.zAsyncValidateOn() === 'change') {
|
|
534
|
+
this._asyncValidationSubject.next(value);
|
|
535
|
+
}
|
|
536
|
+
if (this.hasAutoSuggest() && this.isFocused()) {
|
|
537
|
+
this._loadSuggestHistory();
|
|
538
|
+
if (this.suggestHistory().length > 0) {
|
|
539
|
+
this._showSuggestPopover();
|
|
540
|
+
this.suggestActiveIndex.set(-1);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
onBlur() {
|
|
545
|
+
if (this._dirty()) {
|
|
546
|
+
this._touched.set(true);
|
|
547
|
+
}
|
|
548
|
+
this._onTouched();
|
|
549
|
+
this.isFocused.set(false);
|
|
550
|
+
if (this.zAsyncValidators().length > 0 && this.zAsyncValidateOn() === 'blur') {
|
|
551
|
+
this._asyncValidationSubject.next(this._value());
|
|
552
|
+
}
|
|
553
|
+
const el = this.inputRef()?.nativeElement;
|
|
554
|
+
if (el) {
|
|
555
|
+
if (el.value && !el.classList.contains('z-input-auto-fill')) {
|
|
556
|
+
el.classList.add('z-input-auto-fill');
|
|
557
|
+
const currentValue = el.value;
|
|
558
|
+
el.value = '';
|
|
559
|
+
el.value = currentValue;
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
onFocus() {
|
|
564
|
+
this.isFocused.set(true);
|
|
565
|
+
this._loadSuggestHistory();
|
|
566
|
+
if (this.hasAutoSuggest() && this.suggestHistory().length > 0) {
|
|
567
|
+
this._showSuggestPopover();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
onKeydown(event) {
|
|
571
|
+
if (this.zType() !== 'number') {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (event.key === 'ArrowUp') {
|
|
575
|
+
event.preventDefault();
|
|
576
|
+
this._incrementValue(1);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (event.key === 'ArrowDown') {
|
|
580
|
+
event.preventDefault();
|
|
581
|
+
this._incrementValue(-1);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
onSuggestKeydown(event) {
|
|
585
|
+
if (event.key === 'Enter' && this.hasAutoSuggest()) {
|
|
586
|
+
const activeIndex = this.suggestActiveIndex();
|
|
587
|
+
const history = this.filteredSuggestHistory();
|
|
588
|
+
if (this.showSuggestPopover() && activeIndex >= 0 && activeIndex < history.length) {
|
|
589
|
+
event.preventDefault();
|
|
590
|
+
this.selectSuggestItem(history[activeIndex]);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
const currentValue = String(this._value() ?? '').trim();
|
|
594
|
+
if (currentValue) {
|
|
595
|
+
this.saveToSuggestHistory(currentValue);
|
|
596
|
+
this._hideSuggestPopover();
|
|
597
|
+
this.suggestActiveIndex.set(-1);
|
|
598
|
+
if (this.zSearch()) {
|
|
599
|
+
this.zOnSearch.emit(currentValue);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (!this.hasAutoSuggest() || !this.showSuggestPopover()) {
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const history = this.filteredSuggestHistory();
|
|
608
|
+
if (history.length === 0) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
if (event.key === 'ArrowDown') {
|
|
612
|
+
event.preventDefault();
|
|
613
|
+
const currentIndex = this.suggestActiveIndex();
|
|
614
|
+
const newIndex = currentIndex < history.length - 1 ? currentIndex + 1 : 0;
|
|
615
|
+
this.suggestActiveIndex.set(newIndex);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (event.key === 'ArrowUp') {
|
|
619
|
+
event.preventDefault();
|
|
620
|
+
const currentIndex = this.suggestActiveIndex();
|
|
621
|
+
const newIndex = currentIndex > 0 ? currentIndex - 1 : history.length - 1;
|
|
622
|
+
this.suggestActiveIndex.set(newIndex);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (event.key === 'Escape') {
|
|
626
|
+
this._hideSuggestPopover();
|
|
627
|
+
this.suggestActiveIndex.set(-1);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
selectSuggestItem(item) {
|
|
631
|
+
this._value.set(item);
|
|
632
|
+
this._dirty.set(true);
|
|
633
|
+
this._onChange(item);
|
|
634
|
+
this._hideSuggestPopover();
|
|
635
|
+
this.suggestActiveIndex.set(-1);
|
|
636
|
+
this.saveToSuggestHistory(item);
|
|
637
|
+
if (this.zSearch()) {
|
|
638
|
+
this._searchSubject.next(item);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
closeSuggestPopover() {
|
|
642
|
+
setTimeout(() => {
|
|
643
|
+
this._hideSuggestPopover();
|
|
644
|
+
this.suggestActiveIndex.set(-1);
|
|
645
|
+
}, 150);
|
|
646
|
+
}
|
|
647
|
+
_showSuggestPopover() {
|
|
648
|
+
this.showSuggestPopover.set(true);
|
|
649
|
+
}
|
|
650
|
+
_hideSuggestPopover() {
|
|
651
|
+
this.showSuggestPopover.set(false);
|
|
652
|
+
}
|
|
653
|
+
saveToSuggestHistory(value) {
|
|
654
|
+
const key = this.zAutoSuggest();
|
|
655
|
+
if (!key || !value || value.trim() === '') {
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
const cacheKey = `autosuggest-${key}`;
|
|
659
|
+
let history = ZCacheService.get(cacheKey, []) ?? [];
|
|
660
|
+
const trimmedValue = value.trim();
|
|
661
|
+
history = history.filter(item => item !== trimmedValue);
|
|
662
|
+
history.unshift(trimmedValue);
|
|
663
|
+
if (history.length > 5) {
|
|
664
|
+
history = history.slice(0, 5);
|
|
665
|
+
}
|
|
666
|
+
ZCacheService.set(cacheKey, history);
|
|
667
|
+
this.suggestHistory.set(history);
|
|
668
|
+
}
|
|
669
|
+
_loadSuggestHistory() {
|
|
670
|
+
const key = this.zAutoSuggest();
|
|
671
|
+
if (!key) {
|
|
672
|
+
this.suggestHistory.set([]);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
const cacheKey = `autosuggest-${key}`;
|
|
676
|
+
const history = ZCacheService.get(cacheKey, []) ?? [];
|
|
677
|
+
this.suggestHistory.set(history);
|
|
678
|
+
}
|
|
679
|
+
onArrowMouseDown(event, direction) {
|
|
680
|
+
event.preventDefault();
|
|
681
|
+
const multiplier = direction === 'up' ? 1 : -1;
|
|
682
|
+
this._incrementValue(multiplier);
|
|
683
|
+
this._arrowInterval = setInterval(() => {
|
|
684
|
+
this._incrementValue(multiplier);
|
|
685
|
+
}, 100);
|
|
686
|
+
}
|
|
687
|
+
onArrowMouseUp() {
|
|
688
|
+
if (this._arrowInterval) {
|
|
689
|
+
clearInterval(this._arrowInterval);
|
|
690
|
+
this._arrowInterval = null;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
togglePasswordVisibility() {
|
|
694
|
+
this.passwordVisible.update(v => !v);
|
|
695
|
+
}
|
|
696
|
+
copyColorToClipboard() {
|
|
697
|
+
const colorValue = String(this._value() || '#000000').toUpperCase();
|
|
698
|
+
void navigator.clipboard.writeText(colorValue).then(() => {
|
|
699
|
+
this.colorCopied.set(true);
|
|
700
|
+
this._toastService.success(`Copied ${colorValue}`);
|
|
701
|
+
setTimeout(() => {
|
|
702
|
+
this.colorCopied.set(false);
|
|
703
|
+
}, 1500);
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
_incrementValue(multiplier) {
|
|
707
|
+
const currentValue = this._value();
|
|
708
|
+
const numValue = typeof currentValue === 'number' ? currentValue : parseFloat(String(currentValue)) || 0;
|
|
709
|
+
const step = this.zStep();
|
|
710
|
+
let newValue = numValue + step * multiplier;
|
|
711
|
+
const min = this.zMin();
|
|
712
|
+
const max = this.zMax();
|
|
713
|
+
if (min !== undefined && newValue < min) {
|
|
714
|
+
newValue = min;
|
|
715
|
+
}
|
|
716
|
+
if (max !== undefined && newValue > max) {
|
|
717
|
+
newValue = max;
|
|
718
|
+
}
|
|
719
|
+
if (!this.zAllowNegative() && newValue < 0) {
|
|
720
|
+
newValue = 0;
|
|
721
|
+
}
|
|
722
|
+
this._value.set(newValue);
|
|
723
|
+
this._onChange(newValue);
|
|
724
|
+
}
|
|
725
|
+
_cleanNumberValue(value) {
|
|
726
|
+
const thousandSep = this.zThousandSeparator();
|
|
727
|
+
let cleaned = value.replace(new RegExp(`\\${thousandSep}`, 'g'), '');
|
|
728
|
+
const decimalMarker = this.zDecimalMarker();
|
|
729
|
+
if (typeof decimalMarker === 'string' && decimalMarker !== '.') {
|
|
730
|
+
cleaned = cleaned.replace(decimalMarker, '.');
|
|
731
|
+
}
|
|
732
|
+
return cleaned;
|
|
733
|
+
}
|
|
734
|
+
_getValidationErrors() {
|
|
735
|
+
const errors = [];
|
|
736
|
+
const value = this._value();
|
|
737
|
+
const validators = this.zValidators();
|
|
738
|
+
if (!this._shouldShowValidation()) {
|
|
739
|
+
return errors;
|
|
740
|
+
}
|
|
741
|
+
for (const validator of validators) {
|
|
742
|
+
if (validator.validate && !validator.validate(value)) {
|
|
743
|
+
errors.push(validator.message);
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
if (validator.error === 'required' && this.zRequired()) {
|
|
747
|
+
if (value === null || value === undefined || value === '') {
|
|
748
|
+
errors.push(validator.message);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (validator.error === 'number' && value !== null && value !== '') {
|
|
752
|
+
const numValue = typeof value === 'number' ? value : parseFloat(String(value));
|
|
753
|
+
if (isNaN(numValue)) {
|
|
754
|
+
errors.push(validator.message);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (validator.error === 'min' && validator.min !== undefined && value !== null && value !== '') {
|
|
758
|
+
const numValue = typeof value === 'number' ? value : parseFloat(String(value));
|
|
759
|
+
if (!isNaN(numValue) && numValue < validator.min) {
|
|
760
|
+
errors.push(validator.message);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
if (validator.error === 'max' && validator.max !== undefined && value !== null && value !== '') {
|
|
764
|
+
const numValue = typeof value === 'number' ? value : parseFloat(String(value));
|
|
765
|
+
if (!isNaN(numValue) && numValue > validator.max) {
|
|
766
|
+
errors.push(validator.message);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (validator.error === 'pattern' && validator.pattern && value !== null && value !== '') {
|
|
770
|
+
if (!validator.pattern.test(String(value))) {
|
|
771
|
+
errors.push(validator.message);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return errors;
|
|
776
|
+
}
|
|
777
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
778
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ZInputComponent, isStandalone: true, selector: "z-input", inputs: { class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, zType: { classPropertyName: "zType", publicName: "zType", isSignal: true, isRequired: false, transformFunction: null }, zSize: { classPropertyName: "zSize", publicName: "zSize", isSignal: true, isRequired: false, transformFunction: null }, zLabel: { classPropertyName: "zLabel", publicName: "zLabel", isSignal: true, isRequired: false, transformFunction: null }, zLabelClass: { classPropertyName: "zLabelClass", publicName: "zLabelClass", isSignal: true, isRequired: false, transformFunction: null }, zPlaceholder: { classPropertyName: "zPlaceholder", publicName: "zPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, zRequired: { classPropertyName: "zRequired", publicName: "zRequired", isSignal: true, isRequired: false, transformFunction: null }, zDisabled: { classPropertyName: "zDisabled", publicName: "zDisabled", isSignal: true, isRequired: false, transformFunction: null }, zReadonly: { classPropertyName: "zReadonly", publicName: "zReadonly", isSignal: true, isRequired: false, transformFunction: null }, zPrefix: { classPropertyName: "zPrefix", publicName: "zPrefix", isSignal: true, isRequired: false, transformFunction: null }, zSuffix: { classPropertyName: "zSuffix", publicName: "zSuffix", isSignal: true, isRequired: false, transformFunction: null }, zMin: { classPropertyName: "zMin", publicName: "zMin", isSignal: true, isRequired: false, transformFunction: null }, zMax: { classPropertyName: "zMax", publicName: "zMax", isSignal: true, isRequired: false, transformFunction: null }, zStep: { classPropertyName: "zStep", publicName: "zStep", isSignal: true, isRequired: false, transformFunction: null }, zShowArrows: { classPropertyName: "zShowArrows", publicName: "zShowArrows", isSignal: true, isRequired: false, transformFunction: null }, zMask: { classPropertyName: "zMask", publicName: "zMask", isSignal: true, isRequired: false, transformFunction: null }, zDecimalPlaces: { classPropertyName: "zDecimalPlaces", publicName: "zDecimalPlaces", isSignal: true, isRequired: false, transformFunction: null }, zAllowNegative: { classPropertyName: "zAllowNegative", publicName: "zAllowNegative", isSignal: true, isRequired: false, transformFunction: null }, zThousandSeparator: { classPropertyName: "zThousandSeparator", publicName: "zThousandSeparator", isSignal: true, isRequired: false, transformFunction: null }, zDecimalMarker: { classPropertyName: "zDecimalMarker", publicName: "zDecimalMarker", isSignal: true, isRequired: false, transformFunction: null }, zValidators: { classPropertyName: "zValidators", publicName: "zValidators", isSignal: true, isRequired: false, transformFunction: null }, zAsyncValidators: { classPropertyName: "zAsyncValidators", publicName: "zAsyncValidators", isSignal: true, isRequired: false, transformFunction: null }, zAsyncDebounce: { classPropertyName: "zAsyncDebounce", publicName: "zAsyncDebounce", isSignal: true, isRequired: false, transformFunction: null }, zAsyncValidateOn: { classPropertyName: "zAsyncValidateOn", publicName: "zAsyncValidateOn", isSignal: true, isRequired: false, transformFunction: null }, zShowPasswordToggle: { classPropertyName: "zShowPasswordToggle", publicName: "zShowPasswordToggle", isSignal: true, isRequired: false, transformFunction: null }, zSearch: { classPropertyName: "zSearch", publicName: "zSearch", isSignal: true, isRequired: false, transformFunction: null }, zDebounce: { classPropertyName: "zDebounce", publicName: "zDebounce", isSignal: true, isRequired: false, transformFunction: null }, zAutofocus: { classPropertyName: "zAutofocus", publicName: "zAutofocus", isSignal: true, isRequired: false, transformFunction: null }, zAutoComplete: { classPropertyName: "zAutoComplete", publicName: "zAutoComplete", isSignal: true, isRequired: false, transformFunction: null }, zAllowClear: { classPropertyName: "zAllowClear", publicName: "zAllowClear", isSignal: true, isRequired: false, transformFunction: null }, zAutoSizeContent: { classPropertyName: "zAutoSizeContent", publicName: "zAutoSizeContent", isSignal: true, isRequired: false, transformFunction: null }, zRows: { classPropertyName: "zRows", publicName: "zRows", isSignal: true, isRequired: false, transformFunction: null }, zResize: { classPropertyName: "zResize", publicName: "zResize", isSignal: true, isRequired: false, transformFunction: null }, zMaxLength: { classPropertyName: "zMaxLength", publicName: "zMaxLength", isSignal: true, isRequired: false, transformFunction: null }, zAutoSuggest: { classPropertyName: "zAutoSuggest", publicName: "zAutoSuggest", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { zOnSearch: "zOnSearch", zOnChange: "zOnChange", zControl: "zControl" }, providers: [
|
|
779
|
+
provideNgxMask(),
|
|
780
|
+
{
|
|
781
|
+
provide: NG_VALUE_ACCESSOR,
|
|
782
|
+
useExisting: forwardRef(() => ZInputComponent),
|
|
783
|
+
multi: true,
|
|
784
|
+
},
|
|
785
|
+
], viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }], exportAs: ["zInput"], ngImport: i0, template: "<div class=\"z-input-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"inputId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n @if (isTextarea()) {\n <div class=\"relative w-full\" [class]=\"textareaClasses()\" [class.overflow-auto]=\"zAutoSizeContent()\">\n <textarea\n #inputEl\n [id]=\"inputId\"\n [placeholder]=\"zPlaceholder()\"\n class=\"z-input-native placeholder:text-muted-foreground m-0 block min-h-14 w-full resize-none bg-transparent p-2 text-sm outline-none\"\n [class.resize-y]=\"zResize() && !isDisabled() && !zReadonly()\"\n [class.field-sizing-content]=\"zAutoSizeContent()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n [autocomplete]=\"zAutoComplete()\"\n [rows]=\"zRows()\"\n [attr.maxlength]=\"zMaxLength()\"\n [ngModel]=\"displayValue()\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (keydown)=\"onKeydown($event)\"></textarea>\n @if (zMaxLength()) {\n <div class=\"flex justify-end pr-1 pb-1\">\n <span class=\"text-muted-foreground text-xs\">{{ displayValue().length }} / {{ zMaxLength() }}</span>\n </div>\n }\n @if (zResize() && !isDisabled() && !zReadonly() && !zMaxLength()) {\n <svg\n class=\"text-muted-foreground pointer-events-none absolute right-0.5 bottom-0.5 opacity-40\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\">\n <path d=\"M10 2L2 10\" />\n <path d=\"M10 6L6 10\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"relative w-full\">\n <div class=\"z-input-container flex w-full items-center\" [class]=\"inputClasses()\">\n <!-- Color picker square (prefix for color type) -->\n @if (isColorType()) {\n <label\n [for]=\"inputId\"\n class=\"border-input relative z-10 size-6 shrink-0 cursor-pointer overflow-hidden rounded border\">\n <input\n type=\"color\"\n [id]=\"inputId + '-picker'\"\n class=\"absolute -top-2 -left-2 size-12 cursor-pointer border-none bg-transparent p-0\"\n [disabled]=\"isDisabled()\"\n [ngModel]=\"displayValue() || '#000000'\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\" />\n </label>\n }\n\n @if (hasPrefix() && !isColorType()) {\n <div class=\"text-muted-foreground left-3 flex items-center justify-center\">\n @if (zSearch()) {\n <z-icon zType=\"lucideSearch\" zSize=\"16\" />\n } @else if (isPrefixTemplate()) {\n <ng-container *ngTemplateOutlet=\"$any(zPrefix())\" />\n } @else {\n {{ zPrefix() }}\n }\n </div>\n }\n\n <input\n #inputEl\n [id]=\"inputId\"\n [type]=\"isColorType() ? 'text' : effectiveType()\"\n [placeholder]=\"zPlaceholder()\"\n class=\"z-input-native placeholder:text-muted-foreground h-full min-w-0 flex-1 bg-white text-sm outline-none dark:bg-transparent\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isColorType() ? true : zReadonly()\"\n [attr.min]=\"zMin()\"\n [attr.max]=\"zMax()\"\n [attr.step]=\"zStep()\"\n [autocomplete]=\"zAutoComplete()\"\n [ngModel]=\"isColorType() ? (displayValue() || '#000000').toUpperCase() : displayValue()\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (keydown)=\"onKeydown($event)\"\n [mask]=\"effectiveMask()\"\n [thousandSeparator]=\"zThousandSeparator()\"\n [decimalMarker]=\"effectiveDecimalMarker()\"\n [allowNegativeNumbers]=\"zAllowNegative()\"\n [dropSpecialCharacters]=\"false\"\n (keydown)=\"onSuggestKeydown($event)\"\n (blur)=\"closeSuggestPopover()\" />\n\n @if (hasSuffix() && !isColorType()) {\n <div class=\"text-muted-foreground flex items-center justify-center text-sm\">\n @if (isSuffixTemplate()) {\n <ng-container *ngTemplateOutlet=\"$any(zSuffix())\" />\n } @else {\n {{ zSuffix() }}\n }\n </div>\n }\n\n <!-- Async validation loading indicator -->\n @if (isValidating()) {\n <div class=\"text-muted-foreground flex items-center justify-center\">\n <z-icon zType=\"lucideLoader2\" zSize=\"16\" class=\"animate-spin\" />\n </div>\n }\n\n <!-- Clear button -->\n @if (showClearButton()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded transition-colors\"\n (click)=\"clearValue($event)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n }\n\n <!-- Copy button for color type -->\n @if (isColorType()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-accent flex size-6 shrink-0 cursor-pointer items-center justify-center rounded transition-all\"\n (click)=\"copyColorToClipboard()\">\n <span class=\"relative flex size-4 items-center justify-center\">\n <z-icon\n zType=\"lucideCopy\"\n [class]=\"colorCopied() ? 'scale-0 rotate-90 opacity-0' : 'scale-100 rotate-0 opacity-100'\"\n class=\"absolute transition-all duration-200 ease-out\"\n zSize=\"14\" />\n <z-icon\n zType=\"lucideCheck\"\n [class]=\"colorCopied() ? 'text-success scale-100 rotate-0 opacity-100' : 'scale-0 -rotate-90 opacity-0'\"\n class=\"absolute transition-all duration-200 ease-out\"\n zSize=\"14\" />\n </span>\n </button>\n }\n\n @if (showArrows() && !isDisabled()) {\n <div class=\"-mr-1 flex h-[calc(100%-4px)] shrink-0 flex-col\">\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:bg-accent hover:text-foreground flex w-5 flex-1 cursor-pointer items-center justify-center rounded transition-all\"\n (mousedown)=\"onArrowMouseDown($event, 'up')\"\n (mouseup)=\"onArrowMouseUp()\"\n (mouseleave)=\"onArrowMouseUp()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:bg-accent hover:text-foreground flex w-5 flex-1 cursor-pointer items-center justify-center rounded transition-all\"\n (mousedown)=\"onArrowMouseDown($event, 'down')\"\n (mouseup)=\"onArrowMouseUp()\"\n (mouseleave)=\"onArrowMouseUp()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" />\n </button>\n </div>\n }\n\n @if (isPasswordType() && zShowPasswordToggle()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded transition-all\"\n (click)=\"togglePasswordVisibility()\">\n @if (passwordVisible()) {\n <z-icon zType=\"lucideEyeOff\" zSize=\"16\" />\n } @else {\n <z-icon zType=\"lucideEye\" zSize=\"16\" />\n }\n </button>\n }\n </div>\n\n @if (hasAutoSuggest() && showSuggestPopover() && suggestHistory().length > 0) {\n <div\n class=\"bg-popover text-popover-foreground border-border z-animate-in z-fade-in z-duration-200 z-slide-in-from-top-4 absolute top-full left-0 z-50 mt-1 flex w-full flex-col gap-[3px] rounded-[6px] border p-1 shadow-md\">\n @for (item of filteredSuggestHistory(); track item; let i = $index) {\n <button\n type=\"button\"\n class=\"hover:bg-primary/10 hover:text-foreground flex w-full cursor-pointer items-center gap-2 rounded-[4px] px-2 py-1.5 text-left text-sm transition-colors\"\n [class.bg-primary/15]=\"suggestActiveIndex() === i\"\n [class.text-primary]=\"suggestActiveIndex() === i\"\n (mousedown)=\"selectSuggestItem(item)\">\n <z-icon zType=\"lucideClock\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">{{ item }}</span>\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n", styles: [".z-input-native:-webkit-autofill,.z-input-native:-webkit-autofill:hover,.z-input-native:-webkit-autofill:focus,.z-input-native:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px white inset!important;-webkit-text-fill-color:var(--color-foreground)!important;transition:background-color 9999s ease-in-out 0s!important;caret-color:var(--color-foreground)}:is(.dark,.dark *) .z-input-native:-webkit-autofill,:is(.dark,.dark *) .z-input-native:-webkit-autofill:hover,:is(.dark,.dark *) .z-input-native:-webkit-autofill:focus,:is(.dark,.dark *) .z-input-native:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--input-autofill) inset!important;transition:background-color 9999s ease-in-out 0s!important}textarea.z-input-native::-webkit-resizer{display:none}input[type=color]{cursor:pointer}input[type=color]::-webkit-color-swatch-wrapper{padding:0}input[type=color]::-webkit-color-swatch{border:none;border-radius:calc(var(--radius) - 2px)}input[type=color]::-moz-color-swatch{border:none;border-radius:calc(var(--radius) - 2px)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: NgxMaskDirective, selector: "input[mask], textarea[mask]", inputs: ["mask", "specialCharacters", "patterns", "prefix", "suffix", "thousandSeparator", "decimalMarker", "dropSpecialCharacters", "hiddenInput", "showMaskTyped", "placeHolderCharacter", "shownMaskExpression", "clearIfNotMatch", "validation", "separatorLimit", "allowNegativeNumbers", "leadZeroDateTime", "leadZero", "triggerOnMaskChange", "apm", "inputTransformFn", "outputTransformFn", "keepCharacterPositions", "instantPrefix"], outputs: ["maskFilled"], exportAs: ["mask", "ngxMask"] }, { kind: "component", type: ZIconComponent, selector: "z-icon, [z-icon]", inputs: ["class", "zType", "zSize", "zStrokeWidth", "zSvg"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
786
|
+
}
|
|
787
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ZInputComponent, decorators: [{
|
|
788
|
+
type: Component,
|
|
789
|
+
args: [{ selector: 'z-input', imports: [FormsModule, ReactiveFormsModule, NgxMaskDirective, ZIconComponent, NgTemplateOutlet], standalone: true, providers: [
|
|
790
|
+
provideNgxMask(),
|
|
791
|
+
{
|
|
792
|
+
provide: NG_VALUE_ACCESSOR,
|
|
793
|
+
useExisting: forwardRef(() => ZInputComponent),
|
|
794
|
+
multi: true,
|
|
795
|
+
},
|
|
796
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, exportAs: 'zInput', template: "<div class=\"z-input-wrapper flex w-full flex-col gap-2\">\n @if (zLabel()) {\n <label [for]=\"inputId\" class=\"text-xs leading-none font-medium\" [class]=\"zLabelClass()\">\n {{ zLabel() }}\n @if (zRequired()) {\n <span class=\"text-destructive! ml-0.5\">*</span>\n }\n </label>\n }\n\n @if (isTextarea()) {\n <div class=\"relative w-full\" [class]=\"textareaClasses()\" [class.overflow-auto]=\"zAutoSizeContent()\">\n <textarea\n #inputEl\n [id]=\"inputId\"\n [placeholder]=\"zPlaceholder()\"\n class=\"z-input-native placeholder:text-muted-foreground m-0 block min-h-14 w-full resize-none bg-transparent p-2 text-sm outline-none\"\n [class.resize-y]=\"zResize() && !isDisabled() && !zReadonly()\"\n [class.field-sizing-content]=\"zAutoSizeContent()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"zReadonly()\"\n [autocomplete]=\"zAutoComplete()\"\n [rows]=\"zRows()\"\n [attr.maxlength]=\"zMaxLength()\"\n [ngModel]=\"displayValue()\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (keydown)=\"onKeydown($event)\"></textarea>\n @if (zMaxLength()) {\n <div class=\"flex justify-end pr-1 pb-1\">\n <span class=\"text-muted-foreground text-xs\">{{ displayValue().length }} / {{ zMaxLength() }}</span>\n </div>\n }\n @if (zResize() && !isDisabled() && !zReadonly() && !zMaxLength()) {\n <svg\n class=\"text-muted-foreground pointer-events-none absolute right-0.5 bottom-0.5 opacity-40\"\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\">\n <path d=\"M10 2L2 10\" />\n <path d=\"M10 6L6 10\" />\n </svg>\n }\n </div>\n } @else {\n <div class=\"relative w-full\">\n <div class=\"z-input-container flex w-full items-center\" [class]=\"inputClasses()\">\n <!-- Color picker square (prefix for color type) -->\n @if (isColorType()) {\n <label\n [for]=\"inputId\"\n class=\"border-input relative z-10 size-6 shrink-0 cursor-pointer overflow-hidden rounded border\">\n <input\n type=\"color\"\n [id]=\"inputId + '-picker'\"\n class=\"absolute -top-2 -left-2 size-12 cursor-pointer border-none bg-transparent p-0\"\n [disabled]=\"isDisabled()\"\n [ngModel]=\"displayValue() || '#000000'\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\" />\n </label>\n }\n\n @if (hasPrefix() && !isColorType()) {\n <div class=\"text-muted-foreground left-3 flex items-center justify-center\">\n @if (zSearch()) {\n <z-icon zType=\"lucideSearch\" zSize=\"16\" />\n } @else if (isPrefixTemplate()) {\n <ng-container *ngTemplateOutlet=\"$any(zPrefix())\" />\n } @else {\n {{ zPrefix() }}\n }\n </div>\n }\n\n <input\n #inputEl\n [id]=\"inputId\"\n [type]=\"isColorType() ? 'text' : effectiveType()\"\n [placeholder]=\"zPlaceholder()\"\n class=\"z-input-native placeholder:text-muted-foreground h-full min-w-0 flex-1 bg-white text-sm outline-none dark:bg-transparent\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isColorType() ? true : zReadonly()\"\n [attr.min]=\"zMin()\"\n [attr.max]=\"zMax()\"\n [attr.step]=\"zStep()\"\n [autocomplete]=\"zAutoComplete()\"\n [ngModel]=\"isColorType() ? (displayValue() || '#000000').toUpperCase() : displayValue()\"\n (ngModelChange)=\"onModelChange($event)\"\n (blur)=\"onBlur()\"\n (focus)=\"onFocus()\"\n (keydown)=\"onKeydown($event)\"\n [mask]=\"effectiveMask()\"\n [thousandSeparator]=\"zThousandSeparator()\"\n [decimalMarker]=\"effectiveDecimalMarker()\"\n [allowNegativeNumbers]=\"zAllowNegative()\"\n [dropSpecialCharacters]=\"false\"\n (keydown)=\"onSuggestKeydown($event)\"\n (blur)=\"closeSuggestPopover()\" />\n\n @if (hasSuffix() && !isColorType()) {\n <div class=\"text-muted-foreground flex items-center justify-center text-sm\">\n @if (isSuffixTemplate()) {\n <ng-container *ngTemplateOutlet=\"$any(zSuffix())\" />\n } @else {\n {{ zSuffix() }}\n }\n </div>\n }\n\n <!-- Async validation loading indicator -->\n @if (isValidating()) {\n <div class=\"text-muted-foreground flex items-center justify-center\">\n <z-icon zType=\"lucideLoader2\" zSize=\"16\" class=\"animate-spin\" />\n </div>\n }\n\n <!-- Clear button -->\n @if (showClearButton()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-5 shrink-0 cursor-pointer items-center justify-center rounded transition-colors\"\n (click)=\"clearValue($event)\">\n <z-icon zType=\"lucideX\" zSize=\"14\" />\n </button>\n }\n\n <!-- Copy button for color type -->\n @if (isColorType()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground hover:bg-accent flex size-6 shrink-0 cursor-pointer items-center justify-center rounded transition-all\"\n (click)=\"copyColorToClipboard()\">\n <span class=\"relative flex size-4 items-center justify-center\">\n <z-icon\n zType=\"lucideCopy\"\n [class]=\"colorCopied() ? 'scale-0 rotate-90 opacity-0' : 'scale-100 rotate-0 opacity-100'\"\n class=\"absolute transition-all duration-200 ease-out\"\n zSize=\"14\" />\n <z-icon\n zType=\"lucideCheck\"\n [class]=\"colorCopied() ? 'text-success scale-100 rotate-0 opacity-100' : 'scale-0 -rotate-90 opacity-0'\"\n class=\"absolute transition-all duration-200 ease-out\"\n zSize=\"14\" />\n </span>\n </button>\n }\n\n @if (showArrows() && !isDisabled()) {\n <div class=\"-mr-1 flex h-[calc(100%-4px)] shrink-0 flex-col\">\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:bg-accent hover:text-foreground flex w-5 flex-1 cursor-pointer items-center justify-center rounded transition-all\"\n (mousedown)=\"onArrowMouseDown($event, 'up')\"\n (mouseup)=\"onArrowMouseUp()\"\n (mouseleave)=\"onArrowMouseUp()\">\n <z-icon zType=\"lucideChevronUp\" zSize=\"12\" />\n </button>\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:bg-accent hover:text-foreground flex w-5 flex-1 cursor-pointer items-center justify-center rounded transition-all\"\n (mousedown)=\"onArrowMouseDown($event, 'down')\"\n (mouseup)=\"onArrowMouseUp()\"\n (mouseleave)=\"onArrowMouseUp()\">\n <z-icon zType=\"lucideChevronDown\" zSize=\"12\" />\n </button>\n </div>\n }\n\n @if (isPasswordType() && zShowPasswordToggle()) {\n <button\n type=\"button\"\n tabindex=\"-1\"\n class=\"text-muted-foreground hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded transition-all\"\n (click)=\"togglePasswordVisibility()\">\n @if (passwordVisible()) {\n <z-icon zType=\"lucideEyeOff\" zSize=\"16\" />\n } @else {\n <z-icon zType=\"lucideEye\" zSize=\"16\" />\n }\n </button>\n }\n </div>\n\n @if (hasAutoSuggest() && showSuggestPopover() && suggestHistory().length > 0) {\n <div\n class=\"bg-popover text-popover-foreground border-border z-animate-in z-fade-in z-duration-200 z-slide-in-from-top-4 absolute top-full left-0 z-50 mt-1 flex w-full flex-col gap-[3px] rounded-[6px] border p-1 shadow-md\">\n @for (item of filteredSuggestHistory(); track item; let i = $index) {\n <button\n type=\"button\"\n class=\"hover:bg-primary/10 hover:text-foreground flex w-full cursor-pointer items-center gap-2 rounded-[4px] px-2 py-1.5 text-left text-sm transition-colors\"\n [class.bg-primary/15]=\"suggestActiveIndex() === i\"\n [class.text-primary]=\"suggestActiveIndex() === i\"\n (mousedown)=\"selectSuggestItem(item)\">\n <z-icon zType=\"lucideClock\" zSize=\"14\" class=\"text-muted-foreground shrink-0\" />\n <span class=\"truncate\">{{ item }}</span>\n </button>\n }\n </div>\n }\n </div>\n }\n\n @if (showError()) {\n <p class=\"text-destructive animate-in fade-in slide-in-from-top-1 m-0 text-xs duration-200\">\n {{ errorMessage() }}\n </p>\n }\n</div>\n", styles: [".z-input-native:-webkit-autofill,.z-input-native:-webkit-autofill:hover,.z-input-native:-webkit-autofill:focus,.z-input-native:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px white inset!important;-webkit-text-fill-color:var(--color-foreground)!important;transition:background-color 9999s ease-in-out 0s!important;caret-color:var(--color-foreground)}:is(.dark,.dark *) .z-input-native:-webkit-autofill,:is(.dark,.dark *) .z-input-native:-webkit-autofill:hover,:is(.dark,.dark *) .z-input-native:-webkit-autofill:focus,:is(.dark,.dark *) .z-input-native:-webkit-autofill:active{-webkit-box-shadow:0 0 0 1000px var(--input-autofill) inset!important;transition:background-color 9999s ease-in-out 0s!important}textarea.z-input-native::-webkit-resizer{display:none}input[type=color]{cursor:pointer}input[type=color]::-webkit-color-swatch-wrapper{padding:0}input[type=color]::-webkit-color-swatch{border:none;border-radius:calc(var(--radius) - 2px)}input[type=color]::-moz-color-swatch{border:none;border-radius:calc(var(--radius) - 2px)}\n"] }]
|
|
797
|
+
}], propDecorators: { class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], zType: [{ type: i0.Input, args: [{ isSignal: true, alias: "zType", required: false }] }], zSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSize", required: false }] }], zLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabel", required: false }] }], zLabelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "zLabelClass", required: false }] }], zPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPlaceholder", required: false }] }], zRequired: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRequired", required: false }] }], zDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDisabled", required: false }] }], zReadonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "zReadonly", required: false }] }], zPrefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "zPrefix", required: false }] }], zSuffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSuffix", required: false }] }], zMin: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMin", required: false }] }], zMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMax", required: false }] }], zStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "zStep", required: false }] }], zShowArrows: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowArrows", required: false }] }], zMask: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMask", required: false }] }], zDecimalPlaces: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDecimalPlaces", required: false }] }], zAllowNegative: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowNegative", required: false }] }], zThousandSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "zThousandSeparator", required: false }] }], zDecimalMarker: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDecimalMarker", required: false }] }], zValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "zValidators", required: false }] }], zAsyncValidators: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncValidators", required: false }] }], zAsyncDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncDebounce", required: false }] }], zAsyncValidateOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAsyncValidateOn", required: false }] }], zShowPasswordToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "zShowPasswordToggle", required: false }] }], zSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "zSearch", required: false }] }], zDebounce: [{ type: i0.Input, args: [{ isSignal: true, alias: "zDebounce", required: false }] }], zAutofocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAutofocus", required: false }] }], zAutoComplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAutoComplete", required: false }] }], zAllowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAllowClear", required: false }] }], zAutoSizeContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAutoSizeContent", required: false }] }], zRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "zRows", required: false }] }], zResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "zResize", required: false }] }], zMaxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "zMaxLength", required: false }] }], zAutoSuggest: [{ type: i0.Input, args: [{ isSignal: true, alias: "zAutoSuggest", required: false }] }], zOnSearch: [{ type: i0.Output, args: ["zOnSearch"] }], zOnChange: [{ type: i0.Output, args: ["zOnChange"] }], zControl: [{ type: i0.Output, args: ["zControl"] }], inputRef: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }] } });
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* Generated bundle index. Do not edit.
|
|
801
|
+
*/
|
|
802
|
+
|
|
803
|
+
export { ZInputComponent, zInputVariants, zTextareaVariants };
|
|
804
|
+
//# sourceMappingURL=shival99-z-ui-components-z-input.mjs.map
|