ngx-dynamic-entity-builder 1.14.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-dynamic-entity-builder",
3
- "version": "1.14.0",
3
+ "version": "2.0.0",
4
4
  "description": "Angular standalone visual builder for authoring dynamic-entity EntityConfig (fields, tabs, validators, RBAC).",
5
5
  "//typings": "Local workspace resolution only: ng-packagr 21 writes types/ngx-dynamic-entity-builder.d.ts into dist/package.json. Do NOT add a 'main' field here — ng-packagr does not generate one, so it would be copied verbatim and resolve wrongly in the published package.",
6
6
  "typings": "types/ngx-dynamic-entity-builder.d.ts",
@@ -10,8 +10,8 @@
10
10
  "@angular/core": "^17.2.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
11
11
  "@angular/forms": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
12
12
  "@angular/material": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
13
- "@dynamic-entity/core": "^1.14.0",
14
- "ngx-dynamic-entity": "^1.14.0",
13
+ "@dynamic-entity/core": "^2.0.0",
14
+ "ngx-dynamic-entity": "^2.0.0",
15
15
  "rxjs": "^7.0.0"
16
16
  },
17
17
  "keywords": [
@@ -73,6 +73,8 @@ declare class BuilderStore {
73
73
  * removing or moving anything always earns its own step however fast it is clicked.
74
74
  */
75
75
  private record;
76
+ /** How many undo steps are kept. */
77
+ private static readonly MAX_HISTORY;
76
78
  /** Counts that distinguish a structural edit from a value edit. */
77
79
  private shapeOf;
78
80
  /** Start history again from the state just loaded. Nothing before it is undoable. */
@@ -113,7 +115,7 @@ declare class BuilderStore {
113
115
  readonly problems: _angular_core.Signal<BuilderProblem[]>;
114
116
  readonly errors: _angular_core.Signal<BuilderProblem[]>;
115
117
  readonly isValid: _angular_core.Signal<boolean>;
116
- load(config: EntityFormConfig): void;
118
+ load(config: EntityFormConfig, rules?: readonly FormRule[]): void;
117
119
  reset(entity?: string): void;
118
120
  resetDirty(): void;
119
121
  private emptyConfig;
@@ -274,6 +276,30 @@ declare class BuilderStore {
274
276
  /** Scan all referenced fields in the config and update their hasDrift state against current source configs. */
275
277
  checkDrift(sourceConfigs: Record<string, EntityFormConfig>): void;
276
278
  addOption(fieldId: string): void;
279
+ /**
280
+ * A key for a new option: the label slugified, made unique within its own field.
281
+ *
282
+ * Unique within the field and nowhere wider, because that is the scope the key has to
283
+ * distinguish within — two fields may both offer "Active" and they are the same value.
284
+ * A label that slugifies to nothing (punctuation, a script `labelToId` strips) falls back
285
+ * to a positional name rather than an empty key, which `optionKeyOf` would ignore.
286
+ */
287
+ private mintOptionKey;
288
+ /**
289
+ * Give every option in the config a key, leaving the ones that already have one alone.
290
+ *
291
+ * The counterpart to `optionKeyMigration` in core: that one keys stored *records* against
292
+ * a keyed config, this one keys the config. Run this first, then ship the migration — the
293
+ * other order leaves the migration with no keys to attach.
294
+ *
295
+ * Existing keys are never rewritten, so this is safe to run again on a config that is
296
+ * already half-keyed, which is what happens as options are added to an older schema.
297
+ */
298
+ assignOptionKeys(): void;
299
+ /** Whether any option in the config is still without a key — gates the action in the UI. */
300
+ readonly hasUnkeyedOptions: _angular_core.Signal<boolean>;
301
+ /** An option's stable key, for the inspector to show read-only. */
302
+ optionKey(option: DropdownOption): string;
277
303
  /** Merge language keys into an option. `setOptionLabel` is the usual single-language path. */
278
304
  updateOption(fieldId: string, index: number, patch: DropdownOption): void;
279
305
  /**
@@ -306,6 +332,11 @@ declare class BuilderStore {
306
332
  * had lost its rules.
307
333
  */
308
334
  readonly rulesForSelectedField: _angular_core.Signal<FormRule[]>;
335
+ /**
336
+ * Replace the rules without touching the config — for a host whose rules changed on their
337
+ * own. It records a step, because from the author's side it is an edit. Loading a config
338
+ * passes its rules to `load` instead, so the pair arrives as one snapshot.
339
+ */
309
340
  loadRules(rules: FormRule[]): void;
310
341
  addRule(rule: FormRule): string;
311
342
  updateRule(id: string, patch: Partial<FormRule>): void;
@@ -481,6 +512,9 @@ declare const DEFAULT_BUILDER_TEXT: {
481
512
  optionInLanguage: string;
482
513
  removeOption: string;
483
514
  noOptionsYet: string;
515
+ optionKey: string;
516
+ optionKeyHint: string;
517
+ assignOptionKeys: string;
484
518
  display: string;
485
519
  visible: string;
486
520
  tableColumn: string;
@@ -631,6 +665,15 @@ declare class EntityBuilderComponent implements OnChanges {
631
665
  private readonly hostRef;
632
666
  /** Existing config to edit. When omitted, the builder starts blank. */
633
667
  config?: EntityFormConfig;
668
+ /**
669
+ * The rules that belong with `config`.
670
+ *
671
+ * Rules live beside a config rather than inside it — that is the shape the renderer takes
672
+ * them in, and the shape a host stores them in. Without this input, loading a config for
673
+ * editing silently dropped every rule already authored against it: the builder opened on
674
+ * the right fields with an empty rules list, and saving put that emptiness back.
675
+ */
676
+ rules?: FormRule[];
634
677
  /** Languages available for label/placeholder editing. First entry is the default. */
635
678
  languages: string[];
636
679
  /**
@@ -653,6 +696,21 @@ declare class EntityBuilderComponent implements OnChanges {
653
696
  commonModules: readonly CommonModuleEntry[];
654
697
  /** Emitted on every change to the working config. */
655
698
  configChange: EventEmitter<EntityFormConfig>;
699
+ /**
700
+ * Emitted on every change to the working rules — the mirror of `configChange`.
701
+ *
702
+ * Without it a rule authored here could not leave this component. `BuilderStore` is
703
+ * provided by the component, so its instance is private to this injector, and `save`
704
+ * carries an `EntityFormConfig` alone. The builder could author a rule and hand it to
705
+ * nobody: a host had no supported way to persist one, and therefore no way to pass it
706
+ * back to the renderer as `[rules]`.
707
+ *
708
+ * A host that persists on Save keeps the latest emission and writes it alongside the
709
+ * config `save` carries — the same pairing `configChange`/`save` already implies, and the
710
+ * pairing the undo history has always stored, because undoing a field rename without the
711
+ * rule that follows it would leave the rule pointing at a field that no longer exists.
712
+ */
713
+ rulesChange: EventEmitter<FormRule[]>;
656
714
  /** Emitted when the user clicks Save. Carries a clean, deep-cloned config. */
657
715
  save: EventEmitter<EntityFormConfig>;
658
716
  protected readonly rbacActions: readonly RbacAction[];
@@ -699,7 +757,7 @@ declare class EntityBuilderComponent implements OnChanges {
699
757
  /** Parse a comma-separated role string into a trimmed, de-duplicated array. */
700
758
  protected setRolesFromText(action: RbacAction, text: string): void;
701
759
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityBuilderComponent, never>;
702
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityBuilderComponent, "ngx-entity-builder", never, { "config": { "alias": "config"; "required": false; }; "languages": { "alias": "languages"; "required": false; }; "uiLanguage": { "alias": "uiLanguage"; "required": false; }; "availableRoles": { "alias": "availableRoles"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; "commonModules": { "alias": "commonModules"; "required": false; }; "leftSidebarOpen": { "alias": "leftSidebarOpen"; "required": false; "isSignal": true; }; "rightSidebarOpen": { "alias": "rightSidebarOpen"; "required": false; "isSignal": true; }; "fieldsOpen": { "alias": "fieldsOpen"; "required": false; "isSignal": true; }; "previewOpen": { "alias": "previewOpen"; "required": false; "isSignal": true; }; }, { "configChange": "configChange"; "save": "save"; "leftSidebarOpen": "leftSidebarOpenChange"; "rightSidebarOpen": "rightSidebarOpenChange"; "fieldsOpen": "fieldsOpenChange"; "previewOpen": "previewOpenChange"; }, never, ["[ngxBuilderPreview]"], true, never>;
760
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityBuilderComponent, "ngx-entity-builder", never, { "config": { "alias": "config"; "required": false; }; "rules": { "alias": "rules"; "required": false; }; "languages": { "alias": "languages"; "required": false; }; "uiLanguage": { "alias": "uiLanguage"; "required": false; }; "availableRoles": { "alias": "availableRoles"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; "commonModules": { "alias": "commonModules"; "required": false; }; "leftSidebarOpen": { "alias": "leftSidebarOpen"; "required": false; "isSignal": true; }; "rightSidebarOpen": { "alias": "rightSidebarOpen"; "required": false; "isSignal": true; }; "fieldsOpen": { "alias": "fieldsOpen"; "required": false; "isSignal": true; }; "previewOpen": { "alias": "previewOpen"; "required": false; "isSignal": true; }; }, { "configChange": "configChange"; "rulesChange": "rulesChange"; "save": "save"; "leftSidebarOpen": "leftSidebarOpenChange"; "rightSidebarOpen": "rightSidebarOpenChange"; "fieldsOpen": "fieldsOpenChange"; "previewOpen": "previewOpenChange"; }, never, ["[ngxBuilderPreview]"], true, never>;
703
761
  }
704
762
 
705
763
  /**