commons-shared-web-ui 0.0.63 → 0.0.64

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.
@@ -5334,7 +5334,7 @@ class SmartFormComponent {
5334
5334
  if (!rawCfg)
5335
5335
  return of([]);
5336
5336
  const cfg = this._normalizeHierarchyCfg(rawCfg);
5337
- if (!cfg.templateApiUrl)
5337
+ if (!cfg.templateApiUrl && !cfg.templateData)
5338
5338
  return of([]);
5339
5339
  return this._fetchHierarchyTemplate(cfg).pipe(map((template) => template ? this._buildHierarchyFields(cfg, template) : []), catchError(() => of([])));
5340
5340
  }
@@ -5351,6 +5351,8 @@ class SmartFormComponent {
5351
5351
  templateSelect: ta['select'] || 'default',
5352
5352
  templateSelectField: ta['selectField'] || 'isDefault',
5353
5353
  templateSelectCode: ta['selectCode'],
5354
+ templateSelectId: ta['selectId'],
5355
+ templateData: ta['data'],
5354
5356
  rootCodePath: st['rootCodePath'] || 'rootClassCode',
5355
5357
  templateCodePath: st['templateCodePath'] || 'templateCode',
5356
5358
  hierarchyListPath: st['hierarchyListPath'] || 'mdmclasshierarchytemplatestructList',
@@ -5398,6 +5400,11 @@ class SmartFormComponent {
5398
5400
  };
5399
5401
  }
5400
5402
  _fetchHierarchyTemplate(cfg) {
5403
+ // Caller already resolved the exact template object — use it as-is, skipping the HTTP GET
5404
+ // and the templateSelect/templateSelectId matching entirely (there's nothing left to pick
5405
+ // between). See HierarchyCfg.templateData for the staleness tradeoff this accepts.
5406
+ if (cfg.templateData)
5407
+ return of(cfg.templateData);
5401
5408
  const headers = this.getHeaders();
5402
5409
  return this.http.get(cfg.templateApiUrl, { headers }).pipe(map((response) => {
5403
5410
  let list;
@@ -5417,6 +5424,15 @@ class SmartFormComponent {
5417
5424
  if (cfg.templateSelect === 'byCode') {
5418
5425
  return list.find((t) => this._getPathValue(t, cfg.templateCodePath) === cfg.templateSelectCode) || list[0];
5419
5426
  }
5427
+ if (cfg.templateSelect === 'byId') {
5428
+ // Multiple templates can share the same templateCode (distinguished by templateName,
5429
+ // with one flagged isDefault) — 'byCode' alone can't disambiguate between them, so this
5430
+ // matches the exact template the admin picked by its unique numeric id instead. Falls
5431
+ // back to the tenant default (then list[0]) if the id no longer matches anything.
5432
+ return list.find((t) => t.id === cfg.templateSelectId)
5433
+ || list.find((t) => !!t[cfg.templateSelectField])
5434
+ || list[0];
5435
+ }
5420
5436
  return list.find((t) => !!t[cfg.templateSelectField]) || list[0];
5421
5437
  }), catchError(() => of(null)));
5422
5438
  }
@@ -8173,6 +8189,8 @@ class FormSchemaTreeService {
8173
8189
  'GENERATED': 'generated',
8174
8190
  'CHIP': 'chip',
8175
8191
  'LOCATION': 'location',
8192
+ 'GEOGRAPHY_DYNAMIC': 'geography',
8193
+ 'GEOGRAPHY_NODE': 'geographyNode',
8176
8194
  'GROUP': 'group',
8177
8195
  'SUBFIELDS': 'section',
8178
8196
  };
@@ -8237,11 +8255,11 @@ class FormSchemaTreeService {
8237
8255
  else if (child.type === 'ROW' && child.children?.length) {
8238
8256
  // ROW children are leaf fields
8239
8257
  for (const rowChild of child.children) {
8240
- leafFields.push(this._buildFieldNode(rowChild));
8258
+ leafFields.push(...this._buildFieldNodesFor(rowChild));
8241
8259
  }
8242
8260
  }
8243
8261
  else {
8244
- leafFields.push(this._buildFieldNode(child));
8262
+ leafFields.push(...this._buildFieldNodesFor(child));
8245
8263
  }
8246
8264
  }
8247
8265
  // Flush remaining leaf fields
@@ -8260,11 +8278,11 @@ class FormSchemaTreeService {
8260
8278
  }
8261
8279
  else if (child.type === 'ROW' && child.children?.length) {
8262
8280
  for (const rowChild of child.children) {
8263
- fields.push(this._buildFieldNode(rowChild));
8281
+ fields.push(...this._buildFieldNodesFor(rowChild));
8264
8282
  }
8265
8283
  }
8266
8284
  else {
8267
- fields.push(this._buildFieldNode(child));
8285
+ fields.push(...this._buildFieldNodesFor(child));
8268
8286
  }
8269
8287
  }
8270
8288
  const isVisible = field.isEnabled ?? field.visible ?? true;
@@ -8296,6 +8314,38 @@ class FormSchemaTreeService {
8296
8314
  isLocked: field.readonly === true,
8297
8315
  };
8298
8316
  }
