ngx-form-designer 0.0.13 → 0.0.15

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.

Potentially problematic release.


This version of ngx-form-designer might be problematic. Click here for more details.

@@ -3248,6 +3248,278 @@ function readNumber(value) {
3248
3248
  return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
3249
3249
  }
3250
3250
 
3251
+ function normalizeRuntimeOptions(rows) {
3252
+ if (!Array.isArray(rows))
3253
+ return [];
3254
+ const options = [];
3255
+ for (const row of rows) {
3256
+ if (!row || typeof row !== 'object')
3257
+ continue;
3258
+ const labelValue = row['label'];
3259
+ const keyValue = row['key'];
3260
+ if (typeof keyValue !== 'string' && typeof keyValue !== 'number') {
3261
+ continue;
3262
+ }
3263
+ const label = typeof labelValue === 'string'
3264
+ ? labelValue
3265
+ : String(labelValue ?? '');
3266
+ options.push({ label, value: keyValue });
3267
+ }
3268
+ return options;
3269
+ }
3270
+
3271
+ class RuntimeFieldDataAccessRegistryService {
3272
+ contexts = new WeakMap();
3273
+ register(engine, schema, input) {
3274
+ const api = input.fieldDataAccessApi;
3275
+ const normalizedMap = this.normalizeMap(input.fieldDataAccessMap);
3276
+ if (!api || normalizedMap.size === 0) {
3277
+ this.unregister(engine);
3278
+ return;
3279
+ }
3280
+ const formContentId = this.normalizeContentValue(input.formContentId) ?? schema.id;
3281
+ const formContentVersion = this.normalizeContentValue(input.formContentVersion) ?? schema.version;
3282
+ this.contexts.set(engine, {
3283
+ schema,
3284
+ map: normalizedMap,
3285
+ api,
3286
+ formContentId,
3287
+ formContentVersion,
3288
+ cache: new Map(),
3289
+ descendants: this.buildDescendantMap(schema, normalizedMap)
3290
+ });
3291
+ }
3292
+ unregister(engine) {
3293
+ this.contexts.delete(engine);
3294
+ }
3295
+ hasFieldAccess(field, engine) {
3296
+ if (!engine)
3297
+ return false;
3298
+ const context = this.contexts.get(engine);
3299
+ if (!context)
3300
+ return false;
3301
+ return context.map.has(field.id);
3302
+ }
3303
+ async getOptions(field, engine) {
3304
+ if (!engine)
3305
+ return undefined;
3306
+ const context = this.contexts.get(engine);
3307
+ if (!context)
3308
+ return undefined;
3309
+ const mapEntry = context.map.get(field.id);
3310
+ if (!mapEntry)
3311
+ return undefined;
3312
+ const payload = this.buildPayload(context, field, engine, mapEntry);
3313
+ if (!payload) {
3314
+ return [];
3315
+ }
3316
+ const cacheKey = this.getCacheKey(field.id, payload.exactPath);
3317
+ const cached = context.cache.get(cacheKey);
3318
+ if (cached) {
3319
+ return cached.map(option => ({ ...option }));
3320
+ }
3321
+ try {
3322
+ const rows = await context.api(payload);
3323
+ const options = normalizeRuntimeOptions(rows);
3324
+ context.cache.set(cacheKey, options);
3325
+ return options.map(option => ({ ...option }));
3326
+ }
3327
+ catch {
3328
+ return [];
3329
+ }
3330
+ }
3331
+ invalidateFieldAndDescendants(engine, fieldId) {
3332
+ const context = this.contexts.get(engine);
3333
+ if (!context)
3334
+ return;
3335
+ const toInvalidate = new Set([fieldId]);
3336
+ const queue = [fieldId];
3337
+ while (queue.length > 0) {
3338
+ const current = queue.shift();
3339
+ if (!current)
3340
+ continue;
3341
+ const children = context.descendants.get(current);
3342
+ if (!children)
3343
+ continue;
3344
+ for (const child of children) {
3345
+ if (toInvalidate.has(child))
3346
+ continue;
3347
+ toInvalidate.add(child);
3348
+ queue.push(child);
3349
+ }
3350
+ }
3351
+ for (const cacheKey of Array.from(context.cache.keys())) {
3352
+ const cacheFieldId = cacheKey.split('::')[0];
3353
+ if (toInvalidate.has(cacheFieldId)) {
3354
+ context.cache.delete(cacheKey);
3355
+ }
3356
+ }
3357
+ }
3358
+ buildPayload(context, field, engine, mapEntry) {
3359
+ const payload = {
3360
+ datasourceId: mapEntry.datasourceId,
3361
+ formContentId: context.formContentId,
3362
+ formContentVersion: context.formContentVersion,
3363
+ identifier: mapEntry.chainName,
3364
+ fieldId: field.id
3365
+ };
3366
+ if (!mapEntry.hierarchyAccess) {
3367
+ return payload;
3368
+ }
3369
+ const exactPath = this.resolveExactPath({
3370
+ schema: context.schema,
3371
+ engine,
3372
+ chainName: mapEntry.chainName,
3373
+ field
3374
+ });
3375
+ if (exactPath === null) {
3376
+ return undefined;
3377
+ }
3378
+ if (exactPath) {
3379
+ payload.exactPath = exactPath;
3380
+ }
3381
+ return payload;
3382
+ }
3383
+ resolveExactPath(params) {
3384
+ const tokens = params.chainName
3385
+ .split('#')
3386
+ .map(token => token.trim())
3387
+ .filter(Boolean);
3388
+ if (tokens.length === 0) {
3389
+ return '';
3390
+ }
3391
+ const currentIndex = tokens.findIndex(token => token === params.field.name || token === params.field.id);
3392
+ if (currentIndex <= 0) {
3393
+ return '';
3394
+ }
3395
+ const fieldsByToken = this.buildFieldLookup(params.schema);
3396
+ const pathSegments = [];
3397
+ for (let index = 0; index < currentIndex; index += 1) {
3398
+ const token = tokens[index];
3399
+ const parentField = fieldsByToken.get(token);
3400
+ if (!parentField) {
3401
+ return null;
3402
+ }
3403
+ const rawValue = params.engine.getValue(parentField.name);
3404
+ if (!this.hasMeaningfulValue(rawValue)) {
3405
+ return null;
3406
+ }
3407
+ pathSegments.push(this.encodePathSegment(rawValue));
3408
+ }
3409
+ return pathSegments.join('.');
3410
+ }
3411
+ encodePathSegment(value) {
3412
+ const stringValue = String(value);
3413
+ return encodeURIComponent(stringValue).replace(/\./g, '%2E');
3414
+ }
3415
+ hasMeaningfulValue(value) {
3416
+ if (value === undefined || value === null)
3417
+ return false;
3418
+ if (typeof value === 'string' && value.trim().length === 0)
3419
+ return false;
3420
+ return true;
3421
+ }
3422
+ buildFieldLookup(schema) {
3423
+ const lookup = new Map();
3424
+ for (const field of schema.fields) {
3425
+ lookup.set(field.id, field);
3426
+ if (field.name) {
3427
+ lookup.set(field.name, field);
3428
+ }
3429
+ }
3430
+ return lookup;
3431
+ }
3432
+ normalizeMap(mapInput) {
3433
+ const normalized = new Map();
3434
+ if (!mapInput || typeof mapInput !== 'object') {
3435
+ return normalized;
3436
+ }
3437
+ for (const [fieldId, rawEntry] of Object.entries(mapInput)) {
3438
+ if (!rawEntry || typeof rawEntry !== 'object')
3439
+ continue;
3440
+ const chainName = typeof rawEntry.chainName === 'string' ? rawEntry.chainName.trim() : '';
3441
+ const datasourceId = typeof rawEntry.datasourceId === 'string' ? rawEntry.datasourceId.trim() : '';
3442
+ if (!fieldId || !chainName || !datasourceId) {
3443
+ continue;
3444
+ }
3445
+ normalized.set(fieldId, {
3446
+ chainName,
3447
+ datasourceId,
3448
+ hierarchyAccess: !!rawEntry.hierarchyAccess
3449
+ });
3450
+ }
3451
+ return normalized;
3452
+ }
3453
+ normalizeContentValue(value) {
3454
+ if (typeof value !== 'string')
3455
+ return undefined;
3456
+ const trimmed = value.trim();
3457
+ return trimmed.length > 0 ? trimmed : undefined;
3458
+ }
3459
+ getCacheKey(fieldId, exactPath) {
3460
+ return `${fieldId}::${exactPath ?? ''}`;
3461
+ }
3462
+ buildDescendantMap(schema, normalizedMap) {
3463
+ const descendants = new Map();
3464
+ const fieldsByToken = this.buildFieldLookup(schema);
3465
+ const edgeMap = new Map();
3466
+ const addEdge = (from, to) => {
3467
+ if (!edgeMap.has(from)) {
3468
+ edgeMap.set(from, new Set());
3469
+ }
3470
+ edgeMap.get(from).add(to);
3471
+ };
3472
+ for (const field of schema.fields) {
3473
+ if (!field.dataConfig?.dependsOn?.length)
3474
+ continue;
3475
+ for (const dep of field.dataConfig.dependsOn) {
3476
+ const parentField = fieldsByToken.get(dep.fieldId);
3477
+ if (!parentField)
3478
+ continue;
3479
+ addEdge(parentField.id, field.id);
3480
+ }
3481
+ }
3482
+ for (const [, entry] of normalizedMap) {
3483
+ const chainFieldIds = entry.chainName
3484
+ .split('#')
3485
+ .map(token => token.trim())
3486
+ .filter(Boolean)
3487
+ .map(token => fieldsByToken.get(token)?.id)
3488
+ .filter((value) => !!value);
3489
+ for (let index = 0; index < chainFieldIds.length - 1; index += 1) {
3490
+ addEdge(chainFieldIds[index], chainFieldIds[index + 1]);
3491
+ }
3492
+ }
3493
+ for (const field of schema.fields) {
3494
+ const fieldId = field.id;
3495
+ const visited = new Set();
3496
+ const queue = [...(edgeMap.get(fieldId) ?? [])];
3497
+ while (queue.length > 0) {
3498
+ const current = queue.shift();
3499
+ if (!current || visited.has(current))
3500
+ continue;
3501
+ visited.add(current);
3502
+ const children = edgeMap.get(current);
3503
+ if (!children)
3504
+ continue;
3505
+ for (const child of children) {
3506
+ if (!visited.has(child)) {
3507
+ queue.push(child);
3508
+ }
3509
+ }
3510
+ }
3511
+ descendants.set(fieldId, visited);
3512
+ }
3513
+ return descendants;
3514
+ }
3515
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeFieldDataAccessRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
3516
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeFieldDataAccessRegistryService, providedIn: 'root' });
3517
+ }
3518
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RuntimeFieldDataAccessRegistryService, decorators: [{
3519
+ type: Injectable,
3520
+ args: [{ providedIn: 'root' }]
3521
+ }] });
3522
+
3251
3523
  const DEFAULT_UPLOAD_ENDPOINT = '/api/uploads';
