ngx-dynamic-entity-builder 1.6.0 → 1.8.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.
|
|
3
|
+
"version": "1.8.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.
|
|
14
|
-
"ngx-dynamic-entity": "^1.
|
|
13
|
+
"@dynamic-entity/core": "^1.8.0",
|
|
14
|
+
"ngx-dynamic-entity": "^1.8.0",
|
|
15
15
|
"rxjs": "^7.0.0"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
@@ -46,6 +46,39 @@ declare class BuilderStore {
|
|
|
46
46
|
* made any role-checking predicate answer false for everyone.
|
|
47
47
|
*/
|
|
48
48
|
private readonly _userRoles;
|
|
49
|
+
private readonly history;
|
|
50
|
+
private readonly cursor;
|
|
51
|
+
private readonly historyLength;
|
|
52
|
+
private lastEditAt;
|
|
53
|
+
/** Consecutive edits closer together than this fold into one undo step. */
|
|
54
|
+
private static readonly COALESCE_MS;
|
|
55
|
+
readonly canUndo: _angular_core.Signal<boolean>;
|
|
56
|
+
readonly canRedo: _angular_core.Signal<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Fold the current state into history.
|
|
59
|
+
*
|
|
60
|
+
* Called explicitly by the write paths rather than from an `effect`. An effect would have
|
|
61
|
+
* been fewer call sites, but it requires an injection context: `BuilderStore` had no
|
|
62
|
+
* constructor, so `new BuilderStore()` was legal, and adding one broke every caller that
|
|
63
|
+
* did it with NG0203. Explicit calls also make the timing deterministic — a test can
|
|
64
|
+
* assert straight after an edit instead of flushing effects first.
|
|
65
|
+
*
|
|
66
|
+
* Calling it twice for one operation is harmless: the second call sees the same signal
|
|
67
|
+
* references already at the cursor and returns.
|
|
68
|
+
*
|
|
69
|
+
* `setFieldLabel` is bound to a keystroke, so recording every emission would make undo
|
|
70
|
+
* walk back one character at a time. Two consecutive edits merge when they land inside
|
|
71
|
+
* `COALESCE_MS` *and* the structure is unchanged — a rename coalesces, while adding,
|
|
72
|
+
* removing or moving anything always earns its own step however fast it is clicked.
|
|
73
|
+
*/
|
|
74
|
+
private record;
|
|
75
|
+
/** Counts that distinguish a structural edit from a value edit. */
|
|
76
|
+
private shapeOf;
|
|
77
|
+
/** Start history again from the state just loaded. Nothing before it is undoable. */
|
|
78
|
+
private resetHistory;
|
|
79
|
+
undo(): void;
|
|
80
|
+
redo(): void;
|
|
81
|
+
private applyHistory;
|
|
49
82
|
readonly config: _angular_core.Signal<EntityFormConfig>;
|
|
50
83
|
readonly selectedFieldId: _angular_core.Signal<string>;
|
|
51
84
|
readonly activeLanguage: _angular_core.Signal<string>;
|
|
@@ -109,7 +142,36 @@ declare class BuilderStore {
|
|
|
109
142
|
* therefore see deeper than `fields()`, which stops at a tab's own fields.
|
|
110
143
|
*/
|
|
111
144
|
private allFieldIds;
|
|
145
|
+
/**
|
|
146
|
+
* Resolve a field by key, where a key is either its `refererField` path or a bare id.
|
|
147
|
+
*
|
|
148
|
+
* Every resolution in this store funnels through here, which is why a bare id was enough
|
|
149
|
+
* to edit the wrong field: with `personal.address` and `work.address` both present, the
|
|
150
|
+
* first match won, so selecting or editing the second one silently addressed the first.
|
|
151
|
+
*
|
|
152
|
+
* The path is tried across the whole tree before any bare id is, so an exact key never
|
|
153
|
+
* loses to a nearer-but-wrong match. Bare ids still resolve — every existing caller and
|
|
154
|
+
* spec passes one, and for an unambiguous id it is the same field either way.
|
|
155
|
+
*/
|
|
112
156
|
private findFieldInTabs;
|
|
157
|
+
private findFieldBy;
|
|
158
|
+
/**
|
|
159
|
+
* The key a caller should hand back to address this exact field. Templates use it so a
|
|
160
|
+
* click on the second of two same-named fields selects that one.
|
|
161
|
+
*/
|
|
162
|
+
keyOf(field: {
|
|
163
|
+
id: string;
|
|
164
|
+
refererField?: string;
|
|
165
|
+
}): string;
|
|
166
|
+
/**
|
|
167
|
+
* Whether this exact field is the selected one.
|
|
168
|
+
*
|
|
169
|
+
* Not `selectedFieldId() === field.id`: selection may hold a bare id or a path depending
|
|
170
|
+
* on who set it, and with two fields sharing an id a bare comparison lights up both rows
|
|
171
|
+
* — or neither, once the click starts storing a path. Resolving both sides answers for
|
|
172
|
+
* the field itself.
|
|
173
|
+
*/
|
|
174
|
+
isSelected(field: NestedFieldConfig): boolean;
|
|
113
175
|
addField(type: RichFieldType, targetTabId?: string): string;
|
|
114
176
|
updateField(id: string, patch: Partial<NestedFieldConfig>): void;
|
|
115
177
|
/**
|
|
@@ -129,10 +191,16 @@ declare class BuilderStore {
|
|
|
129
191
|
* That was survivable while renaming was a rare manual act; label-derived ids make it
|
|
130
192
|
* routine, so the references move with it.
|
|
131
193
|
*/
|
|
194
|
+
/**
|
|
195
|
+
* `key` addresses the field to rename; `oldId` is the bare id every *reference* to it
|
|
196
|
+
* carries. They were one parameter, which worked only while an id was unique across the
|
|
197
|
+
* config: resolving needs the path, while `showWhen`, `parentField`, `autoPatch` targets
|
|
198
|
+
* and rules are all keyed by bare id and never match a path.
|
|
199
|
+
*/
|
|
132
200
|
private applyRename;
|
|
133
|
-
removeField(
|
|
201
|
+
removeField(key: string): void;
|
|
134
202
|
duplicateField(id: string): string | null;
|
|
135
|
-
moveField(
|
|
203
|
+
moveField(key: string, direction: -1 | 1): void;
|
|
136
204
|
/**
|
|
137
205
|
* Moves a field to another tab, keeping its id.
|
|
138
206
|
*
|
|
@@ -160,7 +228,7 @@ declare class BuilderStore {
|
|
|
160
228
|
* Only the config's default language drives the id; translating a label must not rename
|
|
161
229
|
* anything.
|
|
162
230
|
*/
|
|
163
|
-
setFieldLabel(
|
|
231
|
+
setFieldLabel(key: string, language: string, value: string): void;
|
|
164
232
|
/** `derived`, or `derived_2`, `derived_3`… if another field already holds it. */
|
|
165
233
|
private availableId;
|
|
166
234
|
setFieldPlaceholder(id: string, language: string, value: string): void;
|
|
@@ -324,6 +392,13 @@ declare class EntityBuilderComponent implements OnChanges {
|
|
|
324
392
|
save: EventEmitter<EntityFormConfig>;
|
|
325
393
|
protected readonly rbacActions: (keyof EntityPermissions)[];
|
|
326
394
|
constructor();
|
|
395
|
+
/**
|
|
396
|
+
* Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z, but only when the user is not typing.
|
|
397
|
+
*
|
|
398
|
+
* A textarea or input has its own undo stack, and hijacking it would make Ctrl+Z revert a
|
|
399
|
+
* whole structural edit when the author only wanted to take back a character.
|
|
400
|
+
*/
|
|
401
|
+
protected onKeydown(event: KeyboardEvent): void;
|
|
327
402
|
ngOnChanges(changes: SimpleChanges): void;
|
|
328
403
|
protected doSave(): void;
|
|
329
404
|
protected get json(): string;
|