8317
+ /**
8318
+ * Normal leaf fields produce exactly one SelectionFieldNode. A GEOGRAPHY_DYNAMIC field is
8319
+ * special-cased: it expands into the whole-block toggle PLUS one synthetic toggle per
8320
+ * hierarchy level declared in geographyConfig.field.nodes (e.g. Country/State/District), so a
8321
+ * business user can show/hide individual levels instead of only the entire address block.
8322
+ * This is purely additive to every other field type's tree — see _applyGeographyNodeSelections
8323
+ * for the matching write-back half.
8324
+ */
8325
+ _buildFieldNodesFor(field) {
8326
+ if (field.type === 'GEOGRAPHY_DYNAMIC') {
8327
+ return this._buildGeographyFieldNodes(field);
8328
+ }
8329
+ return [this._buildFieldNode(field)];
8330
+ }
8331
+ /** See _buildFieldNodesFor. Synthetic per-level nodes are ephemeral (rebuilt on every parse from
8332
+ * geographyConfig.field.nodes) — they don't exist as real schema children, only as a nested map
8333
+ * on the parent GEOGRAPHY_DYNAMIC field, so they carry a distinguishing `name` for name-keyed
8334
+ * matching in _applyGeographyNodeSelections rather than object identity. */
8335
+ _buildGeographyFieldNodes(field) {
8336
+ const nodes = [this._buildFieldNode(field)];
8337
+ const geoNodes = field.geographyConfig?.field?.nodes ?? {};
8338
+ for (const classCode of Object.keys(geoNodes)) {
8339
+ const cfg = geoNodes[classCode] ?? {};
8340
+ const synthetic = {
8341
+ name: `${field.name}__node__${classCode}`,
8342
+ label: cfg.label ?? classCode,
8343
+ type: 'GEOGRAPHY_NODE',
8344
+ };
8345
+ nodes.push({ fieldConfig: synthetic, selected: cfg.hidden !== true, isLocked: false });
8346
+ }
8347
+ return nodes;
8348
+ }
8299
8349
  // ────────────────────────────────────────────────────────────────────────────
8300
8350
  // PRIVATE — Apply selection back to FormSchema children
8301
8351
  // ────────────────────────────────────────────────────────────────────────────
@@ -8335,6 +8385,9 @@ class FormSchemaTreeService {
8335
8385
  rowChild.visible = matchedField.selected; // Backward compatibility
8336
8386
  fieldIdx++;
8337
8387
  }
8388
+ if (rowChild.type === 'GEOGRAPHY_DYNAMIC') {
8389
+ this._applyGeographyNodeSelections(sections, rowChild);
8390
+ }
8338
8391
  }
8339
8392
  }
8340
8393
  else {
@@ -8344,9 +8397,39 @@ class FormSchemaTreeService {
8344
8397
  child.visible = matchedField.selected; // Backward compatibility
8345
8398
  fieldIdx++;
8346
8399
  }
8400
+ if (child.type === 'GEOGRAPHY_DYNAMIC') {
8401
+ this._applyGeographyNodeSelections(sections, child);
8402
+ }
8347
8403
  }
8348
8404
  }
8349
8405
  }
