@honuware/ui 0.1.0

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.
@@ -0,0 +1,624 @@
1
+ import * as i0 from '@angular/core';
2
+ import { EventEmitter, Output, Input, Component, Inject } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
5
+ import * as i2 from '@angular/material/form-field';
6
+ import { MatFormFieldModule } from '@angular/material/form-field';
7
+ import * as i3 from '@angular/material/input';
8
+ import { MatInputModule } from '@angular/material/input';
9
+ import * as i2$1 from '@angular/material/checkbox';
10
+ import { MatCheckboxModule } from '@angular/material/checkbox';
11
+ import * as i3$1 from '@angular/material/select';
12
+ import { MatSelectModule } from '@angular/material/select';
13
+ import { MatNativeDateModule } from '@angular/material/core';
14
+ import * as i4 from '@angular/material/datepicker';
15
+ import { MatDatepickerModule } from '@angular/material/datepicker';
16
+ import * as i5 from '@angular/material/timepicker';
17
+ import { MatTimepickerModule } from '@angular/material/timepicker';
18
+ import { isMicrosecondTimestamp, microsToDate, dateToMicros } from '@honuware/ui/foundation';
19
+ import * as i4$1 from '@angular/material/autocomplete';
20
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
21
+ import { Subject } from 'rxjs';
22
+ import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';
23
+ import { HONUWARE_CRUD_ACCESS } from '@honuware/ui/access';
24
+
25
+ class SimpleTextComponent {
26
+ dataInfo;
27
+ value;
28
+ readOnly = false;
29
+ valueChanged = new EventEmitter();
30
+ textInput = new FormControl();
31
+ isLoading = true;
32
+ skipValueChanges = false;
33
+ get displayLabel() {
34
+ return this.dataInfo?.label || this.dataInfo?.column_friendly_name || this.dataInfo?.column_name || '';
35
+ }
36
+ ngOnInit() {
37
+ const initialValue = this.value ?? this.dataInfo?.default_value ?? '';
38
+ this.textInput.setValue(initialValue, { emitEvent: false });
39
+ this.textInput.setValidators(this.getValidators());
40
+ this.textInput.updateValueAndValidity();
41
+ if (this.readOnly) {
42
+ this.textInput.disable();
43
+ }
44
+ this.textInput.valueChanges.subscribe((value) => {
45
+ if (!this.skipValueChanges) {
46
+ this.valueChanged.emit(value);
47
+ }
48
+ });
49
+ this.isLoading = false;
50
+ }
51
+ ngOnChanges(changes) {
52
+ if (changes['dataInfo'] && !changes['dataInfo'].firstChange) {
53
+ this.skipValueChanges = true;
54
+ const newValue = this.value ?? this.dataInfo?.default_value ?? '';
55
+ this.textInput.setValue(newValue, { emitEvent: false });
56
+ this.textInput.setValidators(this.getValidators());
57
+ this.textInput.updateValueAndValidity();
58
+ this.skipValueChanges = false;
59
+ }
60
+ if (changes['value'] && !changes['value'].firstChange) {
61
+ this.skipValueChanges = true;
62
+ this.textInput.setValue(this.value ?? '', { emitEvent: false });
63
+ this.textInput.setValidators(this.getValidators());
64
+ this.textInput.updateValueAndValidity();
65
+ this.skipValueChanges = false;
66
+ }
67
+ }
68
+ getValidators() {
69
+ const validators = [];
70
+ if (this.dataInfo?.required) {
71
+ validators.push(Validators.required);
72
+ }
73
+ if (this.dataInfo?.max_length) {
74
+ validators.push(Validators.maxLength(this.dataInfo.max_length));
75
+ }
76
+ if (this.dataInfo?.regex) {
77
+ validators.push(Validators.pattern(this.dataInfo.regex));
78
+ }
79
+ return validators;
80
+ }
81
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
82
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SimpleTextComponent, isStandalone: true, selector: "hw-simple-text", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly" }, outputs: { valueChanged: "valueChanged" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput\n [id]=\"dataInfo?.column_name ?? ''\"\n [type]=\"dataInfo?.html_input_type || 'text'\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\"\n [formControl]=\"textInput\" />\n\n @if (dataInfo?.hint) {\n <mat-hint>{{ dataInfo?.hint }}</mat-hint>\n }\n\n </mat-form-field>\n\n @if (textInput.touched && textInput.hasError('required')) {\n <mat-error>This field is required.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('maxlength')) {\n <mat-error>Max {{ dataInfo?.max_length }} characters allowed.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('pattern')) {\n <mat-error>Invalid format.</mat-error>\n }\n\n</div>\n}\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}.loading{color:#0009;padding:8px 0}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
83
+ }
84
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleTextComponent, decorators: [{
85
+ type: Component,
86
+ args: [{ selector: 'hw-simple-text', imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule], template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput\n [id]=\"dataInfo?.column_name ?? ''\"\n [type]=\"dataInfo?.html_input_type || 'text'\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\"\n [formControl]=\"textInput\" />\n\n @if (dataInfo?.hint) {\n <mat-hint>{{ dataInfo?.hint }}</mat-hint>\n }\n\n </mat-form-field>\n\n @if (textInput.touched && textInput.hasError('required')) {\n <mat-error>This field is required.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('maxlength')) {\n <mat-error>Max {{ dataInfo?.max_length }} characters allowed.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('pattern')) {\n <mat-error>Invalid format.</mat-error>\n }\n\n</div>\n}\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}.loading{color:#0009;padding:8px 0}\n"] }]
87
+ }], propDecorators: { dataInfo: [{
88
+ type: Input
89
+ }], value: [{
90
+ type: Input
91
+ }], readOnly: [{
92
+ type: Input
93
+ }], valueChanged: [{
94
+ type: Output
95
+ }] } });
96
+
97
+ class LongTextComponent {
98
+ dataInfo;
99
+ value;
100
+ readOnly = false;
101
+ valueChanged = new EventEmitter();
102
+ textInput = new FormControl('');
103
+ isLoading = true;
104
+ skipValueChanges = false;
105
+ get displayLabel() {
106
+ return this.dataInfo?.label || this.dataInfo?.column_friendly_name || this.dataInfo?.column_name || '';
107
+ }
108
+ ngOnInit() {
109
+ const initialValue = this.value ?? this.dataInfo?.default_value ?? '';
110
+ this.textInput.setValue(initialValue, { emitEvent: false });
111
+ this.textInput.setValidators(this.getValidators());
112
+ if (this.readOnly) {
113
+ this.textInput.disable();
114
+ }
115
+ this.textInput.valueChanges.subscribe((value) => {
116
+ if (!this.skipValueChanges) {
117
+ this.valueChanged.emit(value);
118
+ }
119
+ });
120
+ this.isLoading = false;
121
+ }
122
+ ngOnChanges(changes) {
123
+ if (changes['dataInfo'] && !changes['dataInfo'].firstChange) {
124
+ this.skipValueChanges = true;
125
+ const newValue = this.value ?? this.dataInfo?.default_value ?? '';
126
+ this.textInput.setValue(newValue, { emitEvent: false });
127
+ this.textInput.setValidators(this.getValidators());
128
+ this.textInput.updateValueAndValidity();
129
+ this.skipValueChanges = false;
130
+ }
131
+ if (changes['value'] && !changes['value'].firstChange) {
132
+ this.skipValueChanges = true;
133
+ this.textInput.setValue(this.value ?? '', { emitEvent: false });
134
+ this.textInput.setValidators(this.getValidators());
135
+ this.textInput.updateValueAndValidity();
136
+ this.skipValueChanges = false;
137
+ }
138
+ }
139
+ getValidators() {
140
+ const validators = [];
141
+ if (this.dataInfo?.required) {
142
+ validators.push(Validators.required);
143
+ }
144
+ if (this.dataInfo?.max_length) {
145
+ validators.push(Validators.maxLength(this.dataInfo.max_length));
146
+ }
147
+ if (this.dataInfo?.regex) {
148
+ validators.push(Validators.pattern(this.dataInfo.regex));
149
+ }
150
+ return validators;
151
+ }
152
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: LongTextComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: LongTextComponent, isStandalone: true, selector: "hw-long-text", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly" }, outputs: { valueChanged: "valueChanged" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<div id=\"loading\">\n Loading...\n</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <textarea matInput\n [id]=\"dataInfo?.column_name ?? ''\"\n [formControl]=\"textInput\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\"\n [rows]=\"dataInfo?.rows || 3\"></textarea>\n\n @if (dataInfo?.hint) {\n <mat-hint>{{ dataInfo?.hint }}</mat-hint>\n }\n\n </mat-form-field>\n\n @if (textInput.touched && textInput.hasError('required')) {\n <mat-error>This field is required.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('maxlength')) {\n <mat-error>Max {{ dataInfo?.max_length }} characters allowed.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('pattern')) {\n <mat-error class=\"error\">Invalid format.</mat-error>\n }\n\n</div>\n }\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}.loading{color:#0009;padding:8px 0}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
154
+ }
155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: LongTextComponent, decorators: [{
156
+ type: Component,
157
+ args: [{ selector: 'hw-long-text', standalone: true, imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule], template: "@if (isLoading) {\n<div id=\"loading\">\n Loading...\n</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <textarea matInput\n [id]=\"dataInfo?.column_name ?? ''\"\n [formControl]=\"textInput\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\"\n [rows]=\"dataInfo?.rows || 3\"></textarea>\n\n @if (dataInfo?.hint) {\n <mat-hint>{{ dataInfo?.hint }}</mat-hint>\n }\n\n </mat-form-field>\n\n @if (textInput.touched && textInput.hasError('required')) {\n <mat-error>This field is required.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('maxlength')) {\n <mat-error>Max {{ dataInfo?.max_length }} characters allowed.</mat-error>\n }\n\n @if (textInput.touched && textInput.hasError('pattern')) {\n <mat-error class=\"error\">Invalid format.</mat-error>\n }\n\n</div>\n }\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}.loading{color:#0009;padding:8px 0}\n"] }]
158
+ }], propDecorators: { dataInfo: [{
159
+ type: Input
160
+ }], value: [{
161
+ type: Input
162
+ }], readOnly: [{
163
+ type: Input
164
+ }], valueChanged: [{
165
+ type: Output
166
+ }] } });
167
+
168
+ class SimpleBoolComponent {
169
+ dataInfo;
170
+ value;
171
+ readOnly = false;
172
+ checkboxValueChange = new EventEmitter();
173
+ checkboxControl = new FormControl(false);
174
+ isLoading = true;
175
+ skipValueChanges = false;
176
+ isTrueValue(value) {
177
+ return value === 'true' || value === 't';
178
+ }
179
+ ngOnInit() {
180
+ const initialValue = this.value !== undefined
181
+ ? this.isTrueValue(this.value)
182
+ : this.isTrueValue(this.dataInfo?.default_value);
183
+ this.checkboxControl.setValue(initialValue, { emitEvent: false });
184
+ this.checkboxControl.updateValueAndValidity();
185
+ if (this.readOnly) {
186
+ this.checkboxControl.disable();
187
+ }
188
+ this.checkboxControl.valueChanges.subscribe((value) => {
189
+ if (!this.skipValueChanges) {
190
+ this.emitCheckboxValue(value);
191
+ }
192
+ });
193
+ this.isLoading = false;
194
+ }
195
+ ngOnChanges(changes) {
196
+ if (changes['dataInfo'] && this.dataInfo) {
197
+ this.skipValueChanges = true;
198
+ const newValue = this.value !== undefined
199
+ ? this.isTrueValue(this.value)
200
+ : this.isTrueValue(this.dataInfo.default_value);
201
+ this.checkboxControl.setValue(newValue, { emitEvent: false });
202
+ this.checkboxControl.updateValueAndValidity();
203
+ this.skipValueChanges = false;
204
+ }
205
+ if (changes['value'] && !changes['value'].firstChange) {
206
+ this.skipValueChanges = true;
207
+ const newValue = this.isTrueValue(this.value);
208
+ this.checkboxControl.setValue(newValue, { emitEvent: false });
209
+ this.checkboxControl.updateValueAndValidity();
210
+ this.skipValueChanges = false;
211
+ }
212
+ if (changes['readOnly'] && !changes['readOnly'].firstChange) {
213
+ if (this.readOnly) {
214
+ this.checkboxControl.disable();
215
+ }
216
+ else {
217
+ this.checkboxControl.enable();
218
+ }
219
+ }
220
+ }
221
+ emitCheckboxValue(value) {
222
+ const emittedValue = value ? 'true' : 'false';
223
+ this.checkboxValueChange.emit(emittedValue);
224
+ }
225
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleBoolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
226
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SimpleBoolComponent, isStandalone: true, selector: "hw-simple-bool", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly" }, outputs: { checkboxValueChange: "checkboxValueChange" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <span class=\"readonly-bool\">{{ checkboxControl.value ? 'Yes' : 'No' }}</span>\n } @else {\n <mat-checkbox [formControl]=\"checkboxControl\">\n {{ dataInfo?.label }}\n </mat-checkbox>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i2$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }] });
227
+ }
228
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleBoolComponent, decorators: [{
229
+ type: Component,
230
+ args: [{ standalone: true, selector: 'hw-simple-bool', imports: [ReactiveFormsModule, MatCheckboxModule], template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <span class=\"readonly-bool\">{{ checkboxControl.value ? 'Yes' : 'No' }}</span>\n } @else {\n <mat-checkbox [formControl]=\"checkboxControl\">\n {{ dataInfo?.label }}\n </mat-checkbox>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}\n"] }]
231
+ }], propDecorators: { dataInfo: [{
232
+ type: Input
233
+ }], value: [{
234
+ type: Input
235
+ }], readOnly: [{
236
+ type: Input
237
+ }], checkboxValueChange: [{
238
+ type: Output
239
+ }] } });
240
+
241
+ class SimpleEnumComponent {
242
+ dataInfo;
243
+ value;
244
+ readOnly = false;
245
+ enumValueChange = new EventEmitter();
246
+ selectControl = new FormControl('');
247
+ isLoading = true;
248
+ skipValueChanges = false;
249
+ ngOnInit() {
250
+ const initialValue = this.value !== undefined
251
+ ? this.value
252
+ : (this.dataInfo?.default_value ?? '');
253
+ this.selectControl.setValue(initialValue, { emitEvent: false });
254
+ if (this.readOnly) {
255
+ this.selectControl.disable();
256
+ }
257
+ this.selectControl.valueChanges.subscribe((value) => {
258
+ if (!this.skipValueChanges) {
259
+ this.enumValueChange.emit(value);
260
+ }
261
+ });
262
+ this.isLoading = false;
263
+ }
264
+ ngOnChanges(changes) {
265
+ if (changes['dataInfo'] && this.dataInfo) {
266
+ this.skipValueChanges = true;
267
+ const newValue = this.value !== undefined
268
+ ? this.value
269
+ : (this.dataInfo.default_value ?? '');
270
+ this.selectControl.setValue(newValue, { emitEvent: false });
271
+ this.skipValueChanges = false;
272
+ }
273
+ if (changes['value'] && !changes['value'].firstChange) {
274
+ this.skipValueChanges = true;
275
+ this.selectControl.setValue(this.value ?? '', { emitEvent: false });
276
+ this.skipValueChanges = false;
277
+ }
278
+ if (changes['readOnly'] && !changes['readOnly'].firstChange) {
279
+ if (this.readOnly) {
280
+ this.selectControl.disable();
281
+ }
282
+ else {
283
+ this.selectControl.enable();
284
+ }
285
+ }
286
+ }
287
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleEnumComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
288
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SimpleEnumComponent, isStandalone: true, selector: "hw-simple-enum", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly" }, outputs: { enumValueChange: "enumValueChange" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <span class=\"readonly-enum\">{{ selectControl.value }}</span>\n } @else {\n <mat-form-field>\n <mat-label>{{ dataInfo?.label }}</mat-label>\n <mat-select [formControl]=\"selectControl\">\n @for (option of dataInfo?.enum_values; track option) {\n <mat-option [value]=\"option\">{{ option }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "component", type: i3$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i3$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatFormFieldModule }] });
289
+ }
290
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleEnumComponent, decorators: [{
291
+ type: Component,
292
+ args: [{ standalone: true, selector: 'hw-simple-enum', imports: [ReactiveFormsModule, MatSelectModule, MatFormFieldModule], template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <span class=\"readonly-enum\">{{ selectControl.value }}</span>\n } @else {\n <mat-form-field>\n <mat-label>{{ dataInfo?.label }}</mat-label>\n <mat-select [formControl]=\"selectControl\">\n @for (option of dataInfo?.enum_values; track option) {\n <mat-option [value]=\"option\">{{ option }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}\n"] }]
293
+ }], propDecorators: { dataInfo: [{
294
+ type: Input
295
+ }], value: [{
296
+ type: Input
297
+ }], readOnly: [{
298
+ type: Input
299
+ }], enumValueChange: [{
300
+ type: Output
301
+ }] } });
302
+
303
+ class SimpleDateComponent {
304
+ dataInfo;
305
+ value;
306
+ loading = true;
307
+ readOnly = false;
308
+ type = 'datetime';
309
+ // Minutes between selectable timepicker options. Default 20 matches the
310
+ // calendar's old TIME_SEGMENT_INCREMENT_MIN — callers that need a different
311
+ // granularity pass it in, so the control no longer depends on @pages/calendar.
312
+ timeIncrementMinutes = 20;
313
+ valueChange = new EventEmitter();
314
+ dateControl = new FormControl();
315
+ isMicrosecondInput = false;
316
+ isBigIntColumn() {
317
+ return this.dataInfo?.type === 'BIGINT';
318
+ }
319
+ parseInputValue(value) {
320
+ if (!value)
321
+ return null;
322
+ if (isMicrosecondTimestamp(value)) {
323
+ this.isMicrosecondInput = true;
324
+ return microsToDate(value);
325
+ }
326
+ this.isMicrosecondInput = false;
327
+ const parsed = new Date(value);
328
+ return isNaN(parsed.getTime()) ? null : parsed;
329
+ }
330
+ ngOnInit() {
331
+ // BIGINT date columns always use microseconds, even for new items
332
+ // where there's no existing value to detect the format from.
333
+ if (this.isBigIntColumn()) {
334
+ this.isMicrosecondInput = true;
335
+ }
336
+ const initialValue = this.value ?? this.dataInfo?.default_value ?? '';
337
+ const initialDate = this.parseInputValue(initialValue);
338
+ this.dateControl = new FormControl(initialDate, {
339
+ validators: this.dataInfo?.required ? [Validators.required] : [],
340
+ });
341
+ if (this.readOnly) {
342
+ this.dateControl.disable();
343
+ }
344
+ this.dateControl.valueChanges.subscribe((value) => {
345
+ if (value && this.dateControl.valid && Date.parse(String(value))) {
346
+ const date = new Date(Date.parse(String(value)));
347
+ if (this.isMicrosecondInput) {
348
+ this.valueChange.emit(dateToMicros(date));
349
+ }
350
+ else {
351
+ this.valueChange.emit(date.toISOString());
352
+ }
353
+ }
354
+ });
355
+ this.loading = false;
356
+ }
357
+ ngOnChanges(changes) {
358
+ if (changes['dataInfo'] && !changes['dataInfo'].firstChange) {
359
+ const newValue = this.value ?? this.dataInfo?.default_value ?? '';
360
+ const newDate = this.parseInputValue(newValue);
361
+ this.dateControl.setValue(newDate, { emitEvent: false });
362
+ this.dateControl.updateValueAndValidity();
363
+ }
364
+ if (changes['value'] && !changes['value'].firstChange) {
365
+ const newDate = this.parseInputValue(this.value ?? '');
366
+ this.dateControl.setValue(newDate, { emitEvent: false });
367
+ this.dateControl.updateValueAndValidity();
368
+ }
369
+ if (changes['readOnly'] && !changes['readOnly'].firstChange) {
370
+ if (this.readOnly) {
371
+ this.dateControl.disable();
372
+ }
373
+ else {
374
+ this.dateControl.enable();
375
+ }
376
+ }
377
+ }
378
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleDateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
379
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: SimpleDateComponent, isStandalone: true, selector: "hw-simple-date", inputs: { dataInfo: "dataInfo", value: "value", loading: "loading", readOnly: "readOnly", type: "type", timeIncrementMinutes: "timeIncrementMinutes" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "@if (loading) {\n<p class=\"loading\">Loading...</p>\n}\n\n@if (!loading) {\n<div class=\"form-fields\">\n @if (type.includes('date')) {\n <mat-form-field>\n <mat-label>{{dataInfo?.label}} date</mat-label>\n <input matInput [formControl]=\"dateControl\" [matDatepicker]=\"datepicker\" />\n <mat-datepicker-toggle [for]=\"datepicker\" matIconSuffix />\n <mat-datepicker #datepicker />\n\n @if (dateControl.getError('required') && !dateControl.hasError('matDatepickerParse')) {\n <mat-error>This value is required.</mat-error>\n }\n\n @if (dateControl.hasError('matDatepickerParse')) {\n <mat-error>\n '{{dateControl.getError('matDatepickerParse')?.text}}' is invalid\n </mat-error>\n }\n </mat-form-field>\n }\n\n @if (type.includes('time')) {\n <mat-form-field>\n <mat-label>{{dataInfo?.label}} time</mat-label>\n <input matInput [formControl]=\"dateControl\" [matTimepicker]=\"timePicker\" />\n <mat-timepicker-toggle matIconSuffix [for]=\"timePicker\" />\n <mat-timepicker #timePicker interval=\"{{timeIncrementMinutes}}m\" />\n\n @if (dateControl.getError('required') && !dateControl.hasError('matTimepickerParse')) {\n <mat-error>This value is required.</mat-error>\n }\n\n @if (dateControl.hasError('matTimepickerParse')) {\n <mat-error>\n '{{dateControl.getError('matTimepickerParse')?.text}}' is invalid\n </mat-error>\n }\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}.mat-form-field .mat-error{white-space:normal;line-height:1.5;max-height:none;padding:0}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "ngmodule", type: MatTimepickerModule }, { kind: "component", type: i5.MatTimepicker, selector: "mat-timepicker", inputs: ["interval", "options", "disableRipple", "aria-label", "aria-labelledby", "panelClass"], outputs: ["selected", "opened", "closed"], exportAs: ["matTimepicker"] }, { kind: "directive", type: i5.MatTimepickerInput, selector: "input[matTimepicker]", inputs: ["value", "matTimepicker", "matTimepickerMin", "matTimepickerMax", "matTimepickerOpenOnClick", "disabled"], outputs: ["valueChange"], exportAs: ["matTimepickerInput"] }, { kind: "component", type: i5.MatTimepickerToggle, selector: "mat-timepicker-toggle", inputs: ["for", "aria-label", "aria-labelledby", "disabled", "tabIndex", "disableRipple"], exportAs: ["matTimepickerToggle"] }] });
380
+ }
381
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: SimpleDateComponent, decorators: [{
382
+ type: Component,
383
+ args: [{ selector: 'hw-simple-date', standalone: true, imports: [
384
+ ReactiveFormsModule,
385
+ MatFormFieldModule,
386
+ MatInputModule,
387
+ MatNativeDateModule,
388
+ MatDatepickerModule,
389
+ MatTimepickerModule,
390
+ ], template: "@if (loading) {\n<p class=\"loading\">Loading...</p>\n}\n\n@if (!loading) {\n<div class=\"form-fields\">\n @if (type.includes('date')) {\n <mat-form-field>\n <mat-label>{{dataInfo?.label}} date</mat-label>\n <input matInput [formControl]=\"dateControl\" [matDatepicker]=\"datepicker\" />\n <mat-datepicker-toggle [for]=\"datepicker\" matIconSuffix />\n <mat-datepicker #datepicker />\n\n @if (dateControl.getError('required') && !dateControl.hasError('matDatepickerParse')) {\n <mat-error>This value is required.</mat-error>\n }\n\n @if (dateControl.hasError('matDatepickerParse')) {\n <mat-error>\n '{{dateControl.getError('matDatepickerParse')?.text}}' is invalid\n </mat-error>\n }\n </mat-form-field>\n }\n\n @if (type.includes('time')) {\n <mat-form-field>\n <mat-label>{{dataInfo?.label}} time</mat-label>\n <input matInput [formControl]=\"dateControl\" [matTimepicker]=\"timePicker\" />\n <mat-timepicker-toggle matIconSuffix [for]=\"timePicker\" />\n <mat-timepicker #timePicker interval=\"{{timeIncrementMinutes}}m\" />\n\n @if (dateControl.getError('required') && !dateControl.hasError('matTimepickerParse')) {\n <mat-error>This value is required.</mat-error>\n }\n\n @if (dateControl.hasError('matTimepickerParse')) {\n <mat-error>\n '{{dateControl.getError('matTimepickerParse')?.text}}' is invalid\n </mat-error>\n }\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{display:flex;flex-direction:row;gap:.5rem}.mat-form-field .mat-error{white-space:normal;line-height:1.5;max-height:none;padding:0}\n"] }]
391
+ }], propDecorators: { dataInfo: [{
392
+ type: Input
393
+ }], value: [{
394
+ type: Input
395
+ }], loading: [{
396
+ type: Input
397
+ }], readOnly: [{
398
+ type: Input
399
+ }], type: [{
400
+ type: Input
401
+ }], timeIncrementMinutes: [{
402
+ type: Input
403
+ }], valueChange: [{
404
+ type: Output
405
+ }] } });
406
+
407
+ class FkPickerComponent {
408
+ serverAccess;
409
+ dataInfo;
410
+ value;
411
+ readOnly = false;
412
+ foreignKeyInfo;
413
+ preloadThreshold = 50;
414
+ valueChanged = new EventEmitter();
415
+ searchControl = new FormControl('');
416
+ filteredOptions = [];
417
+ isLoading = true;
418
+ resolvedDisplayText = '';
419
+ selectedValue = '';
420
+ skipValueChanges = false;
421
+ searchSubject = new Subject();
422
+ subscriptions = [];
423
+ constructor(serverAccess) {
424
+ this.serverAccess = serverAccess;
425
+ }
426
+ get displayLabel() {
427
+ return this.dataInfo?.label || this.dataInfo?.column_friendly_name || this.dataInfo?.column_name || '';
428
+ }
429
+ ngOnInit() {
430
+ this.selectedValue = this.value ?? '';
431
+ if (this.readOnly) {
432
+ this.searchControl.disable();
433
+ this.resolveDisplayText();
434
+ }
435
+ else {
436
+ this.setupSearch();
437
+ this.loadInitialOptions();
438
+ }
439
+ this.isLoading = false;
440
+ }
441
+ ngOnChanges(changes) {
442
+ if (changes['value'] && !changes['value'].firstChange) {
443
+ this.skipValueChanges = true;
444
+ this.selectedValue = this.value ?? '';
445
+ if (this.readOnly) {
446
+ this.resolveDisplayText();
447
+ }
448
+ else {
449
+ this.updateSearchControlFromValue();
450
+ }
451
+ this.skipValueChanges = false;
452
+ }
453
+ }
454
+ ngOnDestroy() {
455
+ this.subscriptions.forEach(sub => sub.unsubscribe());
456
+ this.searchSubject.complete();
457
+ }
458
+ displayFn = (option) => {
459
+ if (typeof option === 'string')
460
+ return option;
461
+ return option?.display ?? '';
462
+ };
463
+ onOptionSelected(event) {
464
+ const selected = event.option.value;
465
+ this.selectedValue = selected.value;
466
+ this.valueChanged.emit(selected.value);
467
+ }
468
+ setupSearch() {
469
+ const searchSub = this.searchSubject.pipe(debounceTime(300), distinctUntilChanged(), switchMap(searchText => {
470
+ const tableName = this.foreignKeyInfo?.parent_table_name ?? '';
471
+ return this.serverAccess.getFkOptions(tableName, searchText, 50);
472
+ })).subscribe(response => {
473
+ this.filteredOptions = response.options;
474
+ });
475
+ this.subscriptions.push(searchSub);
476
+ const valueChangesSub = this.searchControl.valueChanges.subscribe(value => {
477
+ if (this.skipValueChanges)
478
+ return;
479
+ // If the user is typing (not selecting), trigger search
480
+ if (typeof value === 'string') {
481
+ this.searchSubject.next(value);
482
+ }
483
+ });
484
+ this.subscriptions.push(valueChangesSub);
485
+ }
486
+ loadInitialOptions() {
487
+ const tableName = this.foreignKeyInfo?.parent_table_name ?? '';
488
+ if (!tableName)
489
+ return;
490
+ this.serverAccess.getFkOptions(tableName, '', this.preloadThreshold).subscribe(response => {
491
+ this.filteredOptions = response.options;
492
+ this.updateSearchControlFromValue();
493
+ });
494
+ }
495
+ updateSearchControlFromValue() {
496
+ if (!this.selectedValue)
497
+ return;
498
+ const match = this.filteredOptions.find(o => o.value === this.selectedValue);
499
+ if (match) {
500
+ this.searchControl.setValue(match, { emitEvent: false });
501
+ }
502
+ else {
503
+ // Value not in loaded options; resolve display text
504
+ const tableName = this.foreignKeyInfo?.parent_table_name ?? '';
505
+ if (tableName) {
506
+ this.serverAccess.resolveFkDisplay(tableName, [this.selectedValue]).subscribe(response => {
507
+ const displayText = response.resolved[this.selectedValue] ?? this.selectedValue;
508
+ const syntheticOption = { value: this.selectedValue, display: displayText };
509
+ this.searchControl.setValue(syntheticOption, { emitEvent: false });
510
+ });
511
+ }
512
+ }
513
+ }
514
+ resolveDisplayText() {
515
+ if (!this.selectedValue || !this.foreignKeyInfo?.parent_table_name) {
516
+ this.resolvedDisplayText = this.selectedValue;
517
+ return;
518
+ }
519
+ this.serverAccess.resolveFkDisplay(this.foreignKeyInfo.parent_table_name, [this.selectedValue]).subscribe(response => {
520
+ this.resolvedDisplayText = response.resolved[this.selectedValue] ?? this.selectedValue;
521
+ });
522
+ }
523
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FkPickerComponent, deps: [{ token: HONUWARE_CRUD_ACCESS }], target: i0.ɵɵFactoryTarget.Component });
524
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: FkPickerComponent, isStandalone: true, selector: "hw-fk-picker", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly", foreignKeyInfo: "foreignKeyInfo", preloadThreshold: "preloadThreshold" }, outputs: { valueChanged: "valueChanged" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput [value]=\"resolvedDisplayText\" disabled>\n </mat-form-field>\n } @else {\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput\n [formControl]=\"searchControl\"\n [matAutocomplete]=\"auto\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\">\n <mat-autocomplete #auto=\"matAutocomplete\"\n panelWidth=\"auto\"\n [displayWith]=\"displayFn\"\n (optionSelected)=\"onOptionSelected($event)\">\n @for (option of filteredOptions; track option.value) {\n <mat-option [value]=\"option\">{{ option.display }}</mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { 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.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i4$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i3$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i4$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }] });
525
+ }
526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: FkPickerComponent, decorators: [{
527
+ type: Component,
528
+ args: [{ selector: 'hw-fk-picker', standalone: true, imports: [
529
+ ReactiveFormsModule,
530
+ MatFormFieldModule,
531
+ MatInputModule,
532
+ MatAutocompleteModule
533
+ ], template: "@if (isLoading) {\n<div class=\"loading\">Loading...</div>\n}\n\n@if (!isLoading) {\n<div class=\"form-fields\">\n @if (readOnly) {\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput [value]=\"resolvedDisplayText\" disabled>\n </mat-form-field>\n } @else {\n <mat-form-field>\n <mat-label>{{ displayLabel }}</mat-label>\n <input matInput\n [formControl]=\"searchControl\"\n [matAutocomplete]=\"auto\"\n [placeholder]=\"dataInfo?.place_holder ?? ''\">\n <mat-autocomplete #auto=\"matAutocomplete\"\n panelWidth=\"auto\"\n [displayWith]=\"displayFn\"\n (optionSelected)=\"onOptionSelected($event)\">\n @for (option of filteredOptions; track option.value) {\n <mat-option [value]=\"option\">{{ option.display }}</mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n }\n</div>\n}\n", styles: [".form-fields{width:100%;display:flex;flex-direction:row;gap:.5rem}mat-form-field{width:100%}\n"] }]
534
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
535
+ type: Inject,
536
+ args: [HONUWARE_CRUD_ACCESS]
537
+ }] }], propDecorators: { dataInfo: [{
538
+ type: Input
539
+ }], value: [{
540
+ type: Input
541
+ }], readOnly: [{
542
+ type: Input
543
+ }], foreignKeyInfo: [{
544
+ type: Input
545
+ }], preloadThreshold: [{
546
+ type: Input
547
+ }], valueChanged: [{
548
+ type: Output
549
+ }] } });
550
+
551
+ class CompositeControlComponent {
552
+ dataInfo;
553
+ value;
554
+ readOnly = false;
555
+ foreignKeyInfo;
556
+ valueChanged = new EventEmitter();
557
+ isLoading = true;
558
+ activeComponent = null;
559
+ ngOnChanges(changes) {
560
+ if (changes['dataInfo'] || changes['foreignKeyInfo']) {
561
+ this.isLoading = !this.dataInfo;
562
+ this.activeComponent = this.determineActiveComponent();
563
+ }
564
+ }
565
+ determineActiveComponent() {
566
+ // FK columns take priority when foreignKeyInfo is provided
567
+ if (this.foreignKeyInfo) {
568
+ return 'fk';
569
+ }
570
+ // Auto-detect bool columns even without explicit html_input_type
571
+ if (!this.dataInfo?.html_input_type && this.dataInfo?.type === 'bool') {
572
+ return 'bool';
573
+ }
574
+ switch (this.dataInfo?.html_input_type) {
575
+ case 'enum':
576
+ return 'enum';
577
+ case 'long-text':
578
+ return 'long-text';
579
+ case 'bool':
580
+ case 'checkbox':
581
+ return 'bool';
582
+ case 'date':
583
+ case 'time':
584
+ return 'date';
585
+ case 'text':
586
+ default:
587
+ // Default to text for unknown or unspecified types
588
+ return 'text';
589
+ }
590
+ }
591
+ onValueChanged(value) {
592
+ this.valueChanged.emit(value);
593
+ }
594
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: CompositeControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
595
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: CompositeControlComponent, isStandalone: true, selector: "hw-composite-control", inputs: { dataInfo: "dataInfo", value: "value", readOnly: "readOnly", foreignKeyInfo: "foreignKeyInfo" }, outputs: { valueChanged: "valueChanged" }, usesOnChanges: true, ngImport: i0, template: "@if (isLoading)\n{\n<div>Loading...</div>\n}\n\n@if (!isLoading)\n{\n @switch (activeComponent)\n {\n @case ('text')\n {\n<hw-simple-text [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-simple-text>\n }\n\n @case ('long-text')\n {\n<hw-long-text [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-long-text>\n }\n\n @case ('enum')\n {\n<hw-simple-enum [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (enumValueChange)=\"onValueChanged($event)\">\n</hw-simple-enum>\n }\n\n @case ('bool')\n {\n<hw-simple-bool [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (checkboxValueChange)=\"onValueChanged($event)\">\n</hw-simple-bool>\n }\n\n @case ('date')\n {\n<hw-simple-date [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChange)=\"onValueChanged($event)\">\n</hw-simple-date>\n }\n\n @case ('fk')\n {\n<hw-fk-picker [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n [foreignKeyInfo]=\"foreignKeyInfo\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-fk-picker>\n }\n\n @default\n {\n<div>\n Unsupported component type.\n</div>\n }\n }\n}\n", styles: [""], dependencies: [{ kind: "component", type: SimpleTextComponent, selector: "hw-simple-text", inputs: ["dataInfo", "value", "readOnly"], outputs: ["valueChanged"] }, { kind: "component", type: LongTextComponent, selector: "hw-long-text", inputs: ["dataInfo", "value", "readOnly"], outputs: ["valueChanged"] }, { kind: "component", type: SimpleBoolComponent, selector: "hw-simple-bool", inputs: ["dataInfo", "value", "readOnly"], outputs: ["checkboxValueChange"] }, { kind: "component", type: SimpleDateComponent, selector: "hw-simple-date", inputs: ["dataInfo", "value", "loading", "readOnly", "type", "timeIncrementMinutes"], outputs: ["valueChange"] }, { kind: "component", type: SimpleEnumComponent, selector: "hw-simple-enum", inputs: ["dataInfo", "value", "readOnly"], outputs: ["enumValueChange"] }, { kind: "component", type: FkPickerComponent, selector: "hw-fk-picker", inputs: ["dataInfo", "value", "readOnly", "foreignKeyInfo", "preloadThreshold"], outputs: ["valueChanged"] }] });
596
+ }
597
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: CompositeControlComponent, decorators: [{
598
+ type: Component,
599
+ args: [{ selector: 'hw-composite-control', standalone: true, imports: [SimpleTextComponent, LongTextComponent, SimpleBoolComponent, SimpleDateComponent, SimpleEnumComponent, FkPickerComponent], template: "@if (isLoading)\n{\n<div>Loading...</div>\n}\n\n@if (!isLoading)\n{\n @switch (activeComponent)\n {\n @case ('text')\n {\n<hw-simple-text [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-simple-text>\n }\n\n @case ('long-text')\n {\n<hw-long-text [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-long-text>\n }\n\n @case ('enum')\n {\n<hw-simple-enum [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (enumValueChange)=\"onValueChanged($event)\">\n</hw-simple-enum>\n }\n\n @case ('bool')\n {\n<hw-simple-bool [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (checkboxValueChange)=\"onValueChanged($event)\">\n</hw-simple-bool>\n }\n\n @case ('date')\n {\n<hw-simple-date [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n (valueChange)=\"onValueChanged($event)\">\n</hw-simple-date>\n }\n\n @case ('fk')\n {\n<hw-fk-picker [dataInfo]=\"dataInfo\"\n [value]=\"value\"\n [readOnly]=\"readOnly\"\n [foreignKeyInfo]=\"foreignKeyInfo\"\n (valueChanged)=\"onValueChanged($event)\">\n</hw-fk-picker>\n }\n\n @default\n {\n<div>\n Unsupported component type.\n</div>\n }\n }\n}\n" }]
600
+ }], propDecorators: { dataInfo: [{
601
+ type: Input
602
+ }], value: [{
603
+ type: Input
604
+ }], readOnly: [{
605
+ type: Input
606
+ }], foreignKeyInfo: [{
607
+ type: Input
608
+ }], valueChanged: [{
609
+ type: Output
610
+ }] } });
611
+
612
+ /*
613
+ * @honuware/ui/controls — schema-driven field controls (depends on foundation +
614
+ * access). The leaf fields (simple-text, long-text, simple-bool, simple-enum,
615
+ * simple-date), the composite-control type dispatcher, and the fk-picker
616
+ * autocomplete. Selectors use the `hw-` prefix.
617
+ */
618
+
619
+ /**
620
+ * Generated bundle index. Do not edit.
621
+ */
622
+
623
+ export { CompositeControlComponent, FkPickerComponent, LongTextComponent, SimpleBoolComponent, SimpleDateComponent, SimpleEnumComponent, SimpleTextComponent };
624
+ //# sourceMappingURL=honuware-ui-controls.mjs.map