ngx-dynamic-entity-builder 1.8.1 → 1.9.1

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/README.md CHANGED
@@ -35,7 +35,9 @@ export const appConfig: ApplicationConfig = {
35
35
  - **Rules manager** — create, reorder, edit, and toggle reactive rules (`RuleFormComponent`, `FieldRulesListComponent`).
36
36
  - **Tab & tree manager** — organize primary tabs, sub-tabs, nested groups, and array field lists. Nesting is recursive; no depth limit is enforced.
37
37
  - **Live preview slot** — a projected content slot, so the builder renders a preview without depending on the renderer package.
38
- - **All 20 field types** from the `@dynamic-entity/core` catalog.
38
+ - **Undo & redo** — `Ctrl`/`Cmd`+`Z` and `Ctrl`/`Cmd`+`Shift`+`Z`, plus toolbar buttons that disable at the ends of the history. Consecutive edits inside 400ms merge when the structure is unchanged, so typing a label is one step while adding two fields is two.
39
+ - **All 21 field types** from the `@dynamic-entity/core` catalog.
40
+ - **Translatable interface** — every word the builder itself renders resolves through `BUILDER_TEXT`; `uiLanguage` picks the locale. Date punctuation in a live preview follows `setDateFormatters` from `@dynamic-entity/core`; the masked placeholder is a renderer token (`MASKED_PLACEHOLDER`), not a builder one.
39
41
 
40
42
  ---
41
43
 
@@ -45,6 +47,7 @@ export const appConfig: ApplicationConfig = {
45
47
  <ngx-entity-builder
46
48
  [config]="initialConfig"
47
49
  [languages]="['en', 'de']"
50
+ [uiLanguage]="'en'"
48
51
  [availableRoles]="['admin', 'editor']"
49
52
  (configChange)="onConfigUpdated($event)"
50
53
  (save)="onSave($event)"
@@ -57,6 +60,7 @@ export const appConfig: ApplicationConfig = {
57
60
  |---|---|---|
58
61
  | `config` | `EntityFormConfig \| undefined` | Omit to start from an empty schema. |
59
62
  | `languages` | `string[]` | Locales offered for localized labels. Defaults to `['en']`. |
63
+ | `uiLanguage` | `string` | Locale for the builder's **own** chrome, not the labels being authored. Defaults to `'en'`. |
60
64
  | `availableRoles` | `string[]` | Roles offered in the permissions editor. |
61
65
  | `commonModules` | `readonly CommonModuleEntry[]` | Shared-module options for tabs. |
62
66
 
@@ -69,6 +73,60 @@ export const appConfig: ApplicationConfig = {
69
73
 
70
74
  ---
71
75
 
76
+ ## ↩️ Undo & redo
77
+
78
+ Wired to the toolbar and to `Ctrl`/`Cmd`+`Z` / `Ctrl`/`Cmd`+`Shift`+`Z`. The shortcut is
79
+ ignored while focus is in an input, textarea or contenteditable — those have their own undo
80
+ stack, and taking it over would discard a structural edit when the author wanted one
81
+ character back.
82
+
83
+ Driving it yourself, from a host that injects `BuilderStore`:
84
+
85
+ ```ts
86
+ store.undo(); // no-op at the start of history
87
+ store.redo(); // no-op at the end
88
+ store.canUndo(); // signal — bind it to your own button's disabled state
89
+ store.canRedo();
90
+ ```
91
+
92
+ History records the config and its rules **together**: they are two signals, and undoing one
93
+ without the other could leave a rule pointing at a field that no longer exists. Loading a
94
+ config or resetting starts history again, so opening an entity is not something you can undo
95
+ past.
96
+
97
+ ---
98
+
99
+ ## 🌍 Translating the builder
100
+
101
+ Every word the builder renders itself — panel headings, tooltips, empty states — resolves
102
+ through `BUILDER_TEXT`. The library does no translating; it publishes the keys and resolves
103
+ what you hand back, per key, falling back to English for anything you leave out.
104
+
105
+ ```typescript
106
+ import { BUILDER_TEXT } from 'ngx-dynamic-entity-builder';
107
+
108
+ export const builderTextProvider = {
109
+ provide: BUILDER_TEXT,
110
+ useValue: {
111
+ save: { en: 'Save', de: 'Speichern' },
112
+ addField: { en: 'Add field', de: 'Feld hinzufügen' },
113
+ },
114
+ };
115
+ ```
116
+
117
+ A value may be `LocalizedText`, a flat string, or a resolver
118
+ `(key, defaultText, language) => string` for a host that already has ngx-translate, Transloco
119
+ or `$localize`. `DEFAULT_BUILDER_TEXT` exports all 149 keys with their English source
120
+ strings, so a translation file can be generated from it rather than transcribed.
121
+
122
+ **`uiLanguage` is not `languages`.** `languages` is the vocabulary a label is _authored_ in,
123
+ and `store.activeLanguage()` says which entry the inspector is editing right now. Tying the
124
+ chrome to that would flip the whole interface every time an author switched the label
125
+ language they were working on. `BuilderTextService` is root-provided, so two builders mounted
126
+ at once share one chrome language.
127
+
128
+ ---
129
+
72
130
  ## ⚠️ Known limitations
73
131
 
74
132
  - **Field ids are unique per scope**, not across the whole schema — `address` on Personal Details and `address` on Work Details are two different fields, and records nest by tab so they store separately. The builder still generates and enforces ids that are unique across the config, because its selection model addresses a field by bare id. New `showWhen`, cascade, patch and rule references are chosen from a path list (`[work.address]`). A bare id in an older config is still valid while only one scope defines it; `validateConfig` reports it as ambiguous the moment two do.