3252
3524
  class JsonFormRendererComponent {
3253
3525
  designerState;
@@ -3258,6 +3530,10 @@ class JsonFormRendererComponent {
3258
3530
  breakpoint = 'xl';
3259
3531
  eventLogger;
3260
3532
  uploadOnSubmit = true;
3533
+ fieldDataAccessMap;
3534
+ fieldDataAccessApi;
3535
+ formContentId;
3536
+ formContentVersion;
3261
3537
  valueChange = new EventEmitter();
3262
3538
  groupedValueChange = new EventEmitter();
3263
3539
  combinedValueChange = new EventEmitter();
@@ -3267,6 +3543,7 @@ class JsonFormRendererComponent {
3267
3543
  engine;
3268
3544
  runner;
3269
3545
  uploadClient = inject(FILE_UPLOAD_CLIENT, { optional: true }) ?? inject(DefaultFileUploadClient);
3546
+ runtimeFieldDataAccessRegistry = inject(RuntimeFieldDataAccessRegistryService);
3270
3547
  constructor(designerState) {
3271
3548
  this.designerState = designerState;
3272
3549
  }
@@ -3278,17 +3555,26 @@ class JsonFormRendererComponent {
3278
3555
  // Reuse engine if ID matches to prevent full reload
3279
3556
  if (this.engine && this.schema.id === this.engine.getSchema().id) {
3280
3557
  this.engine.updateSchema(this.schema);
3558
+ this.syncRuntimeFieldDataAccessContext();
3281
3559
  }
3282
3560
  else {
3283
3561
  this.createEngine();
3284
3562
  }
3285
3563
  }
3564
+ if (changes['fieldDataAccessMap']
3565
+ || changes['fieldDataAccessApi']
3566
+ || changes['formContentId']
3567
+ || changes['formContentVersion']) {
3568
+ this.syncRuntimeFieldDataAccessContext();
3569
+ }
3286
3570
  }
3287
3571
  ngOnDestroy() {
3572
+ this.unregisterRuntimeFieldDataAccessContext();
3288
3573
  this.disposeRunner();
3289
3574
  }
3290
3575
  createEngine() {
3291
3576
  this.disposeRunner();
3577
+ this.unregisterRuntimeFieldDataAccessContext();
3292
3578
  if (this.schema) {
3293
3579
  // Dev-only guardrail check (Live/Preview modes)
3294
3580
  if (this.mode === 'live' || this.mode === 'preview') {
@@ -3298,6 +3584,7 @@ class JsonFormRendererComponent {
3298
3584
  }
3299
3585
  }
3300
3586
  this.engine = createFormEngine(this.schema, this.initialValues);
3587
+ this.syncRuntimeFieldDataAccessContext();
3301
3588
  // Create event runner if not in design mode
3302
3589
  if (this.mode !== 'design') {
3303
3590
  this.runner = new FormEventRunner(this.engine, this.eventLogger);
@@ -3311,6 +3598,21 @@ class JsonFormRendererComponent {
3311
3598
  void this.emitValuePayload(initialValues);
3312
3599
  }
3313
3600
  }
3601
+ syncRuntimeFieldDataAccessContext() {
3602
+ if (!this.engine || !this.schema)
3603
+ return;
3604
+ this.runtimeFieldDataAccessRegistry.register(this.engine, this.schema, {
3605
+ fieldDataAccessMap: this.fieldDataAccessMap,
3606
+ fieldDataAccessApi: this.fieldDataAccessApi,
3607
+ formContentId: this.formContentId,
3608
+ formContentVersion: this.formContentVersion
3609
+ });
3610
+ }
3611
+ unregisterRuntimeFieldDataAccessContext() {
3612
+ if (!this.engine)
3613
+ return;
3614
+ this.runtimeFieldDataAccessRegistry.unregister(this.engine);
3615
+ }
3314
3616
  async emitValuePayload(values) {
3315
3617
  const fieldValueMap = await this.buildFieldValueMap(values);
3316
3618
  const groupedValues = this.buildGroupedValues(fieldValueMap);
@@ -3671,7 +3973,7 @@ class JsonFormRendererComponent {
3671
3973
  || typeof record['type'] === 'string';
3672
3974
  }
3673
3975
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormRendererComponent, deps: [{ token: DesignerStateService }], target: i0.ɵɵFactoryTarget.Component });
3674
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormRendererComponent, isStandalone: true, selector: "app-json-form-renderer", inputs: { schema: "schema", initialValues: "initialValues", mode: "mode", device: "device", breakpoint: "breakpoint", eventLogger: "eventLogger", uploadOnSubmit: "uploadOnSubmit" }, outputs: { valueChange: "valueChange", groupedValueChange: "groupedValueChange", combinedValueChange: "combinedValueChange", validationChange: "validationChange", uploadedFilesChange: "uploadedFilesChange", formSubmit: "formSubmit" }, usesOnChanges: true, ngImport: i0, template: `
3976
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: JsonFormRendererComponent, isStandalone: true, selector: "app-json-form-renderer", inputs: { schema: "schema", initialValues: "initialValues", mode: "mode", device: "device", breakpoint: "breakpoint", eventLogger: "eventLogger", uploadOnSubmit: "uploadOnSubmit", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { valueChange: "valueChange", groupedValueChange: "groupedValueChange", combinedValueChange: "combinedValueChange", validationChange: "validationChange", uploadedFilesChange: "uploadedFilesChange", formSubmit: "formSubmit" }, usesOnChanges: true, ngImport: i0, template: `
3675
3977
  <div class="form-renderer-container"
3676
3978
  [class.is-mobile]="device === 'mobile'"
3677
3979
  [class.is-design]="mode === 'design'">
@@ -3728,6 +4030,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
3728
4030
  type: Input
3729
4031
  }], uploadOnSubmit: [{
3730
4032
  type: Input
4033
+ }], fieldDataAccessMap: [{
4034
+ type: Input
4035
+ }], fieldDataAccessApi: [{
4036
+ type: Input
4037
+ }], formContentId: [{
4038
+ type: Input
4039
+ }], formContentVersion: [{
4040
+ type: Input
3731
4041
  }], valueChange: [{
3732
4042
  type: Output
3733
4043
  }], groupedValueChange: [{
@@ -3919,12 +4229,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
3919
4229
 
3920
4230
  class FormViewerComponent {
3921
4231
  schema;
3922
- data = {};
4232
+ set data(value) {
4233
+ this._data = value ?? {};
4234
+ this.normalizedInitialValues = this.normalizeInitialValues(this._data);
4235
+ }
4236
+ get data() {
4237
+ return this._data;
4238
+ }
3923
4239
  options = {
3924
4240
  showSubmitButton: false,
3925
4241
  submitLabel: 'Submit',
3926
4242
  emitOnChange: true
3927
4243
  };
4244
+ fieldDataAccessMap;
4245
+ fieldDataAccessApi;
4246
+ formContentId;
4247
+ formContentVersion;
3928
4248
  formDataChange = new EventEmitter();
3929
4249
  formValidationChange = new EventEmitter();
3930
4250
  uploadedFilesChange = new EventEmitter();
@@ -3936,6 +4256,8 @@ class FormViewerComponent {
3936
4256
  zone = inject(NgZone);
3937
4257
  resizeObserver;
3938
4258
  currentValues = {};
4259
+ _data = {};
4260
+ normalizedInitialValues = {};
3939
4261
  ngOnInit() {
3940
4262
  this.setupResizeObserver();
3941
4263
  }
@@ -4000,17 +4322,89 @@ class FormViewerComponent {
4000
4322
  // Re-emit upwards
4001
4323
  this.submit.emit(result);
4002
4324
  }
4325
+ normalizeInitialValues(input) {
4326
+ if (!this.isRecord(input))
4327
+ return {};
4328
+ if (!this.isOutputShapeCandidate(input))
4329
+ return input;
4330
+ const outputValues = new Map();
4331
+ this.collectOutputShapeFields(input, outputValues);
4332
+ if (outputValues.size === 0)
4333
+ return input;
4334
+ const normalized = {};
4335
+ for (const [fieldName, value] of outputValues.entries()) {
4336
+ normalized[fieldName] = this.deserializeFieldValue(value.fieldValue);
4337
+ }
4338
+ return normalized;
4339
+ }
4340
+ collectOutputShapeFields(value, output) {
4341
+ if (this.isFormFieldValue(value)) {
4342
+ output.set(value.fieldName, value);
4343
+ return;
4344
+ }
4345
+ if (Array.isArray(value)) {
4346
+ return;
4347
+ }
4348
+ if (!this.isRecord(value))
4349
+ return;
4350
+ for (const entry of Object.values(value)) {
4351
+ this.collectOutputShapeFields(entry, output);
4352
+ }
4353
+ }
4354
+ deserializeFieldValue(value) {
4355
+ if (Array.isArray(value)) {
4356
+ if (value.every(item => this.isRecord(item) && this.isFormFieldMap(item))) {
4357
+ return value.map(item => this.formFieldMapToNameMap(item));
4358
+ }
4359
+ return value;
4360
+ }
4361
+ if (this.isRecord(value) && this.isFormFieldMap(value)) {
4362
+ return this.formFieldMapToNameMap(value);
4363
+ }
4364
+ return value;
4365
+ }
4366
+ formFieldMapToNameMap(valueMap) {
4367
+ const normalized = {};
4368
+ for (const entry of Object.values(valueMap)) {
4369
+ if (!this.isFormFieldValue(entry))
4370
+ continue;
4371
+ normalized[entry.fieldName] = this.deserializeFieldValue(entry.fieldValue);
4372
+ }
4373
+ return normalized;
4374
+ }
4375
+ isOutputShapeCandidate(value) {
4376
+ return Object.values(value).some(entry => this.isFormFieldValue(entry) || (this.isRecord(entry) && this.isFormFieldMap(entry)));
4377
+ }
4378
+ isFormFieldMap(value) {
4379
+ const entries = Object.values(value);
4380
+ if (entries.length === 0)
4381
+ return true;
4382
+ return entries.every(entry => this.isFormFieldValue(entry));
4383
+ }
4384
+ isFormFieldValue(value) {
4385
+ if (!this.isRecord(value))
4386
+ return false;
4387
+ return typeof value['fieldName'] === 'string'
4388
+ && Object.hasOwn(value, 'fieldValue');
4389
+ }
4390
+ isRecord(value) {
4391
+ return !!value && typeof value === 'object';
4392
+ }
4003
4393
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4004
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormViewerComponent, isStandalone: true, selector: "app-form-viewer", inputs: { schema: "schema", data: "data", options: "options" }, outputs: { formDataChange: "formDataChange", formValidationChange: "formValidationChange", uploadedFilesChange: "uploadedFilesChange", submit: "submit" }, viewQueries: [{ propertyName: "renderer", first: true, predicate: JsonFormRendererComponent, descendants: true }], ngImport: i0, template: `
4394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormViewerComponent, isStandalone: true, selector: "app-form-viewer", inputs: { schema: "schema", data: "data", options: "options", fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, outputs: { formDataChange: "formDataChange", formValidationChange: "formValidationChange", uploadedFilesChange: "uploadedFilesChange", submit: "submit" }, viewQueries: [{ propertyName: "renderer", first: true, predicate: JsonFormRendererComponent, descendants: true }], ngImport: i0, template: `
4005
4395
  <div class="form-viewer-container flex flex-col h-full">
4006
4396
  <!-- Renderer -->
4007
4397
  <div class="flex-1 min-h-0 overflow-y-auto">
4008
4398
  <app-json-form-renderer
4009
4399
  [schema]="schema"
4010
- [initialValues]="data"
4400
+ [initialValues]="normalizedInitialValues"
4011
4401
  [mode]="'live'"
4012
4402
  [breakpoint]="breakpoint()"
4013
4403
  [uploadOnSubmit]="true"
4404
+ [fieldDataAccessMap]="fieldDataAccessMap"
4405
+ [fieldDataAccessApi]="fieldDataAccessApi"
4406
+ [formContentId]="formContentId"
4407
+ [formContentVersion]="formContentVersion"
4014
4408
  (valueChange)="onValueChange($event)"
4015
4409
  (validationChange)="onValidationChange($event)"
4016
4410
  (uploadedFilesChange)="onUploadedFilesChange($event)"
@@ -4029,7 +4423,7 @@ class FormViewerComponent {
4029
4423
  </button>
4030
4424
  </div>
4031
4425
  </div>
4032
- `, isInline: true, styles: [":host{display:block;height:100%;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4426
+ `, isInline: true, styles: [":host{display:block;height:100%;width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4033
4427
  }
4034
4428
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormViewerComponent, decorators: [{
4035
4429
  type: Component,
@@ -4039,10 +4433,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
4039
4433
  <div class="flex-1 min-h-0 overflow-y-auto">
4040
4434
  <app-json-form-renderer
4041
4435
  [schema]="schema"
4042
- [initialValues]="data"
4436
+ [initialValues]="normalizedInitialValues"
4043
4437
  [mode]="'live'"
4044
4438
  [breakpoint]="breakpoint()"
4045
4439
  [uploadOnSubmit]="true"
4440
+ [fieldDataAccessMap]="fieldDataAccessMap"
4441
+ [fieldDataAccessApi]="fieldDataAccessApi"
4442
+ [formContentId]="formContentId"
4443
+ [formContentVersion]="formContentVersion"
4046
4444
  (valueChange)="onValueChange($event)"
4047
4445
  (validationChange)="onValidationChange($event)"
4048
4446
  (uploadedFilesChange)="onUploadedFilesChange($event)"
@@ -4069,6 +4467,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
4069
4467
  type: Input
4070
4468
  }], options: [{
4071
4469
  type: Input
4470
+ }], fieldDataAccessMap: [{
4471
+ type: Input
4472
+ }], fieldDataAccessApi: [{
4473
+ type: Input
4474
+ }], formContentId: [{
4475
+ type: Input
4476
+ }], formContentVersion: [{
4477
+ type: Input
4072
4478
  }], formDataChange: [{
4073
4479
  type: Output
4074
4480
  }], formValidationChange: [{
@@ -5828,7 +6234,7 @@ class LayoutCanvasComponent {
5828
6234
 
5829
6235
  <!-- Hidden file input for import -->
5830
6236
  <input type="file" #fileInput accept=".json" (change)="onFileSelected($event)" style="display: none;">
5831
- `, isInline: true, styles: [".canvas-grid{background-image:radial-gradient(rgba(148,163,184,.35) 1px,transparent 1px);background-size:18px 18px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
6237
+ `, isInline: true, styles: [".canvas-grid{background-image:radial-gradient(rgba(148,163,184,.35) 1px,transparent 1px);background-size:18px 18px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
5832
6238
  }
5833
6239
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: LayoutCanvasComponent, decorators: [{
5834
6240
  type: Component,
@@ -14862,6 +15268,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
14862
15268
 
14863
15269
  class FormPreviewComponent {
14864
15270
  state;
15271
+ fieldDataAccessMap;
15272
+ fieldDataAccessApi;
15273
+ formContentId;
15274
+ formContentVersion;
14865
15275
  breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
14866
15276
  breakpoint = signal('xl');
14867
15277
  // Derived device type for renderer compatibility
@@ -14965,7 +15375,7 @@ class FormPreviewComponent {
14965
15375
  return /^[A-Za-z0-9+/]+={0,2}$/.test(value);
14966
15376
  }
14967
15377
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormPreviewComponent, deps: [{ token: DesignerStateService }], target: i0.ɵɵFactoryTarget.Component });
14968
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormPreviewComponent, isStandalone: true, selector: "app-form-preview", ngImport: i0, template: `
15378
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: FormPreviewComponent, isStandalone: true, selector: "app-form-preview", inputs: { fieldDataAccessMap: "fieldDataAccessMap", fieldDataAccessApi: "fieldDataAccessApi", formContentId: "formContentId", formContentVersion: "formContentVersion" }, ngImport: i0, template: `
14969
15379
  <div class="fixed inset-0 bg-white z-[100] flex flex-col animate-in fade-in duration-200">
14970
15380
  <!-- Toolbar -->
14971
15381
  <div class="h-14 border-b border-gray-200 flex items-center justify-between px-4 bg-white shadow-sm shrink-0">
@@ -15015,6 +15425,10 @@ class FormPreviewComponent {
15015
15425
  mode="live"
15016
15426
  [device]="activeDevice()"
15017
15427
  [breakpoint]="breakpoint()"
15428
+ [fieldDataAccessMap]="fieldDataAccessMap"
15429
+ [fieldDataAccessApi]="fieldDataAccessApi"
15430
+ [formContentId]="formContentId"
15431
+ [formContentVersion]="formContentVersion"
15018
15432
  (valueChange)="updateData($event)"
15019
15433
  (combinedValueChange)="updateCombinedData($event)">
15020
15434
  </app-json-form-renderer>
@@ -15039,7 +15453,7 @@ class FormPreviewComponent {
15039
15453
  </div>
15040
15454
  </div>
15041
15455
  </div>
15042
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
15456
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: i2.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
15043
15457
  }
15044
15458
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormPreviewComponent, decorators: [{
15045
15459
  type: Component,
@@ -15097,6 +15511,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
15097
15511
  mode="live"
15098
15512
  [device]="activeDevice()"
15099
15513
  [breakpoint]="breakpoint()"
15514
+ [fieldDataAccessMap]="fieldDataAccessMap"
15515
+ [fieldDataAccessApi]="fieldDataAccessApi"
15516
+ [formContentId]="formContentId"
15517
+ [formContentVersion]="formContentVersion"
15100
15518
  (valueChange)="updateData($event)"
15101
15519
  (combinedValueChange)="updateCombinedData($event)">
15102
15520
  </app-json-form-renderer>
@@ -15123,7 +15541,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
15123
15541
  </div>
15124
15542
  `
15125
15543
  }]
15126
- }], ctorParameters: () => [{ type: DesignerStateService }] });
15544
+ }], ctorParameters: () => [{ type: DesignerStateService }], propDecorators: { fieldDataAccessMap: [{
15545
+ type: Input
15546
+ }], fieldDataAccessApi: [{
15547
+ type: Input
15548
+ }], formContentId: [{
15549
+ type: Input
15550
+ }], formContentVersion: [{
15551
+ type: Input
15552
+ }] } });
15127
15553
 
15128
15554
  class JsonFormDesignerComponent {
15129
15555
  flavor = 'form';
@@ -15162,7 +15588,7 @@ class JsonFormDesignerComponent {
15162
15588
  <!-- PREVIEW OVERLAY -->
15163
15589
  <app-form-preview *ngIf="state.isPreviewMode()"></app-form-preview>
15164
15590
  </div>
15165
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview" }] });
15591
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"] }] });
15166
15592
  }
15167
15593
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: JsonFormDesignerComponent, decorators: [{
15168
15594
  type: Component,
@@ -16580,7 +17006,7 @@ class FormDesignerShellComponent {
16580
17006
  </div>
16581
17007
  </section>
16582
17008
  </div>
16583
- `, isInline: true, styles: ["@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slide-in-right{animation:slideInRight .3s cubic-bezier(.16,1,.3,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: JsonFormDesignerComponent, selector: "app-json-form-designer", inputs: ["flavor"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: EmailRendererComponent, selector: "app-email-renderer", inputs: ["schema", "engine"] }, { kind: "component", type: GlobalDataManagerComponent, selector: "app-global-data-manager", outputs: ["close"] }] });
17009
+ `, isInline: true, styles: ["@keyframes slideInRight{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.animate-slide-in-right{animation:slideInRight .3s cubic-bezier(.16,1,.3,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.TitleCasePipe, name: "titlecase" }, { kind: "component", type: JsonFormDesignerComponent, selector: "app-json-form-designer", inputs: ["flavor"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }, { kind: "component", type: EmailRendererComponent, selector: "app-email-renderer", inputs: ["schema", "engine"] }, { kind: "component", type: GlobalDataManagerComponent, selector: "app-global-data-manager", outputs: ["close"] }] });
16584
17010
  }
16585
17011
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: FormDesignerShellComponent, decorators: [{
16586
17012
  type: Component,
@@ -19543,7 +19969,7 @@ class WebsiteDesignerShellComponent {
19543
19969
 
19544
19970
  <input type="file" #projectFileInput accept=".json" (change)="onProjectFileSelected($event)" class="hidden">
19545
19971
  </div>
19546
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
19972
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i3.CdkDropListGroup, selector: "[cdkDropListGroup]", inputs: ["cdkDropListGroupDisabled"], exportAs: ["cdkDropListGroup"] }, { kind: "ngmodule", type: UiIconModule }, { kind: "component", type: FieldPaletteComponent, selector: "app-field-palette", inputs: ["sectionLibrary", "pages", "activePageId", "canRemovePage", "savedSections", "bricks"], outputs: ["sectionInsert", "pageAdd", "pageSelect", "pageRemove", "pageRename", "pageRouteChange", "savedSectionInsert", "savedSectionRemove", "savedSectionCreateRequested"] }, { kind: "component", type: LayoutCanvasComponent, selector: "app-layout-canvas", inputs: ["previewMode"], outputs: ["previewRequested"] }, { kind: "component", type: PropertiesPanelComponent, selector: "app-properties-panel" }, { kind: "component", type: FormPreviewComponent, selector: "app-form-preview", inputs: ["fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
19547
19973
  }
19548
19974
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: WebsiteDesignerShellComponent, decorators: [{
19549
19975
  type: Component,
@@ -21519,7 +21945,7 @@ class WebsitePreviewShellComponent {
21519
21945
  }
21520
21946
  </main>
21521
21947
  </div>
21522
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
21948
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: JsonFormRendererComponent, selector: "app-json-form-renderer", inputs: ["schema", "initialValues", "mode", "device", "breakpoint", "eventLogger", "uploadOnSubmit", "fieldDataAccessMap", "fieldDataAccessApi", "formContentId", "formContentVersion"], outputs: ["valueChange", "groupedValueChange", "combinedValueChange", "validationChange", "uploadedFilesChange", "formSubmit"] }] });
21523
21949
  }
21524
21950
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: WebsitePreviewShellComponent, decorators: [{
21525
21951
  type: Component,
@@ -21660,7 +22086,12 @@ function getEffectiveDataConfig(field) {
21660
22086
  const DATA_PROVIDER = new InjectionToken('DATA_PROVIDER');
21661
22087
  class DefaultDataProvider extends DataProvider {
21662
22088
  client = inject(DATA_SOURCE_CLIENT, { optional: true }) || inject(DefaultDataSourceClient);
22089
+ runtimeFieldDataAccessRegistry = inject(RuntimeFieldDataAccessRegistryService);
21663
22090
  async getOptions(field, engine) {
22091
+ const runtimeOptions = await this.getRuntimeOptions(field, engine);
22092
+ if (runtimeOptions !== undefined) {
22093
+ return runtimeOptions;
22094
+ }
21664
22095
  const cfg = getEffectiveDataConfig(field);
21665
22096
  // 1. Resolve Rows
21666
22097
  let rows = await this.getRawRows(cfg, field, engine);
@@ -21678,6 +22109,10 @@ class DefaultDataProvider extends DataProvider {
21678
22109
  }));
21679
22110
  }
21680
22111
  async queryOptions(field, query, engine) {
22112
+ const runtimeOptions = await this.getRuntimeOptions(field, engine);
22113
+ if (runtimeOptions !== undefined) {
22114
+ return runtimeOptions;
22115
+ }
21681
22116
  const cfg = field.dataConfig;
21682
22117
  if (!cfg)
21683
22118
  return super.queryOptions(field, { ...query, term: query.term || '' }, engine);
@@ -21901,6 +22336,11 @@ class DefaultDataProvider extends DataProvider {
21901
22336
  }
21902
22337
  return undefined;
21903
22338
  }
22339
+ async getRuntimeOptions(field, engine) {
22340
+ if (!engine)
22341
+ return undefined;
22342
+ return this.runtimeFieldDataAccessRegistry.getOptions(field, engine);
22343
+ }
21904
22344
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DefaultDataProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
21905
22345
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DefaultDataProvider, providedIn: 'root' });
21906
22346
  }
@@ -22497,7 +22937,11 @@ class SelectWidgetComponent {
22497
22937
  requestId = 0;
22498
22938
  destroyRef = inject(DestroyRef);
22499
22939
  options = [];
22940
+ runtimeManagedField = false;
22941
+ runtimeOptionsLoaded = false;
22942
+ dependencyValueSnapshot = new Map();
22500
22943
  dataProvider = inject(DATA_PROVIDER, { optional: true }) || inject(DefaultDataProvider);
22944
+ runtimeFieldDataAccessRegistry = inject(RuntimeFieldDataAccessRegistryService);
22501
22945
  get fieldId() {
22502
22946
  return `field-${this.config.id}`;
22503
22947
  }
@@ -22532,6 +22976,7 @@ class SelectWidgetComponent {
22532
22976
  .subscribe(val => {
22533
22977
  if (this.engine) {
22534
22978
  this.engine.setValue(this.config.name, val);
22979
+ this.runtimeFieldDataAccessRegistry.invalidateFieldAndDescendants(this.engine, this.config.id);
22535
22980
  this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'change', value: val });
22536
22981
  if (this.control.dirty) {
22537
22982
  this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'dirty' });
@@ -22539,10 +22984,21 @@ class SelectWidgetComponent {
22539
22984
  }
22540
22985
  });
22541
22986
  this.syncEnabledState();
22542
- await this.loadOptions();
22987
+ this.runtimeManagedField = this.runtimeFieldDataAccessRegistry.hasFieldAccess(this.config, this.engine);
22988
+ if (!this.runtimeManagedField) {
22989
+ await this.loadOptions();
22990
+ this.runtimeOptionsLoaded = true;
22991
+ }
22992
+ else if (this.hasSelectedValue()) {
22993
+ // Prefilled runtime-managed selects need initial options so the selected label renders.
22994
+ await this.loadOptions();
22995
+ this.runtimeOptionsLoaded = !this.loadError;
22996
+ }
22543
22997
  // Dependencies
22544
22998
  const dependencyIds = this.getDependencyFieldIds();
22545
22999
  if (this.engine) {
23000
+ const initialValues = this.engine.getValues();
23001
+ this.seedDependencySnapshotFromValues(dependencyIds, initialValues);
22546
23002
  this.engine.valueChanges$
22547
23003
  .pipe(takeUntilDestroyed(this.destroyRef))
22548
23004
  .subscribe(values => {
@@ -22552,12 +23008,19 @@ class SelectWidgetComponent {
22552
23008
  const depNames = schema.fields
22553
23009
  .filter(f => dependencyIds.includes(f.id))
22554
23010
  .map(f => f.name);
22555
- const touched = depNames.some(name => name in values);
22556
- if (touched) {
23011
+ if (this.haveDependencyValuesChanged(depNames, values)) {
23012
+ this.runtimeFieldDataAccessRegistry.invalidateFieldAndDescendants(this.engine, this.config.id);
23013
+ if (this.hasSelectedValue()) {
23014
+ this.control.setValue(null);
23015
+ }
22557
23016
  if (this.searchControl.value) {
22558
23017
  this.searchControl.setValue('', { emitEvent: false });
22559
23018
  }
22560
- this.loadOptions();
23019
+ this.options = [];
23020
+ this.runtimeOptionsLoaded = false;
23021
+ if (!this.runtimeManagedField) {
23022
+ this.loadOptions();
23023
+ }
22561
23024
  }
22562
23025
  }
22563
23026
  });
@@ -22638,10 +23101,16 @@ class SelectWidgetComponent {
22638
23101
  onFocus() {
22639
23102
  if (this.engine)
22640
23103
  this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'focus' });
23104
+ if (this.runtimeManagedField) {
23105
+ void this.ensureRuntimeOptionsLoaded();
23106
+ }
22641
23107
  }
22642
23108
  onClick() {
22643
23109
  if (this.engine)
22644
23110
  this.engine.emitUiEvent({ fieldId: this.config.id, fieldName: this.config.name, type: 'click' });
23111
+ if (this.runtimeManagedField) {
23112
+ void this.ensureRuntimeOptionsLoaded();
23113
+ }
22645
23114
  }
22646
23115
  onBlur() {
22647
23116
  if (this.engine) {
@@ -22660,6 +23129,49 @@ class SelectWidgetComponent {
22660
23129
  this.control.disable({ emitEvent: false });
22661
23130
  }
22662
23131
  }
23132
+ async ensureRuntimeOptionsLoaded() {
23133
+ if (!this.runtimeManagedField || this.loading)
23134
+ return;
23135
+ if (this.runtimeOptionsLoaded && this.options.length > 0)
23136
+ return;
23137
+ await this.loadOptions();
23138
+ if (!this.loadError) {
23139
+ this.runtimeOptionsLoaded = true;
23140
+ }
23141
+ }
23142
+ seedDependencySnapshotFromValues(dependencyIds, values) {
23143
+ if (!this.engine || dependencyIds.length === 0)
23144
+ return;
23145
+ const schema = this.engine.getSchema();
23146
+ const depNames = schema.fields
23147
+ .filter(field => dependencyIds.includes(field.id))
23148
+ .map(field => field.name);
23149
+ for (const depName of depNames) {
23150
+ this.dependencyValueSnapshot.set(depName, values[depName]);
23151
+ }
23152
+ }
23153
+ haveDependencyValuesChanged(dependencyNames, values) {
23154
+ let changed = false;
23155
+ for (const depName of dependencyNames) {
23156
+ const previousValue = this.dependencyValueSnapshot.get(depName);
23157
+ const nextValue = values[depName];
23158
+ if (!Object.is(previousValue, nextValue)) {
23159
+ changed = true;
23160
+ this.dependencyValueSnapshot.set(depName, nextValue);
23161
+ }
23162
+ }
23163
+ return changed;
23164
+ }
23165
+ hasSelectedValue() {
23166
+ const value = this.control.value;
23167
+ if (value === undefined || value === null)
23168
+ return false;
23169
+ if (typeof value === 'string')
23170
+ return value.length > 0;
23171
+ if (Array.isArray(value))
23172
+ return value.length > 0;
23173
+ return true;
23174
+ }
22663
23175
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SelectWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
22664
23176
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SelectWidgetComponent, isStandalone: true, selector: "app-select-widget", inputs: { config: "config", engine: "engine", control: "control" }, ngImport: i0, template: `
22665
23177
  <div class="w-full pb-4 font-sans" [class.hidden]="!visible" [ngStyle]="getWrapperStyles()">
@@ -28359,5 +28871,5 @@ function provideHttpDataSourceClient(config) {
28359
28871
  * Generated bundle index. Do not edit.
28360
28872
  */
28361
28873
 
28362
- export { APPEARANCE_FIELDS, CORE_DESIGNER_PLUGINS, CURRENT_SCHEMA_VERSION, DATA_PROVIDER, DATA_SOURCE_CLIENT, DEFAULT_TEMPLATE_LIBRARY, DEFAULT_WEBSITE_SECTIONS, DEFAULT_WIDGET_PACKS, DESIGNER_PLUGINS, DESIGNER_SECTIONS, DataCatalog, DataPanelComponent, DataProvider, DefaultDataProvider, DefaultDataSourceClient, DefaultFileUploadClient, DesignerContext, DesignerStateService, DynamicPropertiesComponent, EFFECTS_FIELDS, EMAIL_SAFE_STYLE_SECTIONS, EMAIL_WIDGETS, EmailRendererComponent, EventsPanelComponent, FIELD_WIDGETS, FILE_UPLOAD_CLIENT, FULL_WEB_STYLE_SECTIONS, FieldPaletteComponent, FormDesignerShellComponent, FormEngine, FormViewerComponent, GlobalDataManagerComponent, HTTP_DATA_SOURCE_CLIENT_CONFIG, HttpDataSourceClient, InMemoryDataCatalogService, InspectorAdvancedSectionComponent, InspectorBackgroundsSectionComponent, InspectorBordersSectionComponent, InspectorEffectsSectionComponent, InspectorLayoutSectionComponent, InspectorPositionSectionComponent, InspectorSizeSectionComponent, InspectorSpacingSectionComponent, InspectorTypographySectionComponent, JsonFormDesignerComponent, JsonFormRendererComponent, LAYOUT_FIELDS, LayoutCanvasComponent, LayoutNodeComponent, PAGE_WIDGETS, PropertiesPanelComponent, RulesPanelComponent, SPACING_BOX_MODEL_FIELD, SPACING_MARGIN_FIELDS, SPACING_PADDING_FIELDS, STANDARD_FORM_STYLE_SECTIONS, STYLE_APPEARANCE_SECTION, STYLE_EFFECTS_SECTION, STYLE_LAYOUT_SECTION, STYLE_SECTIONS, STYLE_SPACING_SECTION, STYLE_TRANSFORM_SECTION, STYLE_TYPOGRAPHY_SECTION, TRANSFORM_FIELDS, TYPOGRAPHY_FIELDS, ThemeService, UiAccordionComponent, UiBoxModelComponent, UiColorSwatchComponent, UiDimensionComponent, UiEdgeBoxComponent, UiFieldWrapperComponent, UiInputComponent, UiRangeNumberComponent, UiSelectIconComponent, UiTabComponent, UiTabsComponent, WIDGET_DEFINITIONS, WIDGET_ID_SEPARATOR, WebsiteBrickStudioComponent, WebsiteDesignerShellComponent, WebsitePreviewShellComponent, WebsiteProjectService, WidgetDefinitionResolverService, WidgetInspectorComponent, appendSectionToSchema, buildWidgetId, checkSchemaForApiOnlySources, createDefaultWebsiteBrick, createDefaultWebsiteBricks, createDefaultWebsiteTheme, createEmptySchema, createFormEngine, createPluginContext, createWebsiteBrick, createWebsitePage, createWebsiteProject, defineWidget, flattenPluginWidgets, getEffectiveDataConfig, getWidgetsForFlavor, inferSchema, mergeAndNormalize, normalizeStyle, parseCsv, parseJsonArray, parseSchema, provideDesignerPlugins, provideHttpDataSourceClient, serializeSchema, slugifyId, stripEmbeddedSourceData };
28874
+ export { APPEARANCE_FIELDS, CORE_DESIGNER_PLUGINS, CURRENT_SCHEMA_VERSION, DATA_PROVIDER, DATA_SOURCE_CLIENT, DEFAULT_TEMPLATE_LIBRARY, DEFAULT_WEBSITE_SECTIONS, DEFAULT_WIDGET_PACKS, DESIGNER_PLUGINS, DESIGNER_SECTIONS, DataCatalog, DataPanelComponent, DataProvider, DefaultDataProvider, DefaultDataSourceClient, DefaultFileUploadClient, DesignerContext, DesignerStateService, DynamicPropertiesComponent, EFFECTS_FIELDS, EMAIL_SAFE_STYLE_SECTIONS, EMAIL_WIDGETS, EmailRendererComponent, EventsPanelComponent, FIELD_WIDGETS, FILE_UPLOAD_CLIENT, FULL_WEB_STYLE_SECTIONS, FieldPaletteComponent, FormDesignerShellComponent, FormEngine, FormViewerComponent, GlobalDataManagerComponent, HTTP_DATA_SOURCE_CLIENT_CONFIG, HttpDataSourceClient, InMemoryDataCatalogService, InspectorAdvancedSectionComponent, InspectorBackgroundsSectionComponent, InspectorBordersSectionComponent, InspectorEffectsSectionComponent, InspectorLayoutSectionComponent, InspectorPositionSectionComponent, InspectorSizeSectionComponent, InspectorSpacingSectionComponent, InspectorTypographySectionComponent, JsonFormDesignerComponent, JsonFormRendererComponent, LAYOUT_FIELDS, LayoutCanvasComponent, LayoutNodeComponent, PAGE_WIDGETS, PropertiesPanelComponent, RulesPanelComponent, RuntimeFieldDataAccessRegistryService, SPACING_BOX_MODEL_FIELD, SPACING_MARGIN_FIELDS, SPACING_PADDING_FIELDS, STANDARD_FORM_STYLE_SECTIONS, STYLE_APPEARANCE_SECTION, STYLE_EFFECTS_SECTION, STYLE_LAYOUT_SECTION, STYLE_SECTIONS, STYLE_SPACING_SECTION, STYLE_TRANSFORM_SECTION, STYLE_TYPOGRAPHY_SECTION, TRANSFORM_FIELDS, TYPOGRAPHY_FIELDS, ThemeService, UiAccordionComponent, UiBoxModelComponent, UiColorSwatchComponent, UiDimensionComponent, UiEdgeBoxComponent, UiFieldWrapperComponent, UiInputComponent, UiRangeNumberComponent, UiSelectIconComponent, UiTabComponent, UiTabsComponent, WIDGET_DEFINITIONS, WIDGET_ID_SEPARATOR, WebsiteBrickStudioComponent, WebsiteDesignerShellComponent, WebsitePreviewShellComponent, WebsiteProjectService, WidgetDefinitionResolverService, WidgetInspectorComponent, appendSectionToSchema, buildWidgetId, checkSchemaForApiOnlySources, createDefaultWebsiteBrick, createDefaultWebsiteBricks, createDefaultWebsiteTheme, createEmptySchema, createFormEngine, createPluginContext, createWebsiteBrick, createWebsitePage, createWebsiteProject, defineWidget, flattenPluginWidgets, getEffectiveDataConfig, getWidgetsForFlavor, inferSchema, mergeAndNormalize, normalizeRuntimeOptions, normalizeStyle, parseCsv, parseJsonArray, parseSchema, provideDesignerPlugins, provideHttpDataSourceClient, serializeSchema, slugifyId, stripEmbeddedSourceData };
28363
28875
  //# sourceMappingURL=ngx-form-designer.mjs.map