ngx-dynamic-entity-builder 1.9.1 → 1.11.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.9.1",
3
+ "version": "1.11.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.0.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.9.1",
14
- "ngx-dynamic-entity": "^1.9.1",
13
+ "@dynamic-entity/core": "^1.11.0",
14
+ "ngx-dynamic-entity": "^1.11.0",
15
15
  "rxjs": "^7.0.0"
16
16
  },
17
17
  "keywords": [
@@ -233,6 +233,15 @@ declare class BuilderStore {
233
233
  /** `derived`, or `derived_2`, `derived_3`… if another field already holds it. */
234
234
  private availableId;
235
235
  setFieldPlaceholder(id: string, language: string, value: string): void;
236
+ /**
237
+ * Help text shown under the control, per language.
238
+ *
239
+ * Separate from the placeholder for the reason the schema keeps them separate: a
240
+ * placeholder vanishes the moment the user types, so anything they need *while* filling the
241
+ * field in cannot live there. An author with only a placeholder box to write in tends to
242
+ * put it there anyway.
243
+ */
244
+ setFieldHint(id: string, language: string, value: string): void;
236
245
  toggleFlagValidator(id: string, validator: FlagValidator, on: boolean): void;
237
246
  setParamValidator(id: string, validator: ParamValidator, value: number | null): void;
238
247
  getParamValidator(field: NestedFieldConfig, validator: ParamValidator): number | null;
@@ -380,8 +389,10 @@ declare const DEFAULT_BUILDER_TEXT: {
380
389
  redo: string;
381
390
  redoTooltip: string;
382
391
  issuesTooltip: string;
392
+ issuesCount: string;
383
393
  copyJson: string;
384
394
  save: string;
395
+ saveBlockedTooltip: string;
385
396
  entityName: string;
386
397
  entityNamePlaceholder: string;
387
398
  editingLanguage: string;
@@ -393,6 +404,16 @@ declare const DEFAULT_BUILDER_TEXT: {
393
404
  addField: string;
394
405
  fieldProperties: string;
395
406
  configJson: string;
407
+ paletteSearchPlaceholder: string;
408
+ paletteSearchLabel: string;
409
+ paletteSearchClear: string;
410
+ paletteNoMatch: string;
411
+ paletteGroupBasic: string;
412
+ paletteGroupChoice: string;
413
+ paletteGroupDateTime: string;
414
+ paletteGroupRich: string;
415
+ paletteGroupStructure: string;
416
+ paletteGroupOther: string;
396
417
  fieldsHeading: string;
397
418
  canvasEmpty: string;
398
419
  selectField: string;
@@ -415,8 +436,26 @@ declare const DEFAULT_BUILDER_TEXT: {
415
436
  tabMoveHint: string;
416
437
  labelInLanguage: string;
417
438
  placeholderInLanguage: string;
439
+ hintInLanguage: string;
440
+ hintHint: string;
418
441
  defaultValue: string;
419
- validation: string;
442
+ sectionBasics: string;
443
+ sectionLayout: string;
444
+ sectionValidation: string;
445
+ sectionOptions: string;
446
+ sectionDisplay: string;
447
+ sectionVisibility: string;
448
+ sectionAutomation: string;
449
+ sectionRules: string;
450
+ sectionReference: string;
451
+ width: string;
452
+ widthQuarter: string;
453
+ widthThird: string;
454
+ widthHalf: string;
455
+ widthTwoThirds: string;
456
+ widthFull: string;
457
+ widthHint: string;
458
+ widthOf: string;
420
459
  dataSource: string;
421
460
  optionsComeFrom: string;
422
461
  optionsSourceNone: string;
@@ -562,6 +601,7 @@ declare class BuilderTextService {
562
601
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<BuilderTextService>;
563
602
  }
564
603
 
604
+ type RbacAction = 'view' | 'edit' | 'delete';
565
605
  /**
566
606
  * EntityBuilderComponent — the top-level visual builder for an EntityFormConfig.
567
607
  */
@@ -600,7 +640,15 @@ declare class EntityBuilderComponent implements OnChanges {
600
640
  configChange: EventEmitter<EntityFormConfig>;
601
641
  /** Emitted when the user clicks Save. Carries a clean, deep-cloned config. */
602
642
  save: EventEmitter<EntityFormConfig>;
603
- protected readonly rbacActions: (keyof EntityPermissions)[];
643
+ protected readonly rbacActions: readonly RbacAction[];
644
+ /**
645
+ * Select the field an issue is about, so reading the message and acting on it are one step.
646
+ *
647
+ * A problem without a `fieldId` is about the entity itself — no tabs, a bad entity name —
648
+ * and there is nothing to select; the template disables those entries rather than silently
649
+ * doing nothing when one is clicked.
650
+ */
651
+ protected selectProblemField(problem: BuilderProblem): void;
604
652
  constructor();
605
653
  /**
606
654
  * Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z, but only when the user is not typing.
@@ -613,19 +661,53 @@ declare class EntityBuilderComponent implements OnChanges {
613
661
  protected doSave(): void;
614
662
  protected get json(): string;
615
663
  protected copyJson(): void;
616
- protected rolesFor(action: keyof EntityPermissions): readonly string[];
617
- protected setRoles(action: keyof EntityPermissions, roles: string[]): void;
664
+ protected rolesFor(action: RbacAction): readonly string[];
665
+ protected setRoles(action: RbacAction, roles: string[]): void;
618
666
  /** Parse a comma-separated role string into a trimmed, de-duplicated array. */
619
- protected setRolesFromText(action: keyof EntityPermissions, text: string): void;
667
+ protected setRolesFromText(action: RbacAction, text: string): void;
620
668
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityBuilderComponent, never>;
621
669
  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; }; }, { "configChange": "configChange"; "save": "save"; }, never, ["[ngxBuilderPreview]"], true, never>;
622
670
  }
623
671
 
624
672
  /**
625
- * FieldPaletteComponent — the list of buildable field types (Angular Material).
673
+ * Which drawer of the palette a field type belongs in.
674
+ *
675
+ * Kept here rather than on `FieldTypeMeta` in core: the catalogue is a data model shared with
676
+ * the renderer, and how a picker arranges twenty-two buttons is a decision about this panel.
677
+ * A type absent from the map — a consumer's custom type, or one added to core later — falls
678
+ * into `other`, so the palette degrades to "listed, just not filed" rather than dropping it.
679
+ */
680
+ declare const PALETTE_GROUPS: readonly ["basic", "choice", "datetime", "rich", "structure", "other"];
681
+ type PaletteGroup = (typeof PALETTE_GROUPS)[number];
682
+ interface PaletteSection {
683
+ group: PaletteGroup;
684
+ heading: string;
685
+ items: FieldTypeMeta[];
686
+ }
687
+ /**
688
+ * FieldPaletteComponent — the list of buildable field types.
689
+ *
690
+ * Two things changed the day this stopped being a flat grid of twenty-two buttons. The labels
691
+ * were clipped mid-word — "Boolean Toggl", "Entity Referen", "File Attachmen" — because the
692
+ * grid forced two equal columns and the button refused to wrap, so a third of the palette
693
+ * could not be read. And with no order to them, finding "Month & Year" meant scanning the
694
+ * whole list: the grouping and the filter are what make a palette this size navigable.
626
695
  */
627
696
  declare class FieldPaletteComponent {
697
+ /** Builder chrome, overridable via BUILDER_TEXT. */
698
+ protected readonly ui: BuilderTextService;
628
699
  readonly catalog: readonly FieldTypeMeta[];
700
+ /** The filter text. Matched against the label, the type and the description. */
701
+ protected readonly query: _angular_core.WritableSignal<string>;
702
+ /**
703
+ * The catalogue, filtered and filed.
704
+ *
705
+ * Matching the description as well as the label is what makes the filter worth having: a
706
+ * person looking for a currency input types "money", which appears in no label but is
707
+ * exactly the sort of word a description carries. An empty group is dropped rather than
708
+ * rendered as a heading with nothing under it.
709
+ */
710
+ protected readonly sections: _angular_core.Signal<PaletteSection[]>;
629
711
  pick: EventEmitter<RichFieldType>;
630
712
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldPaletteComponent, never>;
631
713
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldPaletteComponent, "ngx-field-palette", never, {}, { "pick": "pick"; }, never, never, true, never>;
@@ -669,10 +751,51 @@ declare class FieldInspectorComponent {
669
751
  protected readonly store: BuilderStore;
670
752
  protected readonly field: _angular_core.Signal<NestedFieldConfig>;
671
753
  protected readonly meta: _angular_core.Signal<FieldTypeMeta>;
754
+ /**
755
+ * The offered widths, as fractions of the 12-column row.
756
+ *
757
+ * Five steps rather than all twelve: a free 1–12 spinner is a layout system, and what an
758
+ * author actually wants is "these two side by side" or "this one across the row". The
759
+ * fractions that divide twelve evenly cover that, and anything finer stays authorable in
760
+ * the JSON for the rare case that needs it.
761
+ */
762
+ protected readonly spanChoices: readonly [{
763
+ readonly span: 3;
764
+ readonly textKey: "widthQuarter";
765
+ }, {
766
+ readonly span: 4;
767
+ readonly textKey: "widthThird";
768
+ }, {
769
+ readonly span: 6;
770
+ readonly textKey: "widthHalf";
771
+ }, {
772
+ readonly span: 8;
773
+ readonly textKey: "widthTwoThirds";
774
+ }, {
775
+ readonly span: 12;
776
+ readonly textKey: "widthFull";
777
+ }];
672
778
  protected lang(): string;
779
+ /**
780
+ * How many validators this field actually has, for the section's badge.
781
+ *
782
+ * `false` and an empty `custom: []` are both "not set" written the long way — a toggle
783
+ * switched off leaves the key behind — so neither counts. `0` does: `minLength: 0` is a
784
+ * value somebody typed.
785
+ */
786
+ protected validatorCount(field: NestedFieldConfig): number;
787
+ /**
788
+ * How many display flags are set away from their default.
789
+ *
790
+ * `visibility` counts when it is *false* and the rest when they are true, because the badge
791
+ * is meant to say "something here is not the default" — counting `visibility: true` would
792
+ * put a 1 on every field in the config and tell the author nothing.
793
+ */
794
+ protected displayFlagCount(field: NestedFieldConfig): number;
673
795
  protected toNum(value: unknown): number | null;
674
796
  protected labelValue(field: NestedFieldConfig): string;
675
797
  protected placeholderValue(field: NestedFieldConfig): string;
798
+ protected hintValue(field: NestedFieldConfig): string;
676
799
  protected optionLabel(option: DropdownOption): string;
677
800
  /**
678
801
  * Every tab a field can live on, sub-tabs included.