@ngx-json-forms/primeng 1.0.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.
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/fesm2022/ngx-json-forms-primeng.mjs +650 -0
- package/fesm2022/ngx-json-forms-primeng.mjs.map +1 -0
- package/package.json +45 -0
- package/types/ngx-json-forms-primeng.d.ts +106 -0
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, output, inject, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/forms';
|
|
4
|
+
import { FormGroup, FormArray, ReactiveFormsModule } from '@angular/forms';
|
|
5
|
+
import { NgTemplateOutlet, NgComponentOutlet, NgOptimizedImage, NgClass } from '@angular/common';
|
|
6
|
+
import * as i2 from 'primeng/inputtext';
|
|
7
|
+
import { InputTextModule } from 'primeng/inputtext';
|
|
8
|
+
import * as i3 from 'primeng/inputgroup';
|
|
9
|
+
import { InputGroupModule } from 'primeng/inputgroup';
|
|
10
|
+
import * as i4 from 'primeng/inputgroupaddon';
|
|
11
|
+
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
|
|
12
|
+
import * as i5 from 'primeng/floatlabel';
|
|
13
|
+
import { FloatLabelModule } from 'primeng/floatlabel';
|
|
14
|
+
import * as i6 from 'primeng/select';
|
|
15
|
+
import { SelectModule } from 'primeng/select';
|
|
16
|
+
import * as i7 from 'primeng/multiselect';
|
|
17
|
+
import { MultiSelectModule } from 'primeng/multiselect';
|
|
18
|
+
import * as i8 from 'primeng/cascadeselect';
|
|
19
|
+
import { CascadeSelectModule } from 'primeng/cascadeselect';
|
|
20
|
+
import * as i9 from 'primeng/autocomplete';
|
|
21
|
+
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
22
|
+
import * as i10 from 'primeng/fileupload';
|
|
23
|
+
import { FileUploadModule } from 'primeng/fileupload';
|
|
24
|
+
import * as i11 from 'primeng/button';
|
|
25
|
+
import { ButtonModule } from 'primeng/button';
|
|
26
|
+
import { DialogModule } from 'primeng/dialog';
|
|
27
|
+
import * as i12 from 'primeng/divider';
|
|
28
|
+
import { DividerModule } from 'primeng/divider';
|
|
29
|
+
import * as i13 from 'primeng/password';
|
|
30
|
+
import { PasswordModule } from 'primeng/password';
|
|
31
|
+
import * as i14 from 'primeng/datepicker';
|
|
32
|
+
import { DatePickerModule } from 'primeng/datepicker';
|
|
33
|
+
import * as i15 from 'primeng/checkbox';
|
|
34
|
+
import { CheckboxModule } from 'primeng/checkbox';
|
|
35
|
+
import * as i16 from 'primeng/toggleswitch';
|
|
36
|
+
import { ToggleSwitchModule } from 'primeng/toggleswitch';
|
|
37
|
+
import * as i17 from 'primeng/textarea';
|
|
38
|
+
import { TextareaModule } from 'primeng/textarea';
|
|
39
|
+
import * as i18 from 'primeng/slider';
|
|
40
|
+
import { SliderModule } from 'primeng/slider';
|
|
41
|
+
import * as i19 from 'primeng/rating';
|
|
42
|
+
import { RatingModule } from 'primeng/rating';
|
|
43
|
+
import * as i20 from 'primeng/colorpicker';
|
|
44
|
+
import { ColorPickerModule } from 'primeng/colorpicker';
|
|
45
|
+
import * as i21 from 'primeng/radiobutton';
|
|
46
|
+
import { RadioButtonModule } from 'primeng/radiobutton';
|
|
47
|
+
import * as i22 from 'primeng/keyfilter';
|
|
48
|
+
import { KeyFilterModule } from 'primeng/keyfilter';
|
|
49
|
+
import * as i23 from 'primeng/editor';
|
|
50
|
+
import { EditorModule } from 'primeng/editor';
|
|
51
|
+
import { FormEngineService, ImageUploadService, FieldRegistry } from '@ngx-json-forms/core';
|
|
52
|
+
|
|
53
|
+
class NgxJsonFormComponent {
|
|
54
|
+
// ─── Inputs / Outputs ────────────────────────────────────────────────────
|
|
55
|
+
formTitle = input('', ...(ngDevMode ? [{ debugName: "formTitle" }] : /* istanbul ignore next */ []));
|
|
56
|
+
fieldsInput = input([], ...(ngDevMode ? [{ debugName: "fieldsInput" }] : /* istanbul ignore next */ []));
|
|
57
|
+
/** Optional schema input — supersedes `fieldsInput` when provided. */
|
|
58
|
+
schema = input(null, ...(ngDevMode ? [{ debugName: "schema" }] : /* istanbul ignore next */ []));
|
|
59
|
+
/** Only render fields in the given step indices (used by the stepper wrapper). */
|
|
60
|
+
stepFields = input(null, ...(ngDevMode ? [{ debugName: "stepFields" }] : /* istanbul ignore next */ []));
|
|
61
|
+
formSubmit = output();
|
|
62
|
+
formChange = output();
|
|
63
|
+
// ─── Services ────────────────────────────────────────────────────────────
|
|
64
|
+
formService = inject(FormEngineService);
|
|
65
|
+
uploadService = inject(ImageUploadService);
|
|
66
|
+
fieldRegistry = inject(FieldRegistry);
|
|
67
|
+
// ─── Internal State ──────────────────────────────────────────────────────
|
|
68
|
+
fields = signal([], ...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
|
|
69
|
+
formGroup = signal(new FormGroup({}), ...(ngDevMode ? [{ debugName: "formGroup" }] : /* istanbul ignore next */ []));
|
|
70
|
+
ready = signal(false, ...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
|
|
71
|
+
/** Async-loaded options keyed by formControlName */
|
|
72
|
+
asyncOptions = signal({}, ...(ngDevMode ? [{ debugName: "asyncOptions" }] : /* istanbul ignore next */ []));
|
|
73
|
+
formStatusTick = signal(0, ...(ngDevMode ? [{ debugName: "formStatusTick" }] : /* istanbul ignore next */ []));
|
|
74
|
+
focusedMap = signal({}, ...(ngDevMode ? [{ debugName: "focusedMap" }] : /* istanbul ignore next */ []));
|
|
75
|
+
/** Subscriptions for async option re-loads; disposed on every rebuild. */
|
|
76
|
+
optionLoaderSubs = [];
|
|
77
|
+
// ─── Derived ─────────────────────────────────────────────────────────────
|
|
78
|
+
visibleFields = computed(() => {
|
|
79
|
+
this.formStatusTick();
|
|
80
|
+
this.formService.patchTick();
|
|
81
|
+
const values = this.formGroup().getRawValue();
|
|
82
|
+
const source = this.stepFields() ?? this.fields();
|
|
83
|
+
return source.filter((f) => {
|
|
84
|
+
if (f.config.attributes.visible === false)
|
|
85
|
+
return false;
|
|
86
|
+
return this.formService.evaluateShowWhen(f, values);
|
|
87
|
+
});
|
|
88
|
+
}, ...(ngDevMode ? [{ debugName: "visibleFields" }] : /* istanbul ignore next */ []));
|
|
89
|
+
/**
|
|
90
|
+
* Track patchTick so .valid (a plain object property) re-reads after every
|
|
91
|
+
* form change. Without this, the submit-button disabled binding stays stuck
|
|
92
|
+
* on the FormGroup's initial (invalid) state.
|
|
93
|
+
*/
|
|
94
|
+
formValid = computed(() => {
|
|
95
|
+
this.formService.patchTick();
|
|
96
|
+
this.formStatusTick();
|
|
97
|
+
return this.formGroup().valid;
|
|
98
|
+
}, ...(ngDevMode ? [{ debugName: "formValid" }] : /* istanbul ignore next */ []));
|
|
99
|
+
placeholderVisibilityMap = {};
|
|
100
|
+
/**
|
|
101
|
+
* Resolve the placeholder string to render for a field. Safe for nested
|
|
102
|
+
* fields (repeater itemFields, group groupFields) whose formControlName
|
|
103
|
+
* isn't pre-registered in `placeholderVisibilityMap` — those fall back to
|
|
104
|
+
* the raw `field.placeholder` since they don't participate in floatLabel.
|
|
105
|
+
*/
|
|
106
|
+
placeholderFor(field) {
|
|
107
|
+
const name = field.formControlName;
|
|
108
|
+
if (!name)
|
|
109
|
+
return field.placeholder ?? null;
|
|
110
|
+
const sig = this.placeholderVisibilityMap[name];
|
|
111
|
+
if (!sig)
|
|
112
|
+
return field.placeholder ?? null;
|
|
113
|
+
return sig() ? (field.placeholder ?? null) : null;
|
|
114
|
+
}
|
|
115
|
+
errorMap = computed(() => {
|
|
116
|
+
this.formStatusTick();
|
|
117
|
+
this.formService.patchTick();
|
|
118
|
+
const errors = {};
|
|
119
|
+
const group = this.formGroup();
|
|
120
|
+
if (!group)
|
|
121
|
+
return errors;
|
|
122
|
+
for (const field of this.fields()) {
|
|
123
|
+
if (!field.formControlName)
|
|
124
|
+
continue;
|
|
125
|
+
const control = group.get(field.formControlName);
|
|
126
|
+
errors[field.formControlName] = this.formService.resolveError(field, control);
|
|
127
|
+
}
|
|
128
|
+
return errors;
|
|
129
|
+
}, ...(ngDevMode ? [{ debugName: "errorMap" }] : /* istanbul ignore next */ []));
|
|
130
|
+
// ─── Lifecycle ───────────────────────────────────────────────────────────
|
|
131
|
+
constructor() {
|
|
132
|
+
effect(() => {
|
|
133
|
+
this.ready.set(false);
|
|
134
|
+
const schemaIn = this.schema();
|
|
135
|
+
const incoming = schemaIn?.fields
|
|
136
|
+
? schemaIn.fields
|
|
137
|
+
: schemaIn?.steps
|
|
138
|
+
? schemaIn.steps.flatMap((s) => s.fields)
|
|
139
|
+
: this.fieldsInput();
|
|
140
|
+
if (!incoming.length)
|
|
141
|
+
return;
|
|
142
|
+
const sorted = [...incoming].sort((a, b) => {
|
|
143
|
+
const oa = a.layout?.order ?? Number.MAX_SAFE_INTEGER;
|
|
144
|
+
const ob = b.layout?.order ?? Number.MAX_SAFE_INTEGER;
|
|
145
|
+
return oa - ob;
|
|
146
|
+
});
|
|
147
|
+
this.fields.set(sorted);
|
|
148
|
+
this.buildForm(sorted, schemaIn ?? undefined);
|
|
149
|
+
});
|
|
150
|
+
effect(() => {
|
|
151
|
+
this.formService.patchTick();
|
|
152
|
+
if (!this.ready())
|
|
153
|
+
return;
|
|
154
|
+
this.fields.set(this.formService.fields());
|
|
155
|
+
this.uploadService.syncPreviews(this.fields(), this.formGroup());
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
// ─── Form Builder ────────────────────────────────────────────────────────
|
|
159
|
+
buildForm(fields, schema) {
|
|
160
|
+
// Tear down anything tied to the previous form group before we rebuild.
|
|
161
|
+
this.disposeOptionLoaderSubs();
|
|
162
|
+
this.placeholderVisibilityMap = {};
|
|
163
|
+
const group = this.formService.buildFormGroup(fields);
|
|
164
|
+
this.formGroup.set(group);
|
|
165
|
+
// Register synchronously so prior subs are disposed BEFORE we add new
|
|
166
|
+
// computed-field listeners below — otherwise register() would wipe them.
|
|
167
|
+
this.formService.register(group, fields, schema);
|
|
168
|
+
for (const field of fields) {
|
|
169
|
+
if (!field.formControlName)
|
|
170
|
+
continue;
|
|
171
|
+
this.placeholderVisibilityMap[field.formControlName] = computed(() => {
|
|
172
|
+
if (!field.floatLabel)
|
|
173
|
+
return true;
|
|
174
|
+
const control = this.formGroup()?.get(field.formControlName);
|
|
175
|
+
if (!control)
|
|
176
|
+
return false;
|
|
177
|
+
const v = control.value;
|
|
178
|
+
const hasValue = v !== null && v !== undefined && v !== '' && (!Array.isArray(v) || v.length > 0);
|
|
179
|
+
return this.focusedMap()[field.formControlName] === true && !hasValue;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (schema?.crossFieldValidators?.length) {
|
|
183
|
+
this.formService.applyCrossFieldValidators(group, schema.crossFieldValidators);
|
|
184
|
+
}
|
|
185
|
+
this.formService.setupComputedFields(group, fields);
|
|
186
|
+
// Bootstrap async options for select-like fields
|
|
187
|
+
for (const f of fields) {
|
|
188
|
+
const a = f.config.attributes;
|
|
189
|
+
if (a.optionsLoader && f.formControlName) {
|
|
190
|
+
void this.loadAsyncOptions(f);
|
|
191
|
+
for (const dep of a.optionsDependsOn ?? []) {
|
|
192
|
+
const depCtrl = group.get(dep);
|
|
193
|
+
if (!depCtrl)
|
|
194
|
+
continue;
|
|
195
|
+
this.optionLoaderSubs.push(depCtrl.valueChanges.subscribe(() => void this.loadAsyncOptions(f)));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
queueMicrotask(() => {
|
|
200
|
+
this.ready.set(true);
|
|
201
|
+
this.uploadService.syncPreviews(this.fields(), this.formGroup());
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
disposeOptionLoaderSubs() {
|
|
205
|
+
for (const s of this.optionLoaderSubs)
|
|
206
|
+
s.unsubscribe();
|
|
207
|
+
this.optionLoaderSubs = [];
|
|
208
|
+
}
|
|
209
|
+
async loadAsyncOptions(field) {
|
|
210
|
+
const a = field.config.attributes;
|
|
211
|
+
if (!a.optionsLoader || !field.formControlName)
|
|
212
|
+
return;
|
|
213
|
+
const formValue = this.formGroup().getRawValue();
|
|
214
|
+
const context = {};
|
|
215
|
+
for (const dep of a.optionsDependsOn ?? [])
|
|
216
|
+
context[dep] = formValue[dep];
|
|
217
|
+
this.formService.updateFieldAttributes(field.formControlName, { loading: true });
|
|
218
|
+
const opts = await this.formService.resolveDependentOptions(a.optionsLoader, context, formValue);
|
|
219
|
+
this.asyncOptions.update((m) => ({ ...m, [field.formControlName]: opts }));
|
|
220
|
+
this.formService.updateFieldAttributes(field.formControlName, { loading: false, options: opts });
|
|
221
|
+
}
|
|
222
|
+
// ─── Field Registry resolver (used by custom inputType) ──────────────────
|
|
223
|
+
customRenderer(field) {
|
|
224
|
+
return this.fieldRegistry.getRenderer(field.config.attributes.inputType);
|
|
225
|
+
}
|
|
226
|
+
customRendererInputs(field) {
|
|
227
|
+
return { field, formGroup: this.formGroup() };
|
|
228
|
+
}
|
|
229
|
+
// ─── Date helpers ────────────────────────────────────────────────────────
|
|
230
|
+
minDateFor(field) {
|
|
231
|
+
const a = field.config.attributes;
|
|
232
|
+
if (a.minDate)
|
|
233
|
+
return a.minDate;
|
|
234
|
+
if (a.minToday) {
|
|
235
|
+
const d = new Date();
|
|
236
|
+
d.setDate(d.getDate() + (a.minOffsetDays ?? 0));
|
|
237
|
+
return d;
|
|
238
|
+
}
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
maxDateFor(field) {
|
|
242
|
+
const a = field.config.attributes;
|
|
243
|
+
if (a.maxDate)
|
|
244
|
+
return a.maxDate;
|
|
245
|
+
if (a.maxToday) {
|
|
246
|
+
const d = new Date();
|
|
247
|
+
d.setDate(d.getDate() + (a.maxOffsetDays ?? 0));
|
|
248
|
+
return d;
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
// ─── Effective options resolver ──────────────────────────────────────────
|
|
253
|
+
optionsFor(field) {
|
|
254
|
+
const a = field.config.attributes;
|
|
255
|
+
if (field.formControlName && this.asyncOptions()[field.formControlName]) {
|
|
256
|
+
return this.asyncOptions()[field.formControlName];
|
|
257
|
+
}
|
|
258
|
+
return a.options ?? [];
|
|
259
|
+
}
|
|
260
|
+
// ─── Repeater helpers ────────────────────────────────────────────────────
|
|
261
|
+
getArray(name) {
|
|
262
|
+
const c = this.formGroup().get(name);
|
|
263
|
+
return c instanceof FormArray ? c : null;
|
|
264
|
+
}
|
|
265
|
+
addRepeaterRow(field) {
|
|
266
|
+
if (!field.formControlName)
|
|
267
|
+
return;
|
|
268
|
+
const arr = this.getArray(field.formControlName);
|
|
269
|
+
if (!arr)
|
|
270
|
+
return;
|
|
271
|
+
if (field.config.attributes.maxRows && arr.length >= field.config.attributes.maxRows)
|
|
272
|
+
return;
|
|
273
|
+
this.formService.addArrayItem(field.formControlName);
|
|
274
|
+
this.triggerTick();
|
|
275
|
+
}
|
|
276
|
+
removeRepeaterRow(field, i) {
|
|
277
|
+
if (!field.formControlName)
|
|
278
|
+
return;
|
|
279
|
+
const arr = this.getArray(field.formControlName);
|
|
280
|
+
if (!arr)
|
|
281
|
+
return;
|
|
282
|
+
if (field.config.attributes.minRows && arr.length <= field.config.attributes.minRows)
|
|
283
|
+
return;
|
|
284
|
+
this.formService.removeArrayItem(field.formControlName, i);
|
|
285
|
+
this.triggerTick();
|
|
286
|
+
}
|
|
287
|
+
rowGroup(field, i) {
|
|
288
|
+
return this.getArray(field.formControlName)?.at(i);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* DOM id for a field's input element. Scoped by row index when the field
|
|
292
|
+
* lives inside a repeater so the same `formControlName` across rows
|
|
293
|
+
* doesn't produce duplicate ids (HTML spec violation + breaks
|
|
294
|
+
* <label for>, aria-describedby, and document.querySelector lookups).
|
|
295
|
+
*/
|
|
296
|
+
inputId(field, suffix) {
|
|
297
|
+
const base = (field.formControlName ?? '') + 'Id';
|
|
298
|
+
return suffix !== undefined && suffix !== null ? `${base}_${suffix}` : base;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Resolve the validation message for a single field inside a repeater row.
|
|
302
|
+
* Mirrors errorMap() but for FormGroup rows that aren't tracked in the
|
|
303
|
+
* top-level fields signal.
|
|
304
|
+
*/
|
|
305
|
+
resolveRowError(row, sub) {
|
|
306
|
+
this.formService.patchTick();
|
|
307
|
+
if (!sub.formControlName)
|
|
308
|
+
return null;
|
|
309
|
+
const ctrl = row.get(sub.formControlName);
|
|
310
|
+
return this.formService.resolveError(sub, ctrl);
|
|
311
|
+
}
|
|
312
|
+
// ─── Events ──────────────────────────────────────────────────────────────
|
|
313
|
+
/** Central event handler. Accepts `unknown` because PrimeNG emits custom event objects. */
|
|
314
|
+
async onEvent(field, event, eventType) {
|
|
315
|
+
this.triggerTick();
|
|
316
|
+
const rawType = eventType ?? event?.type;
|
|
317
|
+
let type = rawType;
|
|
318
|
+
if (type === 'focus')
|
|
319
|
+
this.focusedMap.update((m) => ({ ...m, [field.formControlName]: true }));
|
|
320
|
+
if (type === 'blur')
|
|
321
|
+
this.focusedMap.update((m) => ({ ...m, [field.formControlName]: false }));
|
|
322
|
+
if (type === 'uploadHandler') {
|
|
323
|
+
await this.uploadService.handleUpload(field, event, this.formGroup(), this.formService, () => this.emitChange(field, 'uploadHandler', event));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (type === 'inputKeydown' && field.config.attributes.inputType === 'autocomplete') {
|
|
327
|
+
const ke = event;
|
|
328
|
+
if (ke.key === 'Enter') {
|
|
329
|
+
const inputValue = ke.target.value?.trim();
|
|
330
|
+
if (inputValue) {
|
|
331
|
+
const tag = {
|
|
332
|
+
[field.config.attributes.optionLabel]: inputValue,
|
|
333
|
+
[field.config.attributes.optionValue]: inputValue,
|
|
334
|
+
};
|
|
335
|
+
const existing = [...(field.config.attributes.suggestions ?? []), tag];
|
|
336
|
+
this.formService.updateFieldAttributes(field.formControlName, { suggestions: existing });
|
|
337
|
+
this.formGroup().get(field.formControlName)?.setValue(existing);
|
|
338
|
+
type = 'add';
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (type === 'unselect' && field.config.attributes.inputType === 'autocomplete') {
|
|
343
|
+
const evtValue = event.value;
|
|
344
|
+
const remaining = (field.config.attributes.suggestions ?? []).filter((v) => evtValue !== v);
|
|
345
|
+
this.formService.updateFieldAttributes(field.formControlName, { suggestions: remaining });
|
|
346
|
+
this.formGroup().get(field.formControlName)?.setValue(remaining);
|
|
347
|
+
}
|
|
348
|
+
const allowed = field.config.attributes.acceptedEvents ?? [];
|
|
349
|
+
if (!allowed.includes(type))
|
|
350
|
+
return;
|
|
351
|
+
const payload = this.buildPayload(field, type, event);
|
|
352
|
+
if (type === 'click') {
|
|
353
|
+
const role = field.config.attributes.buttonRole;
|
|
354
|
+
if (role === 'reset') {
|
|
355
|
+
this.formService.reset();
|
|
356
|
+
this.formChange.emit(payload);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (role === 'cancel' || role === 'custom') {
|
|
360
|
+
this.formChange.emit(payload);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (!this.formValid())
|
|
364
|
+
this.formGroup().markAllAsTouched();
|
|
365
|
+
this.formSubmit.emit({ ...payload, values: this.formService.buildSubmitPayload() });
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
this.formChange.emit(payload);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
removeImage(field, image) {
|
|
372
|
+
this.uploadService.removeImage(field, image, this.formGroup(), this.formService, () => this.emitChange(field, 'uploadHandler', new Event('remove')));
|
|
373
|
+
}
|
|
374
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
375
|
+
buildPayload(field, type, originalEvent) {
|
|
376
|
+
return {
|
|
377
|
+
field,
|
|
378
|
+
values: this.formGroup().getRawValue(),
|
|
379
|
+
valid: this.formValid(),
|
|
380
|
+
type,
|
|
381
|
+
originalEvent,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
emitChange(field, type, event) {
|
|
385
|
+
this.formChange.emit(this.buildPayload(field, type, event));
|
|
386
|
+
}
|
|
387
|
+
triggerTick() {
|
|
388
|
+
this.formStatusTick.update((v) => v + 1);
|
|
389
|
+
}
|
|
390
|
+
getControl(name) {
|
|
391
|
+
return this.formGroup().get(name);
|
|
392
|
+
}
|
|
393
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: NgxJsonFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
394
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: NgxJsonFormComponent, isStandalone: true, selector: "ngx-json-form", inputs: { formTitle: { classPropertyName: "formTitle", publicName: "formTitle", isSignal: true, isRequired: false, transformFunction: null }, fieldsInput: { classPropertyName: "fieldsInput", publicName: "fieldsInput", isSignal: true, isRequired: false, transformFunction: null }, schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: false, transformFunction: null }, stepFields: { classPropertyName: "stepFields", publicName: "stepFields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formSubmit: "formSubmit", formChange: "formChange" }, ngImport: i0, template: "@if (formTitle().length) {\n <div class=\"ngx-form-title\">{{ formTitle() }}</div>\n}\n\n@if (ready()) {\n <form [formGroup]=\"formGroup()\" class=\"ngx-form-grid\">\n @for (field of visibleFields(); track field.formControlName ?? $index) {\n <div\n [class]=\"\n 'ngx-col-' +\n (field.layout?.columnSpan ?? 12) +\n ' ' +\n (field.layout?.wrapperClass ?? '')\n \"\n [style]=\"field.layout?.wrapperStyle ?? {}\"\n [style.display]=\"field.config.attributes.isHidden ? 'none' : 'block'\"\n >\n <!-- Float Label wrapper -->\n @if (field.floatLabel) {\n <p-floatlabel [variant]=\"field.floatVariant ?? 'on'\">\n <div class=\"ngx-field-inner\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: field, formGroup: formGroup() }\"\n />\n </div>\n <label\n [attr.for]=\"field.formControlName + 'Id'\"\n [attr.id]=\"field.formControlName + 'Label'\"\n >\n @if (field.labelIconPos === 'left') {\n <i [class]=\"field.labelIcon\"></i>\n }\n {{ field.label }}\n @if (field.labelIconPos === 'right') {\n <i [class]=\"field.labelIcon\"></i>\n }\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n </p-floatlabel>\n }\n\n <!-- Toggle card layout -->\n @else if (\n field.config.attributes.cardLayout &&\n field.config.attributes.inputType === 'toggle'\n ) {\n <div\n class=\"ngx-toggle-card\"\n [style.--toggle-color]=\"field.config.attributes.cardIconColor\"\n >\n <div\n class=\"ngx-toggle-card-icon\"\n [style.background]=\"\n field.config.attributes.cardIconBg ??\n 'var(--p-primary-50, #eff6ff)'\n \"\n [style.color]=\"\n field.config.attributes.cardIconColor ??\n 'var(--p-primary-500, #3b82f6)'\n \"\n >\n <i [class]=\"field.config.attributes.cardIcon ?? 'pi pi-bell'\"></i>\n </div>\n <div class=\"ngx-toggle-card-body\">\n <span class=\"ngx-toggle-card-label\">\n {{ field.label }}\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </span>\n @if (field.config.attributes.info?.length) {\n <span\n class=\"ngx-toggle-card-desc\"\n [innerHTML]=\"field.config.attributes.info\"\n ></span>\n }\n </div>\n <p-toggleswitch\n [formControlName]=\"field.formControlName!\"\n [inputId]=\"field.formControlName + 'Id'\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n </div>\n <!--\n Always reserve one line of space for the error so the row height\n doesn't change when validation fires (otherwise sibling fields\n jump down when the error appears).\n -->\n @if (field.validations?.rules) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!errorMap()[field.formControlName!]\"\n [attr.id]=\"field.formControlName + 'Err'\"\n >{{ errorMap()[field.formControlName!] || '\u00A0' }}</small>\n }\n }\n\n <!-- Normal label wrapper -->\n @else {\n @if (field.label && field.label.length) {\n <label\n class=\"ngx-field-label\"\n [attr.for]=\"field.formControlName + 'Id'\"\n [attr.id]=\"field.formControlName + 'Label'\"\n >\n @if (field.labelIconPos === 'left') {\n <i [class]=\"field.labelIcon\"></i>\n }\n {{ field.label }}\n @if (field.labelIconPos === 'right') {\n <i [class]=\"field.labelIcon\"></i>\n }\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n }\n <div class=\"ngx-field-inner\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: field, formGroup: formGroup() }\"\n />\n </div>\n\n <!--\n Validation error \u2014 always reserve one line of space (placeholder\n class makes it invisible when there's no error) so triggering a\n required/pattern message doesn't push the row below it down.\n -->\n @if (field.validations?.rules) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!errorMap()[field.formControlName!]\"\n [attr.id]=\"field.formControlName + 'Err'\"\n >{{ errorMap()[field.formControlName!] || '\u00A0' }}</small>\n }\n\n <!-- Info / hint -->\n @if (field.config.attributes.info?.length) {\n <small\n class=\"ngx-hint\"\n [attr.id]=\"field.formControlName + 'Hint'\"\n [innerHTML]=\"field.config.attributes.info\"\n ></small>\n }\n }\n </div>\n }\n </form>\n}\n\n<!-- \u2500\u2500\u2500 Field Renderer Template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<!--\n `formGroup` is passed in via the template context so each rendering site\n binds the right group: the root FormGroup for top-level fields, the row's\n FormGroup for repeater rows. Hard-coding `formGroup()` here would override\n row-level bindings and route nested formControlName lookups to the root,\n which is the bug we're fixing.\n\n Known issue: during initial CD passes Angular logs NG01050 spam because\n the FormGroup directive on this ng-container materialises after children\n formControlName directives query their parent ControlContainer. Bindings\n recover and form values flow correctly afterwards. Cleaner fix would be\n to avoid the ngTemplateOutlet + context + nested formGroup combination\n altogether (e.g. inline the @switch at each call site).\n-->\n<ng-template #fieldTpl let-field let-fg=\"formGroup\" let-idSuffix=\"idSuffix\">\n <ng-container [formGroup]=\"fg\">\n @switch (field.config.attributes.inputType) {\n <!-- \u2500\u2500 Custom field (registry) \u2500\u2500 -->\n @case (customRenderer(field) ? field.config.attributes.inputType : '__never__') {\n <ng-container\n *ngComponentOutlet=\"customRenderer(field)!; inputs: customRendererInputs(field)\"\n />\n }\n\n <!-- \u2500\u2500 Group (nested FormGroup) \u2500\u2500 -->\n @case ('group') {\n <fieldset\n class=\"ngx-field-group\"\n [attr.formGroupName]=\"field.formControlName\"\n >\n @for (sub of field.config.attributes.groupFields ?? []; track sub.formControlName ?? $index) {\n <div class=\"ngx-field-group-row\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: sub, formGroup: formGroup() }\"\n />\n </div>\n }\n </fieldset>\n }\n\n <!-- \u2500\u2500 Repeater (FormArray) \u2500\u2500 -->\n @case ('repeater') {\n <div class=\"ngx-repeater\">\n @for (row of getArray(field.formControlName!)?.controls ?? []; track $index) {\n @let rowIndex = $index;\n <div class=\"ngx-repeater-row\" [formGroup]=\"$any(row)\">\n <div class=\"ngx-repeater-row-fields\">\n @for (sub of field.config.attributes.itemFields ?? []; track sub.formControlName ?? $index) {\n <div\n [class]=\"\n 'ngx-col-' + (sub.layout?.columnSpan ?? 12)\n \"\n >\n @if (sub.label) {\n <label\n class=\"ngx-field-label\"\n [attr.for]=\"inputId(sub, rowIndex)\"\n >\n {{ sub.label }}\n @if (sub.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n }\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: sub, formGroup: $any(row), idSuffix: rowIndex }\"\n />\n @if (sub.validations?.rules && sub.formControlName) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!resolveRowError($any(row), sub)\"\n >{{ resolveRowError($any(row), sub) || '\u00A0' }}</small>\n }\n </div>\n }\n </div>\n <button\n type=\"button\"\n class=\"ngx-repeater-remove\"\n pButton\n [icon]=\"'pi pi-trash'\"\n [rounded]=\"true\"\n [text]=\"true\"\n (click)=\"removeRepeaterRow(field, $index)\"\n ></button>\n </div>\n }\n <button\n pButton\n type=\"button\"\n class=\"ngx-repeater-add\"\n [icon]=\"'pi pi-plus'\"\n [label]=\"field.config.attributes.addLabel ?? 'Add row'\"\n [text]=\"true\"\n (click)=\"addRepeaterRow(field)\"\n ></button>\n </div>\n }\n\n <!-- \u2500\u2500 Dependent / Cascading Dropdown \u2500\u2500 -->\n @case ('dependentDropdown') {\n <p-cascadeselect\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel ?? 'label'\"\n [optionValue]=\"field.config.attributes.optionValue ?? 'value'\"\n [optionGroupLabel]=\"field.config.attributes.optionGroupLabel ?? 'label'\"\n [optionGroupChildren]=\"\n $any(field.config.attributes.optionGroupChildren ?? ['children'])\n \"\n [placeholder]=\"field.placeholder ?? ''\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onShow)=\"onEvent(field, $event, 'show')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n />\n }\n\n <!-- \u2500\u2500 Editor (rich text) \u2500\u2500 -->\n @case ('editor') {\n <p-editor\n [formControlName]=\"field.formControlName!\"\n [style]=\"{ height: (field.config.attributes['height'] ?? '180px') }\"\n (onTextChange)=\"onEvent(field, $event, 'change')\"\n ></p-editor>\n }\n\n <!-- \u2500\u2500 Confirm password \u2500\u2500 -->\n @case ('confirmPassword') {\n <p-password\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [feedback]=\"false\"\n [toggleMask]=\"field.config.attributes.toggleMask ?? true\"\n [placeholder]=\"field.placeholder ?? ''\"\n appendTo=\"body\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n />\n }\n\n <!-- \u2500\u2500 File Upload \u2500\u2500 -->\n @case ('fileUpload') {\n <div>\n <div\n [class]=\"field.config.attributes.isInline ? 'ngx-file-inline' : ''\"\n >\n <p-fileUpload\n mode=\"basic\"\n customUpload\n [id]=\"inputId(field, idSuffix)\"\n [multiple]=\"field.config.attributes.multiple\"\n [chooseIcon]=\"field.config.attributes.chooseIcon ?? 'pi pi-upload'\"\n [accept]=\"field.config.attributes.accept ?? 'image/*'\"\n [maxFileSize]=\"field.config.attributes.maxFileSize ?? 1000000\"\n [auto]=\"true\"\n [chooseLabel]=\"field.config.attributes.chooseLabel ?? 'Upload'\"\n (uploadHandler)=\"onEvent(field, $event, 'uploadHandler')\"\n />\n\n @if (uploadService.imagePreviews()[field.formControlName!]?.length) {\n <div class=\"ngx-image-list\">\n @for (\n image of uploadService.imagePreviews()[field.formControlName!];\n let i = $index;\n track i\n ) {\n <div class=\"ngx-image-card\">\n <i\n class=\"pi pi-times ngx-image-remove\"\n (click)=\"removeImage(field, image)\"\n ></i>\n <div class=\"ngx-image-wrapper\">\n @if (!uploadService.isBase64(image)) {\n <img\n fill\n sizes=\"100\"\n [ngSrc]=\"image\"\n (load)=\"uploadService.onLoad(image)\"\n (error)=\"uploadService.onLoad(image)\"\n [class.loading]=\"uploadService.isLoading(image)\"\n [class.loaded]=\"!uploadService.isLoading(image)\"\n class=\"ngx-preview-img\"\n alt=\"preview\"\n />\n } @else {\n <img\n fill\n sizes=\"100\"\n [src]=\"image\"\n (load)=\"uploadService.onLoad(image)\"\n (error)=\"uploadService.onLoad(image)\"\n [class.loading]=\"uploadService.isLoading(image)\"\n [class.loaded]=\"!uploadService.isLoading(image)\"\n class=\"ngx-preview-img\"\n alt=\"preview\"\n />\n }\n @if (uploadService.isLoading(image)) {\n <div class=\"ngx-img-skeleton\"></div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- \u2500\u2500 Static Text \u2500\u2500 -->\n @case ('staticText') {\n <span\n (click)=\"onEvent(field, $event, 'staticTextClick')\"\n [innerHTML]=\"field.config.attributes.value\"\n ></span>\n }\n\n <!-- \u2500\u2500 Divider \u2500\u2500 -->\n @case ('divider') {\n <p-divider\n [layout]=\"field.config.attributes.dividerLayout\"\n [type]=\"field.config.attributes.dividerType\"\n [align]=\"field.config.attributes.dividerAlign\"\n >\n @if (field.config.attributes.value) {\n <span [innerHTML]=\"field.config.attributes.value\"></span>\n }\n </p-divider>\n }\n\n <!-- \u2500\u2500 Button \u2500\u2500 -->\n @case ('button') {\n <div class=\"ngx-btn-wrap\">\n <button\n pButton\n type=\"button\"\n [id]=\"inputId(field, idSuffix)\"\n [label]=\"field.btnLabel ?? ''\"\n [icon]=\"field.config.attributes.icon ?? ''\"\n [iconPos]=\"field.config.attributes.iconPosition ?? 'left'\"\n [tabindex]=\"field.tabIndex ?? 0\"\n [disabled]=\"\n field.config.attributes.buttonRole === 'submit' ||\n field.config.attributes.type === 'submit'\n ? !formValid()\n : !!field.config.attributes.disabled\n \"\n [class.p-button-outlined]=\"\n field.config.attributes.variant === 'secondary'\n \"\n [class.p-button-text]=\"field.config.attributes.text === true\"\n [class.p-button-rounded]=\"field.config.attributes.rounded === true\"\n [class.p-button-sm]=\"field.config.attributes.size === 'sm'\"\n [class.p-button-lg]=\"field.config.attributes.size === 'lg'\"\n (click)=\"onEvent(field, $event)\"\n ></button>\n </div>\n }\n\n <!-- \u2500\u2500 Everything else inside p-inputgroup \u2500\u2500 -->\n @default {\n <p-inputgroup>\n @if (\n field.config.attributes.fieldPos === 'left' &&\n field.config.attributes.fieldIcon\n ) {\n <p-inputgroup-addon>\n <i [class]=\"field.config.attributes.fieldIcon\">\n {{ field.config.attributes.fieldIconText ?? '' }}\n </i>\n </p-inputgroup-addon>\n }\n\n @switch (field.config.attributes.inputType) {\n <!-- text / email / number / url -->\n @case ('text') {\n <input\n pInputText\n [id]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [type]=\"field.config.attributes.type ?? 'text'\"\n [tabindex]=\"field.tabIndex ?? 0\"\n [attr.placeholder]=\"placeholderFor(field)\"\n [attr.aria-describedby]=\"\n (errorMap()[field.formControlName!] ? field.formControlName + 'Err ' : '') +\n (field.config.attributes.info ? field.formControlName + 'Hint' : '')\n \"\n [pKeyFilter]=\"field.config.attributes.keyfilter\"\n (change)=\"onEvent(field, $event)\"\n (input)=\"onEvent(field, $event)\"\n (focus)=\"onEvent(field, $event)\"\n (blur)=\"onEvent(field, $event)\"\n (keyup)=\"onEvent(field, $event)\"\n (keydown)=\"onEvent(field, $event)\"\n (keypress)=\"onEvent(field, $event)\"\n />\n }\n\n <!-- password -->\n @case ('password') {\n <p-password\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [feedback]=\"field.config.attributes.feedback\"\n [toggleMask]=\"field.config.attributes.toggleMask\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n appendTo=\"body\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n >\n @if (field.config.attributes.templateHeader) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.templateHeader\"\n />\n }\n @if (field.config.attributes.templateFooter) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.templateFooter\"\n />\n }\n </p-password>\n }\n\n <!-- textarea -->\n @case ('textarea') {\n <textarea\n pTextarea\n [id]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [rows]=\"field.config.attributes.rows ?? 3\"\n [cols]=\"field.config.attributes.cols ?? 30\"\n [autoResize]=\"field.config.attributes.autoResize\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n (change)=\"onEvent(field, $event)\"\n (input)=\"onEvent(field, $event)\"\n (focus)=\"onEvent(field, $event)\"\n (blur)=\"onEvent(field, $event)\"\n >\n </textarea>\n }\n\n <!-- select -->\n @case ('select') {\n <p-select\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [attr.aria-labelledby]=\"field.formControlName + 'Label'\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [optionValue]=\"field.config.attributes.optionValue\"\n [placeholder]=\"placeholderFor(field) ?? ''\"\n [showClear]=\"field.config.attributes.showClear\"\n [filter]=\"field.config.attributes.filter\"\n [filterBy]=\"field.config.attributes.filterBy\"\n [filterPlaceholder]=\"field.config.attributes.filterPlaceholder\"\n [loading]=\"field.config.attributes.loading\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [lazy]=\"field.config.attributes.lazy\"\n [emptyMessage]=\"field.config.attributes.emptyMessage\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onShow)=\"onEvent(field, $event, 'show')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onLazyLoad)=\"onEvent(field, $event, 'lazyLoad')\"\n >\n @if (\n field.config.attributes.isTemplate &&\n field.config.attributes.template\n ) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.template\"\n />\n }\n </p-select>\n }\n\n <!-- multiSelect -->\n @case ('multiSelect') {\n <p-multiselect\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [optionValue]=\"field.config.attributes.optionValue\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [filter]=\"field.config.attributes.filter\"\n [showClear]=\"field.config.attributes.showClear\"\n [selectionLimit]=\"field.config.attributes.selectionLimit\"\n [display]=\"field.config.attributes.display\"\n [loading]=\"field.config.attributes.loading\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [scrollHeight]=\"field.config.attributes.scrollHeight\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n (onRemove)=\"onEvent(field, $event, 'remove')\"\n (onSelectAll)=\"onEvent(field, $event, 'select')\"\n >\n </p-multiselect>\n }\n\n <!-- autocomplete -->\n @case ('autocomplete') {\n <p-autocomplete\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [suggestions]=\"field.config.attributes.suggestions\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [multiple]=\"field.config.attributes.multiple\"\n [forceSelection]=\"field.config.attributes.forceSelection\"\n [dropdown]=\"field.config.attributes.dropdown\"\n [showClear]=\"field.config.attributes.showClear\"\n [completeOnFocus]=\"field.config.attributes.completeOnFocus\"\n [minLength]=\"field.config.attributes.minLength ?? 1\"\n [delay]=\"field.config.attributes.delay ?? 300\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [scrollHeight]=\"field.config.attributes.scrollHeight\"\n appendTo=\"body\"\n (completeMethod)=\"onEvent(field, $event, 'complete')\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n (onUnselect)=\"onEvent(field, $event, 'unselect')\"\n (onAdd)=\"onEvent(field, $event, 'add')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onInputKeydown)=\"onEvent(field, $event, 'inputKeydown')\"\n >\n </p-autocomplete>\n }\n\n <!-- toggle -->\n @case ('toggle') {\n <p-toggleswitch\n [formControlName]=\"field.formControlName!\"\n [inputId]=\"inputId(field, idSuffix)\"\n [attr.aria-labelledby]=\"field.formControlName + 'Label'\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- checkbox -->\n @case ('checkbox') {\n <p-checkbox\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [name]=\"field.config.attributes.name ?? field.formControlName!\"\n [value]=\"field.config.attributes.value\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- radio -->\n @case ('radio') {\n @for (opt of $any(optionsFor(field)); track $index) {\n <div class=\"ngx-radio-item\">\n <p-radiobutton\n [inputId]=\"field.formControlName + '_' + $index\"\n [formControlName]=\"field.formControlName!\"\n [name]=\"field.formControlName!\"\n [value]=\"\n opt[field.config.attributes.optionValue ?? 'value']\n \"\n (onClick)=\"onEvent(field, $event, 'change')\"\n />\n <label [for]=\"field.formControlName + '_' + $index\">\n {{ opt[field.config.attributes.optionLabel ?? 'label'] }}\n </label>\n </div>\n }\n }\n\n <!-- datePicker / time / month / year -->\n @case ('datePicker') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"field.config.attributes.showIcon\"\n [minDate]=\"minDateFor(field)!\"\n [maxDate]=\"maxDateFor(field)!\"\n [selectionMode]=\"$any(field.config.attributes.selectionMode)\"\n [readonlyInput]=\"field.config.attributes.readonlyInput\"\n [showButtonBar]=\"field.config.attributes.showButtonBar\"\n [showTime]=\"field.config.attributes.showTime\"\n [hourFormat]=\"field.config.attributes.hourFormat\"\n [timeOnly]=\"field.config.attributes.timeOnly\"\n [view]=\"$any(field.config.attributes.view)\"\n [dateFormat]=\"field.config.attributes.dateFormat\"\n [numberOfMonths]=\"field.config.attributes.numberOfMonths ?? 1\"\n [showClear]=\"field.config.attributes.showClear\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n >\n </p-datepicker>\n }\n\n @case ('time') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [iconDisplay]=\"'input'\"\n [timeOnly]=\"true\"\n [showTime]=\"true\"\n [hourFormat]=\"field.config.attributes.hourFormat ?? '24'\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n @case ('month') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [view]=\"'month'\"\n [dateFormat]=\"field.config.attributes.dateFormat ?? 'mm/yy'\"\n [readonlyInput]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n @case ('year') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [view]=\"'year'\"\n [dateFormat]=\"field.config.attributes.dateFormat ?? 'yy'\"\n [readonlyInput]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n <!-- slider -->\n @case ('slider') {\n <p-slider\n [formControlName]=\"field.formControlName!\"\n [min]=\"field.config.attributes.min ?? 0\"\n [max]=\"field.config.attributes.max ?? 100\"\n [step]=\"field.config.attributes.step ?? 1\"\n [range]=\"field.config.attributes.range\"\n [orientation]=\"\n field.config.attributes.orientation ?? 'horizontal'\n \"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- rating -->\n @case ('rating') {\n <p-rating\n [formControlName]=\"field.formControlName!\"\n [stars]=\"field.config.attributes.stars ?? 5\"\n (onRate)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- colorPicker -->\n @case ('colorPicker') {\n <p-colorpicker\n [formControlName]=\"field.formControlName!\"\n [inline]=\"field.config.attributes.inline\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n }\n\n @if (\n field.config.attributes.fieldPos === 'right' &&\n field.config.attributes.fieldIcon\n ) {\n <p-inputgroup-addon>\n <i [class]=\"field.config.attributes.fieldIcon\">\n {{ field.config.attributes.fieldIconText ?? '' }}\n </i>\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n }\n }\n </ng-container>\n</ng-template>\n", styles: [".ngx-form-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:1.25rem}.ngx-col-1{grid-column:span 1;min-width:0}.ngx-col-2{grid-column:span 2;min-width:0}.ngx-col-3{grid-column:span 3;min-width:0}.ngx-col-4{grid-column:span 4;min-width:0}.ngx-col-5{grid-column:span 5;min-width:0}.ngx-col-6{grid-column:span 6;min-width:0}.ngx-col-7{grid-column:span 7;min-width:0}.ngx-col-8{grid-column:span 8;min-width:0}.ngx-col-9{grid-column:span 9;min-width:0}.ngx-col-10{grid-column:span 10;min-width:0}.ngx-col-11{grid-column:span 11;min-width:0}.ngx-col-12{grid-column:span 12;min-width:0}@media(max-width:640px){.ngx-col-1,.ngx-col-2,.ngx-col-3,.ngx-col-4,.ngx-col-5,.ngx-col-6,.ngx-col-7,.ngx-col-8,.ngx-col-9,.ngx-col-10,.ngx-col-11{grid-column:span 12}}.ngx-form-title{font-size:1.25rem;font-weight:700;margin-bottom:1.25rem;color:var(--p-text-color, #111827)}.ngx-field-label{display:block;font-size:.775rem;font-weight:600;color:var(--p-text-muted-color, #4b5563);margin-bottom:.3rem;letter-spacing:.01em}.ngx-required{color:var(--p-red-500, #ef4444);margin-left:.15rem}.ngx-field-inner{margin-top:.2rem;width:100%}.ngx-field-inner .p-inputgroup,.ngx-field-inner .p-select,.ngx-field-inner .p-multiselect,.ngx-field-inner .p-autocomplete,.ngx-field-inner .p-datepicker,.ngx-field-inner .p-inputtext,.ngx-field-inner .p-textarea,.ngx-field-inner .p-password{width:100%}:host ::ng-deep .p-inputgroup{border:1px solid var(--p-surface-border, #d1d5db);border-radius:8px;background:#fff;transition:all .2s;display:flex;align-items:stretch}:host ::ng-deep .p-inputgroup p-inputgroup-addon,:host ::ng-deep .p-inputgroup .p-inputgroup-addon{background:transparent!important;border:none!important;color:#9ca3af;padding:.75rem .5rem .75rem 1rem;display:flex;align-items:center}:host ::ng-deep .p-inputgroup p-inputgroup-addon i,:host ::ng-deep .p-inputgroup .p-inputgroup-addon i{font-size:1.15rem}:host ::ng-deep .p-inputgroup:has(textarea) p-inputgroup-addon,:host ::ng-deep .p-inputgroup:has(textarea) .p-inputgroup-addon{align-items:flex-start;padding-top:1rem}:host ::ng-deep .p-inputgroup:has(input:focus),:host ::ng-deep .p-inputgroup:has(textarea:focus),:host ::ng-deep .p-inputgroup:has(.p-focus){border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f633}:host ::ng-deep .p-inputgroup>.p-inputtext,:host ::ng-deep .p-inputgroup>.p-textarea,:host ::ng-deep .p-inputgroup p-select>.p-select,:host ::ng-deep .p-inputgroup p-multiselect>.p-multiselect,:host ::ng-deep .p-inputgroup p-autocomplete>.p-autocomplete,:host ::ng-deep .p-inputgroup p-datepicker>.p-datepicker{border:none!important;background:transparent!important;box-shadow:none!important;flex:1 1 auto;min-width:0}:host ::ng-deep .p-inputgroup:has(p-select),:host ::ng-deep .p-inputgroup:has(p-multiselect){position:relative}:host ::ng-deep .p-inputgroup:has(p-select) p-inputgroup-addon,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-inputgroup-addon{position:absolute;z-index:2;border:none!important;background:transparent!important;height:100%;width:2.5rem;display:flex;align-items:center;justify-content:center}:host ::ng-deep .p-inputgroup:has(p-select) p-inputgroup-addon:first-child,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-inputgroup-addon:first-child{left:0}:host ::ng-deep .p-inputgroup:has(p-select) p-select,:host ::ng-deep .p-inputgroup:has(p-select) p-multiselect,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-select,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-multiselect{width:100%;flex:1 1 100%}:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-select) .p-select-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-select) .p-multiselect-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-multiselect) .p-select-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-multiselect) .p-multiselect-label{padding-left:2.75rem!important}:host ::ng-deep .ngx-toggle-card{display:flex;align-items:center;justify-content:space-between;padding:.9rem 1rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:8px;background:#fff;margin-bottom:.75rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:1.1rem;margin-right:1rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body{flex:1;min-width:0;padding-right:1.5rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body .ngx-toggle-label{font-weight:600;color:var(--gray-900);margin-bottom:.2rem;font-size:.95rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body .ngx-toggle-desc{color:var(--gray-500);font-size:.8rem;line-height:1.4}:host ::ng-deep .ngx-toggle-card p-toggleswitch,:host ::ng-deep .ngx-toggle-card .p-toggleswitch{flex:0 0 auto!important;width:44px!important;height:24px!important;display:block!important;position:relative!important;box-sizing:border-box!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch-slider{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;border-radius:24px!important;transition:background-color .2s,box-shadow .2s!important;background:var(--p-surface-300, #cbd5e1)!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch-handle{position:absolute!important;top:50%!important;left:3px!important;margin-top:-9px!important;width:18px!important;height:18px!important;border-radius:50%!important;background:#fff!important;transition:transform .2s!important;box-shadow:0 1px 3px #0003!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-handle{transform:translate(20px)!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-slider{background:var(--toggle-color, var(--p-primary-500))!important}::ng-deep .p-select-overlay,::ng-deep .p-multiselect-overlay,::ng-deep .p-autocomplete-overlay{background:#fff!important;box-shadow:0 4px 15px #00000014,0 1px 3px #0000000d!important;border:1px solid var(--p-surface-border, #e5e7eb)!important;border-radius:8px!important;margin-top:6px!important;padding:.25rem!important}::ng-deep .p-select-overlay .p-select-header,::ng-deep .p-select-overlay .p-multiselect-header,::ng-deep .p-multiselect-overlay .p-select-header,::ng-deep .p-multiselect-overlay .p-multiselect-header,::ng-deep .p-autocomplete-overlay .p-select-header,::ng-deep .p-autocomplete-overlay .p-multiselect-header{padding:.5rem!important;margin-bottom:.25rem}::ng-deep .p-select-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-select-overlay .p-select-filter,::ng-deep .p-select-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-select-overlay .p-multiselect-filter,::ng-deep .p-multiselect-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-multiselect-overlay .p-select-filter,::ng-deep .p-multiselect-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-multiselect-overlay .p-multiselect-filter,::ng-deep .p-autocomplete-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-autocomplete-overlay .p-select-filter,::ng-deep .p-autocomplete-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-autocomplete-overlay .p-multiselect-filter{padding:.5rem .75rem!important}::ng-deep .p-select-overlay .p-select-list,::ng-deep .p-select-overlay .p-multiselect-list,::ng-deep .p-multiselect-overlay .p-select-list,::ng-deep .p-multiselect-overlay .p-multiselect-list,::ng-deep .p-autocomplete-overlay .p-select-list,::ng-deep .p-autocomplete-overlay .p-multiselect-list{padding:0!important;display:flex;flex-direction:column;gap:2px}::ng-deep .p-select-overlay .p-select-option,::ng-deep .p-select-overlay .p-multiselect-option,::ng-deep .p-multiselect-overlay .p-select-option,::ng-deep .p-multiselect-overlay .p-multiselect-option,::ng-deep .p-autocomplete-overlay .p-select-option,::ng-deep .p-autocomplete-overlay .p-multiselect-option{border-radius:6px!important;margin:0!important;padding:.5rem .75rem!important;display:flex;align-items:center}::ng-deep .p-select-overlay .p-select-option:hover,::ng-deep .p-select-overlay .p-multiselect-option:hover,::ng-deep .p-multiselect-overlay .p-select-option:hover,::ng-deep .p-multiselect-overlay .p-multiselect-option:hover,::ng-deep .p-autocomplete-overlay .p-select-option:hover,::ng-deep .p-autocomplete-overlay .p-multiselect-option:hover{background:var(--p-surface-hover, #f3f4f6)!important}::ng-deep .p-select-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-select-overlay .p-select-option.p-select-option-selected,::ng-deep .p-select-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-select-overlay .p-multiselect-option.p-select-option-selected,::ng-deep .p-multiselect-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-multiselect-overlay .p-select-option.p-select-option-selected,::ng-deep .p-multiselect-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-multiselect-overlay .p-multiselect-option.p-select-option-selected,::ng-deep .p-autocomplete-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-autocomplete-overlay .p-select-option.p-select-option-selected,::ng-deep .p-autocomplete-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-autocomplete-overlay .p-multiselect-option.p-select-option-selected{background:#f1f5f9!important;color:var(--p-primary-700, #334155)!important;font-weight:500}.ngx-error{display:block;color:var(--p-red-500, #ef4444);font-size:.72rem;line-height:1.4;min-height:1.008rem;margin-top:.25rem;font-weight:500}.ngx-error--placeholder{visibility:hidden}.ngx-hint{display:block;font-size:.72rem;margin-top:.25rem;color:var(--p-text-muted-color, #9ca3af);line-height:1.4}.ngx-btn-wrap{display:flex;align-items:flex-end;justify-content:stretch;width:100%;height:100%;padding-top:1.5rem}.ngx-btn-wrap button{width:100%;justify-content:center;font-weight:600}.ngx-file-inline{display:flex;flex-wrap:wrap;gap:.5rem}.ngx-image-list{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.ngx-image-card{position:relative}.ngx-image-remove{position:absolute;top:0;right:0;z-index:2;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:50%;cursor:pointer;background:#fff;color:#111;box-shadow:0 2px 6px #0003;transform:translate(40%,-40%);font-size:.65rem;transition:background .15s,color .15s}.ngx-image-remove:hover{background:#fee2e2;color:#dc2626}.ngx-image-wrapper{position:relative;width:80px;height:80px;border-radius:8px;overflow:hidden;border:1px solid var(--p-surface-border, #e5e7eb)}.ngx-preview-img{object-fit:cover;transition:opacity .25s ease}.ngx-preview-img.loading{opacity:0}.ngx-preview-img.loaded{opacity:1}.ngx-img-skeleton{position:absolute;inset:0;background:linear-gradient(90deg,#f0f0f0 25%,#e0e0e0,#f0f0f0 75%);background-size:200% 100%;animation:shimmer 1.4s infinite;border-radius:8px}@keyframes shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.ngx-toggle-card{display:flex;align-items:center;gap:.85rem;padding:.9rem 1rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;background:#fff;width:100%;transition:border-color .2s,box-shadow .2s,background .2s}.ngx-toggle-card:has(.p-toggleswitch.p-toggleswitch-checked){border-color:var(--toggle-color, var(--p-primary-500, #3b82f6));box-shadow:0 0 0 3px color-mix(in srgb,var(--toggle-color, #3b82f6) 12%,transparent)}.ngx-toggle-card-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem;flex-shrink:0}.ngx-toggle-card-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:.15rem}.ngx-toggle-card-label{font-size:.84rem;font-weight:600;color:var(--p-text-color, #111827);line-height:1.3}.ngx-toggle-card-desc{font-size:.72rem;color:var(--p-text-muted-color, #6b7280);line-height:1.4}.ngx-radio-item{display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem;font-size:.875rem;color:var(--p-text-color, #374151)}.ngx-field-group{border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;padding:1rem 1rem .5rem;display:flex;flex-direction:column;gap:.75rem}.ngx-field-group-row{display:block}.ngx-repeater{display:flex;flex-direction:column;gap:.75rem}.ngx-repeater-row{display:grid;grid-template-columns:1fr auto;gap:.5rem;align-items:start;padding:.75rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;background:var(--p-surface-50, #f9fafb)}.ngx-repeater-row-fields{display:grid;grid-template-columns:repeat(12,1fr);gap:.75rem;min-width:0}.ngx-repeater-remove{margin-top:.2rem}.ngx-repeater-add{align-self:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "ngmodule", type:
|
|
395
|
+
// PrimeNG
|
|
396
|
+
InputTextModule }, { kind: "directive", type: i2.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i3.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i4.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i5.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i7.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: CascadeSelectModule }, { kind: "component", type: i8.CascadeSelect, selector: "p-cascadeSelect, p-cascadeselect, p-cascade-select", inputs: ["id", "searchMessage", "emptyMessage", "selectionMessage", "emptySearchMessage", "emptySelectionMessage", "searchLocale", "optionDisabled", "focusOnHover", "selectOnFocus", "autoOptionFocus", "styleClass", "options", "optionLabel", "optionValue", "optionGroupLabel", "optionGroupChildren", "placeholder", "value", "dataKey", "inputId", "tabindex", "ariaLabelledBy", "inputLabel", "ariaLabel", "showClear", "panelStyleClass", "panelStyle", "overlayOptions", "autofocus", "loading", "loadingIcon", "breakpoint", "size", "variant", "fluid", "appendTo", "motionOptions"], outputs: ["onChange", "onGroupChange", "onShow", "onHide", "onClear", "onBeforeShow", "onBeforeHide", "onFocus", "onBlur"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i9.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FileUploadModule }, { kind: "component", type: i10.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i11.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "ngmodule", type: DialogModule }, { kind: "ngmodule", type: DividerModule }, { kind: "component", type: i12.Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "ngmodule", type: PasswordModule }, { kind: "component", type: i13.Password, selector: "p-password", inputs: ["ariaLabel", "ariaLabelledBy", "label", "promptLabel", "mediumRegex", "strongRegex", "weakLabel", "mediumLabel", "maxLength", "strongLabel", "inputId", "feedback", "toggleMask", "inputStyleClass", "styleClass", "inputStyle", "showTransitionOptions", "hideTransitionOptions", "autocomplete", "placeholder", "showClear", "autofocus", "tabindex", "appendTo", "motionOptions", "overlayOptions"], outputs: ["onFocus", "onBlur", "onClear"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i14.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i15.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ToggleSwitchModule }, { kind: "component", type: i16.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "ngmodule", type: TextareaModule }, { kind: "directive", type: i17.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["pTextareaPT", "pTextareaUnstyled", "autoResize", "pSize", "variant", "fluid", "invalid"], outputs: ["onResize"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i18.Slider, selector: "p-slider", inputs: ["animate", "min", "max", "orientation", "step", "range", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: RatingModule }, { kind: "component", type: i19.Rating, selector: "p-rating", inputs: ["readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onFocus", "onBlur"] }, { kind: "ngmodule", type: ColorPickerModule }, { kind: "component", type: i20.ColorPicker, selector: "p-colorPicker, p-colorpicker, p-color-picker", inputs: ["styleClass", "showTransitionOptions", "hideTransitionOptions", "inline", "format", "tabindex", "inputId", "autoZIndex", "autofocus", "defaultColor", "appendTo", "overlayOptions", "motionOptions"], outputs: ["onChange", "onShow", "onHide"] }, { kind: "ngmodule", type: RadioButtonModule }, { kind: "component", type: i21.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "styleClass", "autofocus", "binary", "variant", "size"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: KeyFilterModule }, { kind: "directive", type: i22.KeyFilter, selector: "[pKeyFilter]", inputs: ["pValidateOnly", "pKeyFilter"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: EditorModule }, { kind: "component", type: i23.Editor, selector: "p-editor", inputs: ["style", "styleClass", "placeholder", "formats", "modules", "bounds", "scrollingContainer", "debug", "readonly"], outputs: ["onInit", "onTextChange", "onSelectionChange", "onEditorChange", "onFocus", "onBlur"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
397
|
+
}
|
|
398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: NgxJsonFormComponent, decorators: [{
|
|
399
|
+
type: Component,
|
|
400
|
+
args: [{ selector: 'ngx-json-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
401
|
+
ReactiveFormsModule,
|
|
402
|
+
NgTemplateOutlet,
|
|
403
|
+
NgComponentOutlet,
|
|
404
|
+
NgOptimizedImage,
|
|
405
|
+
// PrimeNG
|
|
406
|
+
InputTextModule,
|
|
407
|
+
InputGroupModule,
|
|
408
|
+
InputGroupAddonModule,
|
|
409
|
+
FloatLabelModule,
|
|
410
|
+
SelectModule,
|
|
411
|
+
MultiSelectModule,
|
|
412
|
+
CascadeSelectModule,
|
|
413
|
+
AutoCompleteModule,
|
|
414
|
+
FileUploadModule,
|
|
415
|
+
ButtonModule,
|
|
416
|
+
DialogModule,
|
|
417
|
+
DividerModule,
|
|
418
|
+
PasswordModule,
|
|
419
|
+
DatePickerModule,
|
|
420
|
+
CheckboxModule,
|
|
421
|
+
ToggleSwitchModule,
|
|
422
|
+
TextareaModule,
|
|
423
|
+
SliderModule,
|
|
424
|
+
RatingModule,
|
|
425
|
+
ColorPickerModule,
|
|
426
|
+
RadioButtonModule,
|
|
427
|
+
KeyFilterModule,
|
|
428
|
+
EditorModule,
|
|
429
|
+
], template: "@if (formTitle().length) {\n <div class=\"ngx-form-title\">{{ formTitle() }}</div>\n}\n\n@if (ready()) {\n <form [formGroup]=\"formGroup()\" class=\"ngx-form-grid\">\n @for (field of visibleFields(); track field.formControlName ?? $index) {\n <div\n [class]=\"\n 'ngx-col-' +\n (field.layout?.columnSpan ?? 12) +\n ' ' +\n (field.layout?.wrapperClass ?? '')\n \"\n [style]=\"field.layout?.wrapperStyle ?? {}\"\n [style.display]=\"field.config.attributes.isHidden ? 'none' : 'block'\"\n >\n <!-- Float Label wrapper -->\n @if (field.floatLabel) {\n <p-floatlabel [variant]=\"field.floatVariant ?? 'on'\">\n <div class=\"ngx-field-inner\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: field, formGroup: formGroup() }\"\n />\n </div>\n <label\n [attr.for]=\"field.formControlName + 'Id'\"\n [attr.id]=\"field.formControlName + 'Label'\"\n >\n @if (field.labelIconPos === 'left') {\n <i [class]=\"field.labelIcon\"></i>\n }\n {{ field.label }}\n @if (field.labelIconPos === 'right') {\n <i [class]=\"field.labelIcon\"></i>\n }\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n </p-floatlabel>\n }\n\n <!-- Toggle card layout -->\n @else if (\n field.config.attributes.cardLayout &&\n field.config.attributes.inputType === 'toggle'\n ) {\n <div\n class=\"ngx-toggle-card\"\n [style.--toggle-color]=\"field.config.attributes.cardIconColor\"\n >\n <div\n class=\"ngx-toggle-card-icon\"\n [style.background]=\"\n field.config.attributes.cardIconBg ??\n 'var(--p-primary-50, #eff6ff)'\n \"\n [style.color]=\"\n field.config.attributes.cardIconColor ??\n 'var(--p-primary-500, #3b82f6)'\n \"\n >\n <i [class]=\"field.config.attributes.cardIcon ?? 'pi pi-bell'\"></i>\n </div>\n <div class=\"ngx-toggle-card-body\">\n <span class=\"ngx-toggle-card-label\">\n {{ field.label }}\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </span>\n @if (field.config.attributes.info?.length) {\n <span\n class=\"ngx-toggle-card-desc\"\n [innerHTML]=\"field.config.attributes.info\"\n ></span>\n }\n </div>\n <p-toggleswitch\n [formControlName]=\"field.formControlName!\"\n [inputId]=\"field.formControlName + 'Id'\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n </div>\n <!--\n Always reserve one line of space for the error so the row height\n doesn't change when validation fires (otherwise sibling fields\n jump down when the error appears).\n -->\n @if (field.validations?.rules) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!errorMap()[field.formControlName!]\"\n [attr.id]=\"field.formControlName + 'Err'\"\n >{{ errorMap()[field.formControlName!] || '\u00A0' }}</small>\n }\n }\n\n <!-- Normal label wrapper -->\n @else {\n @if (field.label && field.label.length) {\n <label\n class=\"ngx-field-label\"\n [attr.for]=\"field.formControlName + 'Id'\"\n [attr.id]=\"field.formControlName + 'Label'\"\n >\n @if (field.labelIconPos === 'left') {\n <i [class]=\"field.labelIcon\"></i>\n }\n {{ field.label }}\n @if (field.labelIconPos === 'right') {\n <i [class]=\"field.labelIcon\"></i>\n }\n @if (field.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n }\n <div class=\"ngx-field-inner\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: field, formGroup: formGroup() }\"\n />\n </div>\n\n <!--\n Validation error \u2014 always reserve one line of space (placeholder\n class makes it invisible when there's no error) so triggering a\n required/pattern message doesn't push the row below it down.\n -->\n @if (field.validations?.rules) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!errorMap()[field.formControlName!]\"\n [attr.id]=\"field.formControlName + 'Err'\"\n >{{ errorMap()[field.formControlName!] || '\u00A0' }}</small>\n }\n\n <!-- Info / hint -->\n @if (field.config.attributes.info?.length) {\n <small\n class=\"ngx-hint\"\n [attr.id]=\"field.formControlName + 'Hint'\"\n [innerHTML]=\"field.config.attributes.info\"\n ></small>\n }\n }\n </div>\n }\n </form>\n}\n\n<!-- \u2500\u2500\u2500 Field Renderer Template \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n<!--\n `formGroup` is passed in via the template context so each rendering site\n binds the right group: the root FormGroup for top-level fields, the row's\n FormGroup for repeater rows. Hard-coding `formGroup()` here would override\n row-level bindings and route nested formControlName lookups to the root,\n which is the bug we're fixing.\n\n Known issue: during initial CD passes Angular logs NG01050 spam because\n the FormGroup directive on this ng-container materialises after children\n formControlName directives query their parent ControlContainer. Bindings\n recover and form values flow correctly afterwards. Cleaner fix would be\n to avoid the ngTemplateOutlet + context + nested formGroup combination\n altogether (e.g. inline the @switch at each call site).\n-->\n<ng-template #fieldTpl let-field let-fg=\"formGroup\" let-idSuffix=\"idSuffix\">\n <ng-container [formGroup]=\"fg\">\n @switch (field.config.attributes.inputType) {\n <!-- \u2500\u2500 Custom field (registry) \u2500\u2500 -->\n @case (customRenderer(field) ? field.config.attributes.inputType : '__never__') {\n <ng-container\n *ngComponentOutlet=\"customRenderer(field)!; inputs: customRendererInputs(field)\"\n />\n }\n\n <!-- \u2500\u2500 Group (nested FormGroup) \u2500\u2500 -->\n @case ('group') {\n <fieldset\n class=\"ngx-field-group\"\n [attr.formGroupName]=\"field.formControlName\"\n >\n @for (sub of field.config.attributes.groupFields ?? []; track sub.formControlName ?? $index) {\n <div class=\"ngx-field-group-row\">\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: sub, formGroup: formGroup() }\"\n />\n </div>\n }\n </fieldset>\n }\n\n <!-- \u2500\u2500 Repeater (FormArray) \u2500\u2500 -->\n @case ('repeater') {\n <div class=\"ngx-repeater\">\n @for (row of getArray(field.formControlName!)?.controls ?? []; track $index) {\n @let rowIndex = $index;\n <div class=\"ngx-repeater-row\" [formGroup]=\"$any(row)\">\n <div class=\"ngx-repeater-row-fields\">\n @for (sub of field.config.attributes.itemFields ?? []; track sub.formControlName ?? $index) {\n <div\n [class]=\"\n 'ngx-col-' + (sub.layout?.columnSpan ?? 12)\n \"\n >\n @if (sub.label) {\n <label\n class=\"ngx-field-label\"\n [attr.for]=\"inputId(sub, rowIndex)\"\n >\n {{ sub.label }}\n @if (sub.validations?.rules?.required) {\n <span class=\"ngx-required\">*</span>\n }\n </label>\n }\n <ng-container\n [ngTemplateOutlet]=\"fieldTpl\"\n [ngTemplateOutletContext]=\"{ $implicit: sub, formGroup: $any(row), idSuffix: rowIndex }\"\n />\n @if (sub.validations?.rules && sub.formControlName) {\n <small\n class=\"ngx-error\"\n [class.ngx-error--placeholder]=\"!resolveRowError($any(row), sub)\"\n >{{ resolveRowError($any(row), sub) || '\u00A0' }}</small>\n }\n </div>\n }\n </div>\n <button\n type=\"button\"\n class=\"ngx-repeater-remove\"\n pButton\n [icon]=\"'pi pi-trash'\"\n [rounded]=\"true\"\n [text]=\"true\"\n (click)=\"removeRepeaterRow(field, $index)\"\n ></button>\n </div>\n }\n <button\n pButton\n type=\"button\"\n class=\"ngx-repeater-add\"\n [icon]=\"'pi pi-plus'\"\n [label]=\"field.config.attributes.addLabel ?? 'Add row'\"\n [text]=\"true\"\n (click)=\"addRepeaterRow(field)\"\n ></button>\n </div>\n }\n\n <!-- \u2500\u2500 Dependent / Cascading Dropdown \u2500\u2500 -->\n @case ('dependentDropdown') {\n <p-cascadeselect\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel ?? 'label'\"\n [optionValue]=\"field.config.attributes.optionValue ?? 'value'\"\n [optionGroupLabel]=\"field.config.attributes.optionGroupLabel ?? 'label'\"\n [optionGroupChildren]=\"\n $any(field.config.attributes.optionGroupChildren ?? ['children'])\n \"\n [placeholder]=\"field.placeholder ?? ''\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onShow)=\"onEvent(field, $event, 'show')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n />\n }\n\n <!-- \u2500\u2500 Editor (rich text) \u2500\u2500 -->\n @case ('editor') {\n <p-editor\n [formControlName]=\"field.formControlName!\"\n [style]=\"{ height: (field.config.attributes['height'] ?? '180px') }\"\n (onTextChange)=\"onEvent(field, $event, 'change')\"\n ></p-editor>\n }\n\n <!-- \u2500\u2500 Confirm password \u2500\u2500 -->\n @case ('confirmPassword') {\n <p-password\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [feedback]=\"false\"\n [toggleMask]=\"field.config.attributes.toggleMask ?? true\"\n [placeholder]=\"field.placeholder ?? ''\"\n appendTo=\"body\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n />\n }\n\n <!-- \u2500\u2500 File Upload \u2500\u2500 -->\n @case ('fileUpload') {\n <div>\n <div\n [class]=\"field.config.attributes.isInline ? 'ngx-file-inline' : ''\"\n >\n <p-fileUpload\n mode=\"basic\"\n customUpload\n [id]=\"inputId(field, idSuffix)\"\n [multiple]=\"field.config.attributes.multiple\"\n [chooseIcon]=\"field.config.attributes.chooseIcon ?? 'pi pi-upload'\"\n [accept]=\"field.config.attributes.accept ?? 'image/*'\"\n [maxFileSize]=\"field.config.attributes.maxFileSize ?? 1000000\"\n [auto]=\"true\"\n [chooseLabel]=\"field.config.attributes.chooseLabel ?? 'Upload'\"\n (uploadHandler)=\"onEvent(field, $event, 'uploadHandler')\"\n />\n\n @if (uploadService.imagePreviews()[field.formControlName!]?.length) {\n <div class=\"ngx-image-list\">\n @for (\n image of uploadService.imagePreviews()[field.formControlName!];\n let i = $index;\n track i\n ) {\n <div class=\"ngx-image-card\">\n <i\n class=\"pi pi-times ngx-image-remove\"\n (click)=\"removeImage(field, image)\"\n ></i>\n <div class=\"ngx-image-wrapper\">\n @if (!uploadService.isBase64(image)) {\n <img\n fill\n sizes=\"100\"\n [ngSrc]=\"image\"\n (load)=\"uploadService.onLoad(image)\"\n (error)=\"uploadService.onLoad(image)\"\n [class.loading]=\"uploadService.isLoading(image)\"\n [class.loaded]=\"!uploadService.isLoading(image)\"\n class=\"ngx-preview-img\"\n alt=\"preview\"\n />\n } @else {\n <img\n fill\n sizes=\"100\"\n [src]=\"image\"\n (load)=\"uploadService.onLoad(image)\"\n (error)=\"uploadService.onLoad(image)\"\n [class.loading]=\"uploadService.isLoading(image)\"\n [class.loaded]=\"!uploadService.isLoading(image)\"\n class=\"ngx-preview-img\"\n alt=\"preview\"\n />\n }\n @if (uploadService.isLoading(image)) {\n <div class=\"ngx-img-skeleton\"></div>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n\n <!-- \u2500\u2500 Static Text \u2500\u2500 -->\n @case ('staticText') {\n <span\n (click)=\"onEvent(field, $event, 'staticTextClick')\"\n [innerHTML]=\"field.config.attributes.value\"\n ></span>\n }\n\n <!-- \u2500\u2500 Divider \u2500\u2500 -->\n @case ('divider') {\n <p-divider\n [layout]=\"field.config.attributes.dividerLayout\"\n [type]=\"field.config.attributes.dividerType\"\n [align]=\"field.config.attributes.dividerAlign\"\n >\n @if (field.config.attributes.value) {\n <span [innerHTML]=\"field.config.attributes.value\"></span>\n }\n </p-divider>\n }\n\n <!-- \u2500\u2500 Button \u2500\u2500 -->\n @case ('button') {\n <div class=\"ngx-btn-wrap\">\n <button\n pButton\n type=\"button\"\n [id]=\"inputId(field, idSuffix)\"\n [label]=\"field.btnLabel ?? ''\"\n [icon]=\"field.config.attributes.icon ?? ''\"\n [iconPos]=\"field.config.attributes.iconPosition ?? 'left'\"\n [tabindex]=\"field.tabIndex ?? 0\"\n [disabled]=\"\n field.config.attributes.buttonRole === 'submit' ||\n field.config.attributes.type === 'submit'\n ? !formValid()\n : !!field.config.attributes.disabled\n \"\n [class.p-button-outlined]=\"\n field.config.attributes.variant === 'secondary'\n \"\n [class.p-button-text]=\"field.config.attributes.text === true\"\n [class.p-button-rounded]=\"field.config.attributes.rounded === true\"\n [class.p-button-sm]=\"field.config.attributes.size === 'sm'\"\n [class.p-button-lg]=\"field.config.attributes.size === 'lg'\"\n (click)=\"onEvent(field, $event)\"\n ></button>\n </div>\n }\n\n <!-- \u2500\u2500 Everything else inside p-inputgroup \u2500\u2500 -->\n @default {\n <p-inputgroup>\n @if (\n field.config.attributes.fieldPos === 'left' &&\n field.config.attributes.fieldIcon\n ) {\n <p-inputgroup-addon>\n <i [class]=\"field.config.attributes.fieldIcon\">\n {{ field.config.attributes.fieldIconText ?? '' }}\n </i>\n </p-inputgroup-addon>\n }\n\n @switch (field.config.attributes.inputType) {\n <!-- text / email / number / url -->\n @case ('text') {\n <input\n pInputText\n [id]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [type]=\"field.config.attributes.type ?? 'text'\"\n [tabindex]=\"field.tabIndex ?? 0\"\n [attr.placeholder]=\"placeholderFor(field)\"\n [attr.aria-describedby]=\"\n (errorMap()[field.formControlName!] ? field.formControlName + 'Err ' : '') +\n (field.config.attributes.info ? field.formControlName + 'Hint' : '')\n \"\n [pKeyFilter]=\"field.config.attributes.keyfilter\"\n (change)=\"onEvent(field, $event)\"\n (input)=\"onEvent(field, $event)\"\n (focus)=\"onEvent(field, $event)\"\n (blur)=\"onEvent(field, $event)\"\n (keyup)=\"onEvent(field, $event)\"\n (keydown)=\"onEvent(field, $event)\"\n (keypress)=\"onEvent(field, $event)\"\n />\n }\n\n <!-- password -->\n @case ('password') {\n <p-password\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [feedback]=\"field.config.attributes.feedback\"\n [toggleMask]=\"field.config.attributes.toggleMask\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n appendTo=\"body\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n >\n @if (field.config.attributes.templateHeader) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.templateHeader\"\n />\n }\n @if (field.config.attributes.templateFooter) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.templateFooter\"\n />\n }\n </p-password>\n }\n\n <!-- textarea -->\n @case ('textarea') {\n <textarea\n pTextarea\n [id]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [rows]=\"field.config.attributes.rows ?? 3\"\n [cols]=\"field.config.attributes.cols ?? 30\"\n [autoResize]=\"field.config.attributes.autoResize\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n (change)=\"onEvent(field, $event)\"\n (input)=\"onEvent(field, $event)\"\n (focus)=\"onEvent(field, $event)\"\n (blur)=\"onEvent(field, $event)\"\n >\n </textarea>\n }\n\n <!-- select -->\n @case ('select') {\n <p-select\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [attr.aria-labelledby]=\"field.formControlName + 'Label'\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [optionValue]=\"field.config.attributes.optionValue\"\n [placeholder]=\"placeholderFor(field) ?? ''\"\n [showClear]=\"field.config.attributes.showClear\"\n [filter]=\"field.config.attributes.filter\"\n [filterBy]=\"field.config.attributes.filterBy\"\n [filterPlaceholder]=\"field.config.attributes.filterPlaceholder\"\n [loading]=\"field.config.attributes.loading\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [lazy]=\"field.config.attributes.lazy\"\n [emptyMessage]=\"field.config.attributes.emptyMessage\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onShow)=\"onEvent(field, $event, 'show')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onLazyLoad)=\"onEvent(field, $event, 'lazyLoad')\"\n >\n @if (\n field.config.attributes.isTemplate &&\n field.config.attributes.template\n ) {\n <ng-container\n [ngTemplateOutlet]=\"field.config.attributes.template\"\n />\n }\n </p-select>\n }\n\n <!-- multiSelect -->\n @case ('multiSelect') {\n <p-multiselect\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [options]=\"$any(optionsFor(field))\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [optionValue]=\"field.config.attributes.optionValue\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [filter]=\"field.config.attributes.filter\"\n [showClear]=\"field.config.attributes.showClear\"\n [selectionLimit]=\"field.config.attributes.selectionLimit\"\n [display]=\"field.config.attributes.display\"\n [loading]=\"field.config.attributes.loading\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [scrollHeight]=\"field.config.attributes.scrollHeight\"\n appendTo=\"body\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onHide)=\"onEvent(field, $event, 'hide')\"\n (onRemove)=\"onEvent(field, $event, 'remove')\"\n (onSelectAll)=\"onEvent(field, $event, 'select')\"\n >\n </p-multiselect>\n }\n\n <!-- autocomplete -->\n @case ('autocomplete') {\n <p-autocomplete\n [id]=\"inputId(field, idSuffix)\"\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [suggestions]=\"field.config.attributes.suggestions\"\n [optionLabel]=\"field.config.attributes.optionLabel\"\n [multiple]=\"field.config.attributes.multiple\"\n [forceSelection]=\"field.config.attributes.forceSelection\"\n [dropdown]=\"field.config.attributes.dropdown\"\n [showClear]=\"field.config.attributes.showClear\"\n [completeOnFocus]=\"field.config.attributes.completeOnFocus\"\n [minLength]=\"field.config.attributes.minLength ?? 1\"\n [delay]=\"field.config.attributes.delay ?? 300\"\n [virtualScroll]=\"field.config.attributes.virtualScroll\"\n [virtualScrollItemSize]=\"\n field.config.attributes.virtualScrollItemSize\n \"\n [scrollHeight]=\"field.config.attributes.scrollHeight\"\n appendTo=\"body\"\n (completeMethod)=\"onEvent(field, $event, 'complete')\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n (onUnselect)=\"onEvent(field, $event, 'unselect')\"\n (onAdd)=\"onEvent(field, $event, 'add')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n (onInputKeydown)=\"onEvent(field, $event, 'inputKeydown')\"\n >\n </p-autocomplete>\n }\n\n <!-- toggle -->\n @case ('toggle') {\n <p-toggleswitch\n [formControlName]=\"field.formControlName!\"\n [inputId]=\"inputId(field, idSuffix)\"\n [attr.aria-labelledby]=\"field.formControlName + 'Label'\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- checkbox -->\n @case ('checkbox') {\n <p-checkbox\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [name]=\"field.config.attributes.name ?? field.formControlName!\"\n [value]=\"field.config.attributes.value\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- radio -->\n @case ('radio') {\n @for (opt of $any(optionsFor(field)); track $index) {\n <div class=\"ngx-radio-item\">\n <p-radiobutton\n [inputId]=\"field.formControlName + '_' + $index\"\n [formControlName]=\"field.formControlName!\"\n [name]=\"field.formControlName!\"\n [value]=\"\n opt[field.config.attributes.optionValue ?? 'value']\n \"\n (onClick)=\"onEvent(field, $event, 'change')\"\n />\n <label [for]=\"field.formControlName + '_' + $index\">\n {{ opt[field.config.attributes.optionLabel ?? 'label'] }}\n </label>\n </div>\n }\n }\n\n <!-- datePicker / time / month / year -->\n @case ('datePicker') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"field.config.attributes.showIcon\"\n [minDate]=\"minDateFor(field)!\"\n [maxDate]=\"maxDateFor(field)!\"\n [selectionMode]=\"$any(field.config.attributes.selectionMode)\"\n [readonlyInput]=\"field.config.attributes.readonlyInput\"\n [showButtonBar]=\"field.config.attributes.showButtonBar\"\n [showTime]=\"field.config.attributes.showTime\"\n [hourFormat]=\"field.config.attributes.hourFormat\"\n [timeOnly]=\"field.config.attributes.timeOnly\"\n [view]=\"$any(field.config.attributes.view)\"\n [dateFormat]=\"field.config.attributes.dateFormat\"\n [numberOfMonths]=\"field.config.attributes.numberOfMonths ?? 1\"\n [showClear]=\"field.config.attributes.showClear\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n (onBlur)=\"onEvent(field, $event, 'blur')\"\n (onFocus)=\"onEvent(field, $event, 'focus')\"\n (onClear)=\"onEvent(field, $event, 'clear')\"\n >\n </p-datepicker>\n }\n\n @case ('time') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [iconDisplay]=\"'input'\"\n [timeOnly]=\"true\"\n [showTime]=\"true\"\n [hourFormat]=\"field.config.attributes.hourFormat ?? '24'\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n @case ('month') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [view]=\"'month'\"\n [dateFormat]=\"field.config.attributes.dateFormat ?? 'mm/yy'\"\n [readonlyInput]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n @case ('year') {\n <p-datepicker\n [inputId]=\"inputId(field, idSuffix)\"\n [formControlName]=\"field.formControlName!\"\n [placeholder]=\"field.config.attributes.placeholder ?? ''\"\n [showIcon]=\"true\"\n [view]=\"'year'\"\n [dateFormat]=\"field.config.attributes.dateFormat ?? 'yy'\"\n [readonlyInput]=\"true\"\n appendTo=\"body\"\n (onSelect)=\"onEvent(field, $event, 'select')\"\n />\n }\n\n <!-- slider -->\n @case ('slider') {\n <p-slider\n [formControlName]=\"field.formControlName!\"\n [min]=\"field.config.attributes.min ?? 0\"\n [max]=\"field.config.attributes.max ?? 100\"\n [step]=\"field.config.attributes.step ?? 1\"\n [range]=\"field.config.attributes.range\"\n [orientation]=\"\n field.config.attributes.orientation ?? 'horizontal'\n \"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- rating -->\n @case ('rating') {\n <p-rating\n [formControlName]=\"field.formControlName!\"\n [stars]=\"field.config.attributes.stars ?? 5\"\n (onRate)=\"onEvent(field, $event, 'change')\"\n />\n }\n\n <!-- colorPicker -->\n @case ('colorPicker') {\n <p-colorpicker\n [formControlName]=\"field.formControlName!\"\n [inline]=\"field.config.attributes.inline\"\n (onChange)=\"onEvent(field, $event, 'change')\"\n />\n }\n }\n\n @if (\n field.config.attributes.fieldPos === 'right' &&\n field.config.attributes.fieldIcon\n ) {\n <p-inputgroup-addon>\n <i [class]=\"field.config.attributes.fieldIcon\">\n {{ field.config.attributes.fieldIconText ?? '' }}\n </i>\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n }\n }\n </ng-container>\n</ng-template>\n", styles: [".ngx-form-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:1.25rem}.ngx-col-1{grid-column:span 1;min-width:0}.ngx-col-2{grid-column:span 2;min-width:0}.ngx-col-3{grid-column:span 3;min-width:0}.ngx-col-4{grid-column:span 4;min-width:0}.ngx-col-5{grid-column:span 5;min-width:0}.ngx-col-6{grid-column:span 6;min-width:0}.ngx-col-7{grid-column:span 7;min-width:0}.ngx-col-8{grid-column:span 8;min-width:0}.ngx-col-9{grid-column:span 9;min-width:0}.ngx-col-10{grid-column:span 10;min-width:0}.ngx-col-11{grid-column:span 11;min-width:0}.ngx-col-12{grid-column:span 12;min-width:0}@media(max-width:640px){.ngx-col-1,.ngx-col-2,.ngx-col-3,.ngx-col-4,.ngx-col-5,.ngx-col-6,.ngx-col-7,.ngx-col-8,.ngx-col-9,.ngx-col-10,.ngx-col-11{grid-column:span 12}}.ngx-form-title{font-size:1.25rem;font-weight:700;margin-bottom:1.25rem;color:var(--p-text-color, #111827)}.ngx-field-label{display:block;font-size:.775rem;font-weight:600;color:var(--p-text-muted-color, #4b5563);margin-bottom:.3rem;letter-spacing:.01em}.ngx-required{color:var(--p-red-500, #ef4444);margin-left:.15rem}.ngx-field-inner{margin-top:.2rem;width:100%}.ngx-field-inner .p-inputgroup,.ngx-field-inner .p-select,.ngx-field-inner .p-multiselect,.ngx-field-inner .p-autocomplete,.ngx-field-inner .p-datepicker,.ngx-field-inner .p-inputtext,.ngx-field-inner .p-textarea,.ngx-field-inner .p-password{width:100%}:host ::ng-deep .p-inputgroup{border:1px solid var(--p-surface-border, #d1d5db);border-radius:8px;background:#fff;transition:all .2s;display:flex;align-items:stretch}:host ::ng-deep .p-inputgroup p-inputgroup-addon,:host ::ng-deep .p-inputgroup .p-inputgroup-addon{background:transparent!important;border:none!important;color:#9ca3af;padding:.75rem .5rem .75rem 1rem;display:flex;align-items:center}:host ::ng-deep .p-inputgroup p-inputgroup-addon i,:host ::ng-deep .p-inputgroup .p-inputgroup-addon i{font-size:1.15rem}:host ::ng-deep .p-inputgroup:has(textarea) p-inputgroup-addon,:host ::ng-deep .p-inputgroup:has(textarea) .p-inputgroup-addon{align-items:flex-start;padding-top:1rem}:host ::ng-deep .p-inputgroup:has(input:focus),:host ::ng-deep .p-inputgroup:has(textarea:focus),:host ::ng-deep .p-inputgroup:has(.p-focus){border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f633}:host ::ng-deep .p-inputgroup>.p-inputtext,:host ::ng-deep .p-inputgroup>.p-textarea,:host ::ng-deep .p-inputgroup p-select>.p-select,:host ::ng-deep .p-inputgroup p-multiselect>.p-multiselect,:host ::ng-deep .p-inputgroup p-autocomplete>.p-autocomplete,:host ::ng-deep .p-inputgroup p-datepicker>.p-datepicker{border:none!important;background:transparent!important;box-shadow:none!important;flex:1 1 auto;min-width:0}:host ::ng-deep .p-inputgroup:has(p-select),:host ::ng-deep .p-inputgroup:has(p-multiselect){position:relative}:host ::ng-deep .p-inputgroup:has(p-select) p-inputgroup-addon,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-inputgroup-addon{position:absolute;z-index:2;border:none!important;background:transparent!important;height:100%;width:2.5rem;display:flex;align-items:center;justify-content:center}:host ::ng-deep .p-inputgroup:has(p-select) p-inputgroup-addon:first-child,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-inputgroup-addon:first-child{left:0}:host ::ng-deep .p-inputgroup:has(p-select) p-select,:host ::ng-deep .p-inputgroup:has(p-select) p-multiselect,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-select,:host ::ng-deep .p-inputgroup:has(p-multiselect) p-multiselect{width:100%;flex:1 1 100%}:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-select) .p-select-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-select) .p-multiselect-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-multiselect) .p-select-label,:host ::ng-deep .p-inputgroup:has(p-inputgroup-addon:first-child):has(p-multiselect) .p-multiselect-label{padding-left:2.75rem!important}:host ::ng-deep .ngx-toggle-card{display:flex;align-items:center;justify-content:space-between;padding:.9rem 1rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:8px;background:#fff;margin-bottom:.75rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:1.1rem;margin-right:1rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body{flex:1;min-width:0;padding-right:1.5rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body .ngx-toggle-label{font-weight:600;color:var(--gray-900);margin-bottom:.2rem;font-size:.95rem}:host ::ng-deep .ngx-toggle-card .ngx-toggle-card-body .ngx-toggle-desc{color:var(--gray-500);font-size:.8rem;line-height:1.4}:host ::ng-deep .ngx-toggle-card p-toggleswitch,:host ::ng-deep .ngx-toggle-card .p-toggleswitch{flex:0 0 auto!important;width:44px!important;height:24px!important;display:block!important;position:relative!important;box-sizing:border-box!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch-slider{position:absolute!important;inset:0!important;width:100%!important;height:100%!important;border-radius:24px!important;transition:background-color .2s,box-shadow .2s!important;background:var(--p-surface-300, #cbd5e1)!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch-handle{position:absolute!important;top:50%!important;left:3px!important;margin-top:-9px!important;width:18px!important;height:18px!important;border-radius:50%!important;background:#fff!important;transition:transform .2s!important;box-shadow:0 1px 3px #0003!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-handle{transform:translate(20px)!important}:host ::ng-deep .ngx-toggle-card .p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-slider{background:var(--toggle-color, var(--p-primary-500))!important}::ng-deep .p-select-overlay,::ng-deep .p-multiselect-overlay,::ng-deep .p-autocomplete-overlay{background:#fff!important;box-shadow:0 4px 15px #00000014,0 1px 3px #0000000d!important;border:1px solid var(--p-surface-border, #e5e7eb)!important;border-radius:8px!important;margin-top:6px!important;padding:.25rem!important}::ng-deep .p-select-overlay .p-select-header,::ng-deep .p-select-overlay .p-multiselect-header,::ng-deep .p-multiselect-overlay .p-select-header,::ng-deep .p-multiselect-overlay .p-multiselect-header,::ng-deep .p-autocomplete-overlay .p-select-header,::ng-deep .p-autocomplete-overlay .p-multiselect-header{padding:.5rem!important;margin-bottom:.25rem}::ng-deep .p-select-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-select-overlay .p-select-filter,::ng-deep .p-select-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-select-overlay .p-multiselect-filter,::ng-deep .p-multiselect-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-multiselect-overlay .p-select-filter,::ng-deep .p-multiselect-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-multiselect-overlay .p-multiselect-filter,::ng-deep .p-autocomplete-overlay .p-select-filter-container .p-inputtext,::ng-deep .p-autocomplete-overlay .p-select-filter,::ng-deep .p-autocomplete-overlay .p-multiselect-filter-container .p-inputtext,::ng-deep .p-autocomplete-overlay .p-multiselect-filter{padding:.5rem .75rem!important}::ng-deep .p-select-overlay .p-select-list,::ng-deep .p-select-overlay .p-multiselect-list,::ng-deep .p-multiselect-overlay .p-select-list,::ng-deep .p-multiselect-overlay .p-multiselect-list,::ng-deep .p-autocomplete-overlay .p-select-list,::ng-deep .p-autocomplete-overlay .p-multiselect-list{padding:0!important;display:flex;flex-direction:column;gap:2px}::ng-deep .p-select-overlay .p-select-option,::ng-deep .p-select-overlay .p-multiselect-option,::ng-deep .p-multiselect-overlay .p-select-option,::ng-deep .p-multiselect-overlay .p-multiselect-option,::ng-deep .p-autocomplete-overlay .p-select-option,::ng-deep .p-autocomplete-overlay .p-multiselect-option{border-radius:6px!important;margin:0!important;padding:.5rem .75rem!important;display:flex;align-items:center}::ng-deep .p-select-overlay .p-select-option:hover,::ng-deep .p-select-overlay .p-multiselect-option:hover,::ng-deep .p-multiselect-overlay .p-select-option:hover,::ng-deep .p-multiselect-overlay .p-multiselect-option:hover,::ng-deep .p-autocomplete-overlay .p-select-option:hover,::ng-deep .p-autocomplete-overlay .p-multiselect-option:hover{background:var(--p-surface-hover, #f3f4f6)!important}::ng-deep .p-select-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-select-overlay .p-select-option.p-select-option-selected,::ng-deep .p-select-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-select-overlay .p-multiselect-option.p-select-option-selected,::ng-deep .p-multiselect-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-multiselect-overlay .p-select-option.p-select-option-selected,::ng-deep .p-multiselect-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-multiselect-overlay .p-multiselect-option.p-select-option-selected,::ng-deep .p-autocomplete-overlay .p-select-option[data-p-highlight=true],::ng-deep .p-autocomplete-overlay .p-select-option.p-select-option-selected,::ng-deep .p-autocomplete-overlay .p-multiselect-option[data-p-highlight=true],::ng-deep .p-autocomplete-overlay .p-multiselect-option.p-select-option-selected{background:#f1f5f9!important;color:var(--p-primary-700, #334155)!important;font-weight:500}.ngx-error{display:block;color:var(--p-red-500, #ef4444);font-size:.72rem;line-height:1.4;min-height:1.008rem;margin-top:.25rem;font-weight:500}.ngx-error--placeholder{visibility:hidden}.ngx-hint{display:block;font-size:.72rem;margin-top:.25rem;color:var(--p-text-muted-color, #9ca3af);line-height:1.4}.ngx-btn-wrap{display:flex;align-items:flex-end;justify-content:stretch;width:100%;height:100%;padding-top:1.5rem}.ngx-btn-wrap button{width:100%;justify-content:center;font-weight:600}.ngx-file-inline{display:flex;flex-wrap:wrap;gap:.5rem}.ngx-image-list{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.75rem}.ngx-image-card{position:relative}.ngx-image-remove{position:absolute;top:0;right:0;z-index:2;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:50%;cursor:pointer;background:#fff;color:#111;box-shadow:0 2px 6px #0003;transform:translate(40%,-40%);font-size:.65rem;transition:background .15s,color .15s}.ngx-image-remove:hover{background:#fee2e2;color:#dc2626}.ngx-image-wrapper{position:relative;width:80px;height:80px;border-radius:8px;overflow:hidden;border:1px solid var(--p-surface-border, #e5e7eb)}.ngx-preview-img{object-fit:cover;transition:opacity .25s ease}.ngx-preview-img.loading{opacity:0}.ngx-preview-img.loaded{opacity:1}.ngx-img-skeleton{position:absolute;inset:0;background:linear-gradient(90deg,#f0f0f0 25%,#e0e0e0,#f0f0f0 75%);background-size:200% 100%;animation:shimmer 1.4s infinite;border-radius:8px}@keyframes shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.ngx-toggle-card{display:flex;align-items:center;gap:.85rem;padding:.9rem 1rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;background:#fff;width:100%;transition:border-color .2s,box-shadow .2s,background .2s}.ngx-toggle-card:has(.p-toggleswitch.p-toggleswitch-checked){border-color:var(--toggle-color, var(--p-primary-500, #3b82f6));box-shadow:0 0 0 3px color-mix(in srgb,var(--toggle-color, #3b82f6) 12%,transparent)}.ngx-toggle-card-icon{width:42px;height:42px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem;flex-shrink:0}.ngx-toggle-card-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:.15rem}.ngx-toggle-card-label{font-size:.84rem;font-weight:600;color:var(--p-text-color, #111827);line-height:1.3}.ngx-toggle-card-desc{font-size:.72rem;color:var(--p-text-muted-color, #6b7280);line-height:1.4}.ngx-radio-item{display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem;font-size:.875rem;color:var(--p-text-color, #374151)}.ngx-field-group{border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;padding:1rem 1rem .5rem;display:flex;flex-direction:column;gap:.75rem}.ngx-field-group-row{display:block}.ngx-repeater{display:flex;flex-direction:column;gap:.75rem}.ngx-repeater-row{display:grid;grid-template-columns:1fr auto;gap:.5rem;align-items:start;padding:.75rem;border:1px solid var(--p-surface-border, #e5e7eb);border-radius:10px;background:var(--p-surface-50, #f9fafb)}.ngx-repeater-row-fields{display:grid;grid-template-columns:repeat(12,1fr);gap:.75rem;min-width:0}.ngx-repeater-remove{margin-top:.2rem}.ngx-repeater-add{align-self:flex-start}\n"] }]
|
|
430
|
+
}], ctorParameters: () => [], propDecorators: { formTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "formTitle", required: false }] }], fieldsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldsInput", required: false }] }], schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: false }] }], stepFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepFields", required: false }] }], formSubmit: [{ type: i0.Output, args: ["formSubmit"] }], formChange: [{ type: i0.Output, args: ["formChange"] }] } });
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Wizard-style wrapper that drives `<ngx-json-form>` step-by-step using the
|
|
434
|
+
* `FormSchema.steps` definition. Renders a header strip with step indicators,
|
|
435
|
+
* the current step's fields, and Back / Next / Submit controls.
|
|
436
|
+
*/
|
|
437
|
+
class NgxJsonFormStepperComponent {
|
|
438
|
+
schema = input.required(...(ngDevMode ? [{ debugName: "schema" }] : /* istanbul ignore next */ []));
|
|
439
|
+
submitLabel = input('Submit', ...(ngDevMode ? [{ debugName: "submitLabel" }] : /* istanbul ignore next */ []));
|
|
440
|
+
formSubmit = output();
|
|
441
|
+
formChange = output();
|
|
442
|
+
formService = inject(FormEngineService);
|
|
443
|
+
activeIndex = computed(() => this.formService.activeStepIndex(), ...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
444
|
+
activeStep = computed(() => this.formService.activeStep(), ...(ngDevMode ? [{ debugName: "activeStep" }] : /* istanbul ignore next */ []));
|
|
445
|
+
isLast = computed(() => {
|
|
446
|
+
const steps = this.schema().steps ?? [];
|
|
447
|
+
return this.activeIndex() === steps.length - 1;
|
|
448
|
+
}, ...(ngDevMode ? [{ debugName: "isLast" }] : /* istanbul ignore next */ []));
|
|
449
|
+
constructor() {
|
|
450
|
+
// Reset the wizard whenever the schema input changes
|
|
451
|
+
effect(() => {
|
|
452
|
+
this.schema();
|
|
453
|
+
this.formService.goToStep(0);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
back() {
|
|
457
|
+
this.formService.prevStep();
|
|
458
|
+
}
|
|
459
|
+
next() {
|
|
460
|
+
this.formService.nextStep();
|
|
461
|
+
}
|
|
462
|
+
jumpTo(i) {
|
|
463
|
+
if (i <= this.activeIndex())
|
|
464
|
+
this.formService.goToStep(i);
|
|
465
|
+
}
|
|
466
|
+
submit() {
|
|
467
|
+
if (!this.formService.markAllAsTouchedAndValidate())
|
|
468
|
+
return;
|
|
469
|
+
const values = this.formService.buildSubmitPayload();
|
|
470
|
+
this.formSubmit.emit({
|
|
471
|
+
field: { config: { attributes: { inputType: 'button', buttonRole: 'submit' } } },
|
|
472
|
+
values,
|
|
473
|
+
valid: true,
|
|
474
|
+
type: 'submit',
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/** Pass-through when the inner form emits formSubmit (e.g. via an inline button) */
|
|
478
|
+
onSubmit(e) {
|
|
479
|
+
this.formSubmit.emit(e);
|
|
480
|
+
}
|
|
481
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: NgxJsonFormStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
482
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.10", type: NgxJsonFormStepperComponent, isStandalone: true, selector: "ngx-json-form-stepper", inputs: { schema: { classPropertyName: "schema", publicName: "schema", isSignal: true, isRequired: true, transformFunction: null }, submitLabel: { classPropertyName: "submitLabel", publicName: "submitLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formSubmit: "formSubmit", formChange: "formChange" }, ngImport: i0, template: `
|
|
483
|
+
@if (schema().steps?.length) {
|
|
484
|
+
<div class="ngx-stepper">
|
|
485
|
+
<!-- Step indicators -->
|
|
486
|
+
<ol class="ngx-stepper-bar">
|
|
487
|
+
@for (step of schema().steps; track step.id) {
|
|
488
|
+
<li
|
|
489
|
+
class="ngx-stepper-item"
|
|
490
|
+
[ngClass]="{
|
|
491
|
+
active: $index === activeIndex(),
|
|
492
|
+
done: $index < activeIndex()
|
|
493
|
+
}"
|
|
494
|
+
(click)="jumpTo($index)"
|
|
495
|
+
>
|
|
496
|
+
<span class="ngx-stepper-num">
|
|
497
|
+
@if ($index < activeIndex()) {
|
|
498
|
+
<i class="pi pi-check"></i>
|
|
499
|
+
} @else {
|
|
500
|
+
{{ $index + 1 }}
|
|
501
|
+
}
|
|
502
|
+
</span>
|
|
503
|
+
<span class="ngx-stepper-label">
|
|
504
|
+
@if (step.icon) {
|
|
505
|
+
<i [class]="step.icon"></i>
|
|
506
|
+
}
|
|
507
|
+
{{ step.title }}
|
|
508
|
+
</span>
|
|
509
|
+
</li>
|
|
510
|
+
}
|
|
511
|
+
</ol>
|
|
512
|
+
|
|
513
|
+
<!-- Step body -->
|
|
514
|
+
@if (activeStep(); as step) {
|
|
515
|
+
@if (step.description) {
|
|
516
|
+
<p class="ngx-stepper-desc">{{ step.description }}</p>
|
|
517
|
+
}
|
|
518
|
+
<ngx-json-form
|
|
519
|
+
[schema]="schema()"
|
|
520
|
+
[stepFields]="step.fields"
|
|
521
|
+
(formChange)="formChange.emit($event)"
|
|
522
|
+
(formSubmit)="onSubmit($event)"
|
|
523
|
+
/>
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
<!-- Controls -->
|
|
527
|
+
<div class="ngx-stepper-actions">
|
|
528
|
+
<button
|
|
529
|
+
pButton
|
|
530
|
+
type="button"
|
|
531
|
+
class="p-button-text"
|
|
532
|
+
label="Back"
|
|
533
|
+
icon="pi pi-arrow-left"
|
|
534
|
+
[disabled]="activeIndex() === 0"
|
|
535
|
+
(click)="back()"
|
|
536
|
+
></button>
|
|
537
|
+
@if (!isLast()) {
|
|
538
|
+
<button
|
|
539
|
+
pButton
|
|
540
|
+
type="button"
|
|
541
|
+
label="Next"
|
|
542
|
+
icon="pi pi-arrow-right"
|
|
543
|
+
iconPos="right"
|
|
544
|
+
(click)="next()"
|
|
545
|
+
></button>
|
|
546
|
+
} @else {
|
|
547
|
+
<button
|
|
548
|
+
pButton
|
|
549
|
+
type="button"
|
|
550
|
+
[label]="submitLabel()"
|
|
551
|
+
icon="pi pi-check"
|
|
552
|
+
iconPos="right"
|
|
553
|
+
[disabled]="!formService.formValid()"
|
|
554
|
+
(click)="submit()"
|
|
555
|
+
></button>
|
|
556
|
+
}
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
}
|
|
560
|
+
`, isInline: true, styles: [".ngx-stepper{display:flex;flex-direction:column;gap:1.25rem}.ngx-stepper-bar{list-style:none;margin:0;padding:0;display:flex;gap:.5rem;align-items:stretch;border-bottom:1px solid var(--p-surface-border, #e5e7eb);padding-bottom:1rem;overflow-x:auto}.ngx-stepper-item{flex:1 1 0;min-width:0;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-radius:8px;cursor:pointer;color:var(--p-text-muted-color, #6b7280);font-size:.85rem;transition:background .15s,color .15s;-webkit-user-select:none;user-select:none}.ngx-stepper-item:hover{background:var(--p-surface-hover, #f3f4f6)}.ngx-stepper-item.active{color:var(--p-primary-700, #1d4ed8);background:var(--p-primary-50, #eff6ff)}.ngx-stepper-item.active .ngx-stepper-num{background:var(--p-primary-500, #3b82f6);color:#fff}.ngx-stepper-item.done{color:var(--p-primary-600, #2563eb)}.ngx-stepper-item.done .ngx-stepper-num{background:var(--p-primary-100, #dbeafe);color:var(--p-primary-700, #1d4ed8)}.ngx-stepper-num{flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:var(--p-surface-200, #e5e7eb);color:var(--p-text-muted-color, #6b7280);font-size:.78rem;font-weight:600}.ngx-stepper-label{display:inline-flex;align-items:center;gap:.4rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-stepper-desc{margin:0;font-size:.85rem;color:var(--p-text-muted-color, #6b7280)}.ngx-stepper-actions{display:flex;justify-content:space-between;border-top:1px solid var(--p-surface-border, #e5e7eb);padding-top:1rem}\n"], dependencies: [{ kind: "component", type: NgxJsonFormComponent, selector: "ngx-json-form", inputs: ["formTitle", "fieldsInput", "schema", "stepFields"], outputs: ["formSubmit", "formChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i11.ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "pButtonPT", "pButtonUnstyled", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
561
|
+
}
|
|
562
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: NgxJsonFormStepperComponent, decorators: [{
|
|
563
|
+
type: Component,
|
|
564
|
+
args: [{ selector: 'ngx-json-form-stepper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgxJsonFormComponent, ButtonModule, NgClass], template: `
|
|
565
|
+
@if (schema().steps?.length) {
|
|
566
|
+
<div class="ngx-stepper">
|
|
567
|
+
<!-- Step indicators -->
|
|
568
|
+
<ol class="ngx-stepper-bar">
|
|
569
|
+
@for (step of schema().steps; track step.id) {
|
|
570
|
+
<li
|
|
571
|
+
class="ngx-stepper-item"
|
|
572
|
+
[ngClass]="{
|
|
573
|
+
active: $index === activeIndex(),
|
|
574
|
+
done: $index < activeIndex()
|
|
575
|
+
}"
|
|
576
|
+
(click)="jumpTo($index)"
|
|
577
|
+
>
|
|
578
|
+
<span class="ngx-stepper-num">
|
|
579
|
+
@if ($index < activeIndex()) {
|
|
580
|
+
<i class="pi pi-check"></i>
|
|
581
|
+
} @else {
|
|
582
|
+
{{ $index + 1 }}
|
|
583
|
+
}
|
|
584
|
+
</span>
|
|
585
|
+
<span class="ngx-stepper-label">
|
|
586
|
+
@if (step.icon) {
|
|
587
|
+
<i [class]="step.icon"></i>
|
|
588
|
+
}
|
|
589
|
+
{{ step.title }}
|
|
590
|
+
</span>
|
|
591
|
+
</li>
|
|
592
|
+
}
|
|
593
|
+
</ol>
|
|
594
|
+
|
|
595
|
+
<!-- Step body -->
|
|
596
|
+
@if (activeStep(); as step) {
|
|
597
|
+
@if (step.description) {
|
|
598
|
+
<p class="ngx-stepper-desc">{{ step.description }}</p>
|
|
599
|
+
}
|
|
600
|
+
<ngx-json-form
|
|
601
|
+
[schema]="schema()"
|
|
602
|
+
[stepFields]="step.fields"
|
|
603
|
+
(formChange)="formChange.emit($event)"
|
|
604
|
+
(formSubmit)="onSubmit($event)"
|
|
605
|
+
/>
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
<!-- Controls -->
|
|
609
|
+
<div class="ngx-stepper-actions">
|
|
610
|
+
<button
|
|
611
|
+
pButton
|
|
612
|
+
type="button"
|
|
613
|
+
class="p-button-text"
|
|
614
|
+
label="Back"
|
|
615
|
+
icon="pi pi-arrow-left"
|
|
616
|
+
[disabled]="activeIndex() === 0"
|
|
617
|
+
(click)="back()"
|
|
618
|
+
></button>
|
|
619
|
+
@if (!isLast()) {
|
|
620
|
+
<button
|
|
621
|
+
pButton
|
|
622
|
+
type="button"
|
|
623
|
+
label="Next"
|
|
624
|
+
icon="pi pi-arrow-right"
|
|
625
|
+
iconPos="right"
|
|
626
|
+
(click)="next()"
|
|
627
|
+
></button>
|
|
628
|
+
} @else {
|
|
629
|
+
<button
|
|
630
|
+
pButton
|
|
631
|
+
type="button"
|
|
632
|
+
[label]="submitLabel()"
|
|
633
|
+
icon="pi pi-check"
|
|
634
|
+
iconPos="right"
|
|
635
|
+
[disabled]="!formService.formValid()"
|
|
636
|
+
(click)="submit()"
|
|
637
|
+
></button>
|
|
638
|
+
}
|
|
639
|
+
</div>
|
|
640
|
+
</div>
|
|
641
|
+
}
|
|
642
|
+
`, styles: [".ngx-stepper{display:flex;flex-direction:column;gap:1.25rem}.ngx-stepper-bar{list-style:none;margin:0;padding:0;display:flex;gap:.5rem;align-items:stretch;border-bottom:1px solid var(--p-surface-border, #e5e7eb);padding-bottom:1rem;overflow-x:auto}.ngx-stepper-item{flex:1 1 0;min-width:0;display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;border-radius:8px;cursor:pointer;color:var(--p-text-muted-color, #6b7280);font-size:.85rem;transition:background .15s,color .15s;-webkit-user-select:none;user-select:none}.ngx-stepper-item:hover{background:var(--p-surface-hover, #f3f4f6)}.ngx-stepper-item.active{color:var(--p-primary-700, #1d4ed8);background:var(--p-primary-50, #eff6ff)}.ngx-stepper-item.active .ngx-stepper-num{background:var(--p-primary-500, #3b82f6);color:#fff}.ngx-stepper-item.done{color:var(--p-primary-600, #2563eb)}.ngx-stepper-item.done .ngx-stepper-num{background:var(--p-primary-100, #dbeafe);color:var(--p-primary-700, #1d4ed8)}.ngx-stepper-num{flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:var(--p-surface-200, #e5e7eb);color:var(--p-text-muted-color, #6b7280);font-size:.78rem;font-weight:600}.ngx-stepper-label{display:inline-flex;align-items:center;gap:.4rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ngx-stepper-desc{margin:0;font-size:.85rem;color:var(--p-text-muted-color, #6b7280)}.ngx-stepper-actions{display:flex;justify-content:space-between;border-top:1px solid var(--p-surface-border, #e5e7eb);padding-top:1rem}\n"] }]
|
|
643
|
+
}], ctorParameters: () => [], propDecorators: { schema: [{ type: i0.Input, args: [{ isSignal: true, alias: "schema", required: true }] }], submitLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "submitLabel", required: false }] }], formSubmit: [{ type: i0.Output, args: ["formSubmit"] }], formChange: [{ type: i0.Output, args: ["formChange"] }] } });
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Generated bundle index. Do not edit.
|
|
647
|
+
*/
|
|
648
|
+
|
|
649
|
+
export { NgxJsonFormComponent, NgxJsonFormStepperComponent };
|
|
650
|
+
//# sourceMappingURL=ngx-json-forms-primeng.mjs.map
|