8406
+ /**
8407
+ * Writes each per-level checkbox state (from the synthetic `${field.name}__node__${classCode}`
8408
+ * entries built by _buildGeographyFieldNodes) back onto the real GEOGRAPHY_DYNAMIC field's
8409
+ * nested `geographyConfig.field.nodes[classCode].hidden`. The whole-block toggle itself is
8410
+ * already handled by the normal name-matched assignment at the call site above — this only
8411
+ * covers the additional per-level entries, which have no corresponding real schema child.
8412
+ */
8413
+ _applyGeographyNodeSelections(sections, field) {
8414
+ const geoNodes = field.geographyConfig?.field?.nodes;
8415
+ if (!geoNodes)
8416
+ return;
8417
+ for (const classCode of Object.keys(geoNodes)) {
8418
+ const nodeField = this._findSelectionFieldByName(sections, `${field.name}__node__${classCode}`);
8419
+ if (nodeField) {
8420
+ geoNodes[classCode] = { ...geoNodes[classCode], hidden: !nodeField.selected };
8421
+ }
8422
+ }
8423
+ }
8424
+ _findSelectionFieldByName(sections, name) {
8425
+ for (const section of sections) {
8426
+ for (const f of section.fields) {
8427
+ if (f.fieldConfig.name === name)
8428
+ return f;
8429
+ }
8430
+ }
8431
+ return null;
8432
+ }
8350
8433
  _applyFieldsToChildren(selectionFields, children) {
8351
8434
  let fi = 0;
8352
8435
  for (const child of children) {
@@ -8354,22 +8437,40 @@ class FormSchemaTreeService {
8354
8437
  continue;
8355
8438
  if (child.type === 'ROW' && child.children?.length) {
8356
8439
  for (const rowChild of child.children) {
8357
- if (fi < selectionFields.length) {
8358
- rowChild.isEnabled = selectionFields[fi].selected;
8359
- rowChild.visible = selectionFields[fi].selected; // Backward compatibility
8360
- fi++;
8361
- }
8440
+ fi = this._applyOneFieldSelection(selectionFields, rowChild, fi);
8362
8441
  }
8363
8442
  }
8364
8443
  else {
8365
- if (fi < selectionFields.length) {
8366
- child.isEnabled = selectionFields[fi].selected;
8367
- child.visible = selectionFields[fi].selected; // Backward compatibility
8368
- fi++;
8369
- }
8444
+ fi = this._applyOneFieldSelection(selectionFields, child, fi);
8370
8445
  }
8371
8446
  }
8372
8447
  }
8448
+ /**
8449
+ * Applies the selection state for exactly one schema child at flat position `fi` in
8450
+ * `selectionFields`, and returns the next unconsumed index. Normally that's 1 slot — but
8451
+ * _buildGeographyFieldNodes emits (1 whole-block + 1 per hierarchy level) entries for a single
8452
+ * GEOGRAPHY_DYNAMIC schema child, so this must consume that many slots here too, or every
8453
+ * subsequent sibling field's selection state would read from the wrong (shifted) index.
8454
+ */
8455
+ _applyOneFieldSelection(selectionFields, child, fi) {
8456
+ if (fi < selectionFields.length) {
8457
+ child.isEnabled = selectionFields[fi].selected;
8458
+ child.visible = selectionFields[fi].selected; // Backward compatibility
8459
+ }
8460
+ let consumed = 1;
8461
+ if (child.type === 'GEOGRAPHY_DYNAMIC') {
8462
+ const geoNodes = child.geographyConfig?.field?.nodes ?? {};
8463
+ const classCodes = Object.keys(geoNodes);
8464
+ classCodes.forEach((classCode, i) => {
8465
+ const nodeField = selectionFields[fi + 1 + i];
8466
+ if (nodeField) {
8467
+ geoNodes[classCode] = { ...geoNodes[classCode], hidden: !nodeField.selected };
8468
+ }
8469
+ });
8470
+ consumed += classCodes.length;
8471
+ }
8472
+ return fi + consumed;
8473
+ }
8373
8474
  _findSelectionField(sections, _field, _index) {
8374
8475
  // Flatten all fields from all sections
8375
8476
  for (const section of sections) {
@@ -8397,12 +8498,12 @@ class FormSchemaTreeService {
8397
8498
  else if (child.type === 'ROW' && child.children?.length) {
8398
8499
  child.children.forEach((rowChild, ri) => {
8399
8500
  if (rowChild.isEnabled !== false && rowChild.visible !== false) {
8400
- children.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
8501
+ children.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
8401
8502
  }
8402
8503
  });
8403
8504
  }
8404
8505
  else {
8405
- children.push(this._buildConfiguratorFieldNode(child, childPath));
8506
+ children.push(this._buildConfiguratorLeafNode(child, childPath));
8406
8507
  }
8407
8508
  });
8408
8509
  return {
@@ -8428,12 +8529,12 @@ class FormSchemaTreeService {
8428
8529
  else if (child.type === 'ROW' && child.children?.length) {
8429
8530
  child.children.forEach((rowChild, ri) => {
8430
8531
  if (rowChild.isEnabled !== false && rowChild.visible !== false) {
8431
- children.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
8532
+ children.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
8432
8533
  }
8433
8534
  });
8434
8535
  }
8435
8536
  else {
8436
- children.push(this._buildConfiguratorFieldNode(child, childPath));
8537
+ children.push(this._buildConfiguratorLeafNode(child, childPath));
8437
8538
  }
8438
8539
  });
8439
8540
  return {
@@ -8457,6 +8558,61 @@ class FormSchemaTreeService {
8457
8558
  children: [],
8458
8559
  };
8459
8560
  }
8561
+ /** Dispatches to the GEOGRAPHY_DYNAMIC-aware builder when needed; otherwise a normal leaf node. */
8562
+ _buildConfiguratorLeafNode(field, path) {
8563
+ if (field.type === 'GEOGRAPHY_DYNAMIC') {
8564
+ return this._buildGeographyConfiguratorNode(field, path);
8565
+ }
8566
+ return this._buildConfiguratorFieldNode(field, path);
8567
+ }
8568
+ /**
8569
+ * Builds the Configurator tree entry for a GEOGRAPHY_DYNAMIC field ("Address"): the field
8570
+ * itself stays selectable/editable as normal (its own label/colSpan/etc.), but it ALSO gets
8571
+ * one synthetic child per hierarchy level declared in geographyConfig.field.nodes (skipping
8572
+ * any the admin already hid via Field Selection), so each level's own label can be
8573
+ * individually edited. These children share the parent's `path` (there's no real schema
8574
+ * array index for a nested map entry) — `geoClassCode` is what actually identifies which
8575
+ * one a selection/patch targets. See FieldConfiguratorService for the read/write side.
8576
+ */
8577
+ _buildGeographyConfiguratorNode(field, path) {
8578
+ const geoNodes = field.geographyConfig?.field?.nodes ?? {};
8579
+ const children = Object.keys(geoNodes)
8580
+ .filter((code) => geoNodes[code]?.hidden !== true)
8581
+ .map((code) => ({
8582
+ id: `${path.join('-')}__geo__${code}`,
8583
+ label: geoNodes[code]?.label || code,
8584
+ type: 'field',
8585
+ expanded: false,
8586
+ fieldConfig: null,
8587
+ path,
8588
+ children: [],
8589
+ geoClassCode: code,
8590
+ }));
8591
+ return {
8592
+ id: field.name || `field-${path.join('-')}`,
8593
+ label: field.label || field.name || 'Field',
8594
+ type: 'field',
8595
+ expanded: false,
8596
+ fieldConfig: field,
8597
+ path,
8598
+ children,
8599
+ };
8600
+ }
8601
+ /**
8602
+ * Applies a config patch (label/colSpan only — see field-type-schema.map.ts's
8603
+ * `geographyNode` entry) to one hierarchy level's entry inside a GEOGRAPHY_DYNAMIC field's
8604
+ * nested `geographyConfig.field.nodes[classCode]`, since that's not a real schema array
8605
+ * child that applyFieldPatchToSchema's index-path lookup can reach.
8606
+ */
8607
+ applyGeographyNodePatchToSchema(path, classCode, patch, originalSchema) {
8608
+ const schema = JSON.parse(JSON.stringify(originalSchema));
8609
+ const field = this.findFieldByPath(schema, path);
8610
+ const nodes = field?.geographyConfig?.field?.nodes;
8611
+ if (nodes && nodes[classCode]) {
8612
+ nodes[classCode] = { ...nodes[classCode], ...patch };
8613
+ }
8614
+ return schema;
8615
+ }
8460
8616
  _buildConfiguratorChildNodes(children, basePath) {
8461
8617
  const nodes = [];
8462
8618
  children.forEach((child, ci) => {
@@ -8469,12 +8625,12 @@ class FormSchemaTreeService {
8469
8625
  else if (child.type === 'ROW' && child.children?.length) {
8470
8626
  child.children.forEach((rowChild, ri) => {
8471
8627
  if (rowChild.isEnabled !== false && rowChild.visible !== false) {
8472
- nodes.push(this._buildConfiguratorFieldNode(rowChild, [...childPath, ri]));
8628
+ nodes.push(this._buildConfiguratorLeafNode(rowChild, [...childPath, ri]));
8473
8629
  }
8474
8630
  });
8475
8631
  }
8476
8632
  else {
8477
- nodes.push(this._buildConfiguratorFieldNode(child, childPath));
8633
+ nodes.push(this._buildConfiguratorLeafNode(child, childPath));
8478
8634
  }
8479
8635
  });
8480
8636
  return nodes;
@@ -9006,6 +9162,7 @@ class FieldConfiguratorService {
9006
9162
  _state = signal({
9007
9163
  tree: [],
9008
9164
  selectedFieldPath: null,
9165
+ selectedGeoClassCode: null,
9009
9166
  schema: null,
9010
9167
  }, ...(ngDevMode ? [{ debugName: "_state" }] : []));
9011
9168
  treeService = new FormSchemaTreeService();
@@ -9013,11 +9170,33 @@ class FieldConfiguratorService {
9013
9170
  tree = computed(() => this._state().tree, ...(ngDevMode ? [{ debugName: "tree" }] : []));
9014
9171
  schema = computed(() => this._state().schema, ...(ngDevMode ? [{ debugName: "schema" }] : []));
9015
9172
  selectedFieldPath = computed(() => this._state().selectedFieldPath, ...(ngDevMode ? [{ debugName: "selectedFieldPath" }] : []));
9173
+ selectedGeoClassCode = computed(() => this._state().selectedGeoClassCode, ...(ngDevMode ? [{ debugName: "selectedGeoClassCode" }] : []));
9174
+ /**
9175
+ * Resolves to the real FieldConfig at the selected path — UNLESS the selection is a
9176
+ * synthetic geography-hierarchy-level node (selectedGeoClassCode set), in which case this
9177
+ * returns a small synthetic FieldConfig built from that level's entry in the parent
9178
+ * GEOGRAPHY_DYNAMIC field's `geographyConfig.field.nodes` map instead. Every downstream
9179
+ * consumer (selectedFieldInfo, selectedFieldBuilderType, the config panel itself) works
9180
+ * against whichever shape comes out of here unchanged — mapFieldTypeToBuilderType('GEOGRAPHY_NODE')
9181
+ * resolves the right minimal config schema (label/colSpan only, see field-type-schema.map.ts).
9182
+ */
9016
9183
  selectedField = computed(() => {
9017
- const { schema, selectedFieldPath } = this._state();
9184
+ const { schema, selectedFieldPath, selectedGeoClassCode } = this._state();
9018
9185
  if (!schema || !selectedFieldPath)
9019
9186
  return null;
9020
- return this.treeService.findFieldByPath(schema, selectedFieldPath);
9187
+ const realField = this.treeService.findFieldByPath(schema, selectedFieldPath);
9188
+ if (!realField)
9189
+ return null;
9190
+ if (selectedGeoClassCode) {
9191
+ const nodeCfg = realField.geographyConfig?.field?.nodes?.[selectedGeoClassCode] ?? {};
9192
+ return {
9193
+ name: selectedGeoClassCode,
9194
+ label: nodeCfg.label,
9195
+ colSpan: nodeCfg.colSpan,
9196
+ type: 'GEOGRAPHY_NODE',
9197
+ };
9198
+ }
9199
+ return realField;
9021
9200
  }, ...(ngDevMode ? [{ debugName: "selectedField" }] : []));
9022
9201
  selectedFieldInfo = computed(() => {
9023
9202
  const field = this.selectedField();
@@ -9056,24 +9235,35 @@ class FieldConfiguratorService {
9056
9235
  // If preserveSelection is truthy, we definitely keep it.
9057
9236
  // Otherwise, we still try to keep it IF the path is still valid in the new schema.
9058
9237
  let newPath = s.selectedFieldPath;
9238
+ let newGeoClassCode = s.selectedGeoClassCode;
9059
9239
  if (!preserveSelection && newPath) {
9060
- const stillExists = !!this.treeService.findFieldByPath(schema, newPath);
9061
- if (!stillExists)
9240
+ const field = this.treeService.findFieldByPath(schema, newPath);
9241
+ if (!field) {
9062
9242
  newPath = null;
9243
+ newGeoClassCode = null;
9244
+ }
9245
+ else if (newGeoClassCode && !field.geographyConfig?.field?.nodes?.[newGeoClassCode]) {
9246
+ // The selected hierarchy level no longer exists on this field (e.g. the address
9247
+ // template changed) — fall back to the parent field itself rather than dangling.
9248
+ newGeoClassCode = null;
9249
+ }
9063
9250
  }
9064
9251
  return {
9065
9252
  ...s,
9066
9253
  tree,
9067
9254
  selectedFieldPath: newPath,
9255
+ selectedGeoClassCode: newGeoClassCode,
9068
9256
  schema: JSON.parse(JSON.stringify(schema)),
9069
9257
  };
9070
9258
  });
9071
9259
  }
9072
9260
  /**
9073
- * Select a field by its path. Pass null to deselect.
9261
+ * Select a field by its path. Pass null to deselect. `geoClassCode` selects a synthetic
9262
+ * geography-hierarchy-level child of the GEOGRAPHY_DYNAMIC field at `path` instead of the
9263
+ * field itself — see ConfiguratorTreeNode.geoClassCode / selectedField above.
9074
9264
  */
9075
- selectField(path) {
9076
- this._state.update(s => ({ ...s, selectedFieldPath: path }));
9265
+ selectField(path, geoClassCode = null) {
9266
+ this._state.update(s => ({ ...s, selectedFieldPath: path, selectedGeoClassCode: geoClassCode }));
9077
9267
  }
9078
9268
  /**
9079
9269
  * Toggle a tree node's expanded state.
@@ -9089,10 +9279,12 @@ class FieldConfiguratorService {
9089
9279
  * Rebuilds the schema and tree nodes immutably.
9090
9280
  */
9091
9281
  patchSelectedField(patch) {
9092
- const { schema, selectedFieldPath, tree } = this._state();
9282
+ const { schema, selectedFieldPath, selectedGeoClassCode, tree } = this._state();
9093
9283
  if (!schema || !selectedFieldPath)
9094
9284
  return;
9095
- const newSchema = this.treeService.applyFieldPatchToSchema(selectedFieldPath, patch, schema);
9285
+ const newSchema = selectedGeoClassCode
9286
+ ? this.treeService.applyGeographyNodePatchToSchema(selectedFieldPath, selectedGeoClassCode, patch, schema)
9287
+ : this.treeService.applyFieldPatchToSchema(selectedFieldPath, patch, schema);
9096
9288
  // Rebuild the tree to reflect label changes etc.
9097
9289
  const newTree = this.treeService.parseSchemaToConfiguratorTree(newSchema);
9098
9290
  // Preserve expanded states from the old tree
@@ -9100,15 +9292,19 @@ class FieldConfiguratorService {
9100
9292
  this._state.set({
9101
9293
  schema: newSchema,
9102
9294
  selectedFieldPath,
9295
+ selectedGeoClassCode,
9103
9296
  tree: newTree,
9104
9297
  });
9105
9298
  }
9106
9299
  /**
9107
9300
  * Change the type (and optionally subType) of the currently selected field.
9108
9301
  * Mapping goes from builderType keys (e.g. 'richText') → {type, subType?}.
9109
- * DROPDOWN fields cannot be changed and are guarded here as well.
9302
+ * DROPDOWN fields cannot be changed and are guarded here as well — same for a synthetic
9303
+ * geography-hierarchy-level selection, which has no real `type` to switch at all.
9110
9304
  */
9111
9305
  changeFieldType(builderType) {
9306
+ if (this._state().selectedGeoClassCode)
9307
+ return;
9112
9308
  const currentField = this.selectedField();
9113
9309
  if (!currentField)
9114
9310
  return;
@@ -9516,6 +9712,17 @@ const DEFAULT_FIELD_TYPE_SCHEMA_MAP = {
9516
9712
  hint: 'Use data.field_name to reference other fields'
9517
9713
  },
9518
9714
  ]), FLAGS_SECTION, ADVANCED_SECTION),
9715
+ // ── GEOGRAPHY (GEOGRAPHY_DYNAMIC → geographyConfig, whole-block settings) ──
9716
+ geography: buildSchema(BASE_SECTION, FLAGS_SECTION, ADVANCED_SECTION),
9717
+ // ── GEOGRAPHY NODE (one hierarchy level of a GEOGRAPHY_DYNAMIC field, e.g. Country/State/
9718
+ // District — a synthetic child, not a real schema field; see
9719
+ // FormSchemaTreeService.applyGeographyNodePatchToSchema). Only label/colSpan are
9720
+ // meaningful per level: mandatoriness is always forced off for every field but Center
9721
+ // Name (see lc-master-form.ts's lockRequiredFields), and name/payloadPath/API config are
9722
+ // all derived from the resolved template, not editable per-level. ─────────────────────
9723
+ geographyNode: buildSchema(section('Basic Settings', [
9724
+ row(F.label, F.colSpan),
9725
+ ])),
9519
9726
  // ── GROUP & SECTION ───────────────────────────────────────────────────────
9520
9727
  group: buildSchema(section('Group Settings', [
9521
9728
  row(F.label, F.name),
@@ -9531,18 +9738,21 @@ const DEFAULT_FIELD_TYPE_SCHEMA_MAP = {
9531
9738
  class ConfiguratorTreeComponent {
9532
9739
  tree = [];
9533
9740
  selectedFieldPath = null;
9741
+ /** Distinguishes a GEOGRAPHY_DYNAMIC field itself from one of its synthetic hierarchy-level
9742
+ * children — both share the same `path`, so `path` alone can't tell them apart. */
9743
+ selectedGeoClassCode = null;
9534
9744
  selectField = new EventEmitter();
9535
9745
  toggleExpanded = new EventEmitter();
9536
9746
  onNodeClick(node) {
9537
9747
  if (node.type === 'field') {
9538
- this.selectField.emit(node.path);
9748
+ this.selectField.emit({ path: node.path, geoClassCode: node.geoClassCode });
9539
9749
  }
9540
9750
  else {
9541
9751
  this.toggleExpanded.emit(node.id);
9542
9752
  }
9543
9753
  }
9544
9754
  onFieldSelect(node) {
9545
- this.selectField.emit(node.path);
9755
+ this.selectField.emit({ path: node.path, geoClassCode: node.geoClassCode });
9546
9756
  }
9547
9757
  onToggleExpand(node, event) {
9548
9758
  event.stopPropagation();
@@ -9551,7 +9761,9 @@ class ConfiguratorTreeComponent {
9551
9761
  isSelected(node) {
9552
9762
  if (!this.selectedFieldPath || !node.path)
9553
9763
  return false;
9554
- return this.pathsEqual(node.path, this.selectedFieldPath);
9764
+ if (!this.pathsEqual(node.path, this.selectedFieldPath))
9765
+ return false;
9766
+ return (node.geoClassCode ?? null) === (this.selectedGeoClassCode ?? null);
9555
9767
  }
9556
9768
  trackByNodeId(_index, node) {
9557
9769
  return node.id;
@@ -9562,15 +9774,17 @@ class ConfiguratorTreeComponent {
9562
9774
  return a.every((v, i) => v === b[i]);
9563
9775
  }
9564
9776
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfiguratorTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9565
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfiguratorTreeComponent, isStandalone: false, selector: "lib-configurator-tree", inputs: { tree: "tree", selectedFieldPath: "selectedFieldPath" }, outputs: { selectField: "selectField", toggleExpanded: "toggleExpanded" }, ngImport: i0, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9777
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConfiguratorTreeComponent, isStandalone: false, selector: "lib-configurator-tree", inputs: { tree: "tree", selectedFieldPath: "selectedFieldPath", selectedGeoClassCode: "selectedGeoClassCode" }, outputs: { selectField: "selectField", toggleExpanded: "toggleExpanded" }, ngImport: i0, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) \u2014 may itself have synthetic children (see\r\n geoClassCode), in which case it also gets an expand chevron. -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n @if (node.children.length > 0) {\r\n <span\r\n class=\"fb-cfg-tree-item__chevron\"\r\n [class.fb-cfg-tree-item__chevron--expanded]=\"node.expanded\"\r\n (click)=\"onToggleExpand(node, $event)\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n @if (node.children.length > 0 && node.expanded) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1);margin-right:4px;cursor:pointer}.fb-cfg-tree-item__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9566
9778
  }
9567
9779
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConfiguratorTreeComponent, decorators: [{
9568
9780
  type: Component,
9569
- args: [{ selector: 'lib-configurator-tree', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"] }]
9781
+ args: [{ selector: 'lib-configurator-tree', standalone: false, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-cfg-tree\">\r\n <div class=\"fb-cfg-tree__header\">\r\n <h4 class=\"fb-cfg-tree__title\">Field Tree</h4>\r\n <p class=\"fb-cfg-tree__subtitle\">Select a field to configure</p>\r\n </div>\r\n\r\n <div class=\"fb-cfg-tree__scrollable\">\r\n @for (node of tree; track trackByNodeId($index, node)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: node, depth: 0 }\"></ng-container>\r\n }\r\n\r\n @if (tree.length === 0) {\r\n <div class=\"fb-cfg-tree__empty\">\r\n No fields to configure.\r\n </div>\r\n }\r\n </div>\r\n</div>\r\n\r\n<!-- Recursive tree node template -->\r\n<ng-template #treeNodeTpl let-node let-depth=\"depth\">\r\n @if (node.type === 'field') {\r\n <!-- Field node (clickable leaf) \u2014 may itself have synthetic children (see\r\n geoClassCode), in which case it also gets an expand chevron. -->\r\n <div\r\n class=\"fb-cfg-tree-item\"\r\n [class.fb-cfg-tree-item--active]=\"isSelected(node)\"\r\n (click)=\"onFieldSelect(node)\"\r\n [style.padding-left.px]=\"16 + depth * 16\"\r\n >\r\n @if (node.children.length > 0) {\r\n <span\r\n class=\"fb-cfg-tree-item__chevron\"\r\n [class.fb-cfg-tree-item__chevron--expanded]=\"node.expanded\"\r\n (click)=\"onToggleExpand(node, $event)\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n }\r\n <span class=\"fb-cfg-tree-item__drag\" title=\"Drag to reorder\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </span>\r\n <div class=\"fb-cfg-tree-item__content\">\r\n <span class=\"fb-cfg-tree-item__label\">{{ node.label }}</span>\r\n @if (node.fieldConfig?.type) {\r\n <span class=\"fb-cfg-tree-item__type\">{{ node.fieldConfig.type }}</span>\r\n }\r\n </div>\r\n </div>\r\n @if (node.children.length > 0 && node.expanded) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <!-- Group or Section node (expandable) -->\r\n <div\r\n class=\"fb-cfg-tree-section\"\r\n [style.padding-left.px]=\"8 + depth * 12\"\r\n >\r\n <div class=\"fb-cfg-tree-section__header\" (click)=\"onNodeClick(node)\">\r\n <div class=\"fb-cfg-tree-section__title-group\">\r\n <span\r\n class=\"fb-cfg-tree-section__chevron\"\r\n [class.fb-cfg-tree-section__chevron--expanded]=\"node.expanded\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\r\n <polyline points=\"9 18 15 12 9 6\"></polyline>\r\n </svg>\r\n </span>\r\n <span class=\"fb-cfg-tree-section__label\">{{ node.label }}</span>\r\n </div>\r\n </div>\r\n\r\n @if (node.expanded && node.children.length > 0) {\r\n <div class=\"fb-cfg-tree-section__children\">\r\n @for (child of node.children; track trackByNodeId($index, child)) {\r\n <ng-container *ngTemplateOutlet=\"treeNodeTpl; context: { $implicit: child, depth: depth + 1 }\"></ng-container>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree{display:flex;flex-direction:column;height:100%;overflow:hidden}.fb-cfg-tree__header{padding:16px 20px;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-tree-header-bg, #ffffff);flex-shrink:0}@media(max-width:768px){.fb-cfg-tree__header{padding:12px 16px}}@media(max-width:640px){.fb-cfg-tree__header{padding:10px 12px}}.fb-cfg-tree__title{margin:0;font-size:14px;font-weight:700;color:var(--fb-fc-tree-title-color, #111827)}@media(max-width:640px){.fb-cfg-tree__title{font-size:13px}}.fb-cfg-tree__subtitle{margin:4px 0 0;font-size:11px;color:var(--fb-fc-tree-subtitle-color, #6b7280);letter-spacing:.02em}@media(max-width:640px){.fb-cfg-tree__subtitle{font-size:10px}}.fb-cfg-tree__scrollable{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding:16px}@media(max-width:768px){.fb-cfg-tree__scrollable{padding:12px}}@media(max-width:640px){.fb-cfg-tree__scrollable{padding:8px}}.fb-cfg-tree__empty{padding:32px 16px;text-align:center;color:var(--fb-fc-empty-color, #9ca3af);font-size:13px}@media(max-width:640px){.fb-cfg-tree__empty{padding:24px 12px;font-size:12px}}.fb-cfg-tree-section{margin-bottom:16px}@media(max-width:768px){.fb-cfg-tree-section{margin-bottom:12px}}@media(max-width:640px){.fb-cfg-tree-section{margin-bottom:8px}}.fb-cfg-tree-section__header{display:flex;align-items:center;justify-content:space-between;padding:4px 8px 8px;border-bottom:1px solid var(--fb-fc-section-divider, #f3f4f6);margin-bottom:8px;cursor:pointer}@media(max-width:640px){.fb-cfg-tree-section__header{padding:3px 6px 6px;margin-bottom:6px}}.fb-cfg-tree-section__header:hover{background:var(--fb-fc-section-hover, #f9fafb);border-radius:6px}.fb-cfg-tree-section__title-group{display:flex;align-items:center;gap:6px}@media(max-width:640px){.fb-cfg-tree-section__title-group{gap:4px}}.fb-cfg-tree-section__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-section__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-section__label{font-size:13px;font-weight:700;color:var(--fb-fc-section-label-color, #111827);text-transform:uppercase;letter-spacing:.05em}@media(max-width:640px){.fb-cfg-tree-section__label{font-size:12px;letter-spacing:.02em}}.fb-cfg-tree-section__children{display:flex;flex-direction:column;gap:8px}@media(max-width:640px){.fb-cfg-tree-section__children{gap:6px}}.fb-cfg-tree-item{display:flex;align-items:center;padding:12px;background:var(--fb-fc-item-bg, #ffffff);border:1px solid var(--fb-fc-item-border, #e5e7eb);border-radius:10px;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1)}.fb-cfg-tree-item:hover{border-color:var(--fb-fc-item-hover-border, #3b82f6);box-shadow:0 2px 8px #3b82f614}.fb-cfg-tree-item--active{border-color:var(--fb-fc-item-active-border, #3b82f6);background:var(--fb-fc-item-active-bg, #f0f7ff);box-shadow:0 0 0 1px var(--fb-fc-item-active-border, #3b82f6)}.fb-cfg-tree-item__drag{color:var(--fb-fc-drag-color, #d1d5db);cursor:grab;margin-right:8px;display:flex}.fb-cfg-tree-item__chevron{display:flex;color:var(--fb-fc-chevron-color, #9ca3af);transition:transform .2s cubic-bezier(.4,0,.2,1);margin-right:4px;cursor:pointer}.fb-cfg-tree-item__chevron--expanded{transform:rotate(90deg)}.fb-cfg-tree-item__content{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.fb-cfg-tree-item__label{font-size:13px;font-weight:600;color:var(--fb-fc-item-label-color, #111827);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fb-cfg-tree-item__type{font-size:10px;color:var(--fb-fc-item-type-color, #6b7280);text-transform:uppercase;letter-spacing:.05em;font-weight:500}\n"] }]
9570
9782
  }], propDecorators: { tree: [{
9571
9783
  type: Input
9572
9784
  }], selectedFieldPath: [{
9573
9785
  type: Input
9786
+ }], selectedGeoClassCode: [{
9787
+ type: Input
9574
9788
  }], selectField: [{
9575
9789
  type: Output
9576
9790
  }], toggleExpanded: [{
@@ -9615,10 +9829,11 @@ class ConfiguratorConfigPanelComponent {
9615
9829
  currentBuilderType = null;
9616
9830
  /** Identity key of the currently rendered field — used to detect real field switches. */
9617
9831
  _currentFieldKey = '';
9618
- /** True when the current field type is DROPDOWN — type switching is disabled for these fields. */
9832
+ /** True when type switching should be disabled — DROPDOWN-based fields, and synthetic
9833
+ * geography-hierarchy-level nodes (GEOGRAPHY_NODE), which have no real `type` to switch. */
9619
9834
  get isDropdownType() {
9620
9835
  const t = this.selectedField?.type?.toUpperCase();
9621
- return t === 'DROPDOWN' || t === 'MULTI_SELECT';
9836
+ return t === 'DROPDOWN' || t === 'MULTI_SELECT' || t === 'GEOGRAPHY_NODE';
9622
9837
  }
9623
9838
  ngOnChanges(changes) {
9624
9839
  if ((changes['selectedField'] || changes['builderFieldType'] || changes['fieldTypeSchemaMap'])
@@ -10018,8 +10233,8 @@ class FieldConfiguratorComponent {
10018
10233
  this._isInternalChange = false;
10019
10234
  }
10020
10235
  }
10021
- onFieldSelected(path) {
10022
- this.store.selectField(path);
10236
+ onFieldSelected(selection) {
10237
+ this.store.selectField(selection.path, selection.geoClassCode ?? null);
10023
10238
  this.cdr.markForCheck();
10024
10239
  }
10025
10240
  onNodeToggleExpanded(nodeId) {
@@ -10043,11 +10258,11 @@ class FieldConfiguratorComponent {
10043
10258
  }
10044
10259
  }
10045
10260
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FieldConfiguratorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
10046
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FieldConfiguratorComponent, isStandalone: false, selector: "lib-field-configurator", inputs: { schema: "schema", showOptionConfig: "showOptionConfig", lockedFieldNames: "lockedFieldNames" }, outputs: { schemaChange: "schemaChange" }, providers: [FieldConfiguratorService], usesOnChanges: true, ngImport: i0, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"], dependencies: [{ kind: "component", type: ConfiguratorTreeComponent, selector: "lib-configurator-tree", inputs: ["tree", "selectedFieldPath"], outputs: ["selectField", "toggleExpanded"] }, { kind: "component", type: ConfiguratorConfigPanelComponent, selector: "lib-configurator-config-panel", inputs: ["selectedField", "selectedFieldInfo", "builderFieldType", "fieldTypeSchemaMap", "showOptionConfig", "lockedFieldNames"], outputs: ["configChange", "typeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10261
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FieldConfiguratorComponent, isStandalone: false, selector: "lib-field-configurator", inputs: { schema: "schema", showOptionConfig: "showOptionConfig", lockedFieldNames: "lockedFieldNames" }, outputs: { schemaChange: "schemaChange" }, providers: [FieldConfiguratorService], usesOnChanges: true, ngImport: i0, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n [selectedGeoClassCode]=\"store.selectedGeoClassCode()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"], dependencies: [{ kind: "component", type: ConfiguratorTreeComponent, selector: "lib-configurator-tree", inputs: ["tree", "selectedFieldPath", "selectedGeoClassCode"], outputs: ["selectField", "toggleExpanded"] }, { kind: "component", type: ConfiguratorConfigPanelComponent, selector: "lib-configurator-config-panel", inputs: ["selectedField", "selectedFieldInfo", "builderFieldType", "fieldTypeSchemaMap", "showOptionConfig", "lockedFieldNames"], outputs: ["configChange", "typeChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10047
10262
  }
10048
10263
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FieldConfiguratorComponent, decorators: [{
10049
10264
  type: Component,
10050
- args: [{ selector: 'lib-field-configurator', standalone: false, providers: [FieldConfiguratorService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"] }]
10265
+ args: [{ selector: 'lib-field-configurator', standalone: false, providers: [FieldConfiguratorService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-configurator\">\r\n <div class=\"fb-configurator__layout\">\r\n <div class=\"fb-configurator__sidebar\">\r\n <lib-configurator-tree\r\n [tree]=\"store.tree()\"\r\n [selectedFieldPath]=\"store.selectedFieldPath()\"\r\n [selectedGeoClassCode]=\"store.selectedGeoClassCode()\"\r\n (selectField)=\"onFieldSelected($event)\"\r\n (toggleExpanded)=\"onNodeToggleExpanded($event)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-configurator__main\">\r\n <lib-configurator-config-panel\r\n [selectedField]=\"store.selectedField()\"\r\n [selectedFieldInfo]=\"store.selectedFieldInfo()\"\r\n [builderFieldType]=\"store.selectedFieldBuilderType()\"\r\n [fieldTypeSchemaMap]=\"finalFieldTypeSchemaMap\"\r\n [showOptionConfig]=\"showOptionConfig\"\r\n [lockedFieldNames]=\"lockedFieldNames\"\r\n (configChange)=\"onConfigChange($event)\"\r\n (typeChange)=\"onTypeChange($event)\"\r\n />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".fb-configurator{display:flex;flex-direction:column;height:100%;width:100%;background:var(--fb-fc-bg, #ffffff);font-family:var(--fb-font-family, \"Inter\", sans-serif)}.fb-configurator__layout{flex:1;display:flex;overflow:hidden;width:100%}@media(max-width:768px){.fb-configurator__layout{flex-direction:column}}.fb-configurator__sidebar{flex:0 0 280px;border-right:1px solid var(--fb-fc-border, #e5e7eb);background:var(--fb-fc-sidebar-bg, #f9fafb);display:flex;flex-direction:column;overflow:hidden;min-width:0}@media(max-width:1024px){.fb-configurator__sidebar{flex:0 0 250px}}@media(min-width:1440px){.fb-configurator__sidebar{flex:0 0 300px}}@media(max-width:768px){.fb-configurator__sidebar{flex:0 0 auto;width:100%;border-right:none;border-bottom:1px solid var(--fb-fc-border, #e5e7eb);max-height:40vh}}@media(max-width:640px){.fb-configurator__sidebar{max-height:35vh}}.fb-configurator__main{flex:1;min-width:0;overflow-y:auto;overflow-x:hidden;background:var(--fb-fc-main-bg, #ffffff);display:flex;flex-direction:column}@media(max-width:768px){.fb-configurator__main{width:100%;flex:1;min-height:0}}\n"] }]
10051
10266
  }], propDecorators: { schema: [{
10052
10267
  type: Input,
10053
10268
  args: [{ required: true }]