@softheon/armature 21.2.0 → 21.2.2
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/assets/styles/material-override/_tooltip.scss +4 -4
- package/b2b/README.md +255 -0
- package/fesm2022/softheon-armature-b2b.mjs +1198 -0
- package/fesm2022/softheon-armature-b2b.mjs.map +1 -0
- package/fesm2022/softheon-armature.mjs +36 -7
- package/fesm2022/softheon-armature.mjs.map +1 -1
- package/package.json +10 -2
- package/types/softheon-armature-b2b.d.ts +584 -0
- package/types/softheon-armature.d.ts +13 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softheon/armature",
|
|
3
|
-
"version": "21.2.
|
|
3
|
+
"version": "21.2.2",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"tslib": "^2.8.1"
|
|
6
6
|
},
|
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"angular-oauth2-oidc-jwks": "~20.0.0",
|
|
25
25
|
"ngx-cookie-service": "^21.1.0",
|
|
26
26
|
"rxjs": "~7.8.0",
|
|
27
|
-
"moment": "^2.29.4"
|
|
27
|
+
"moment": "^2.29.4",
|
|
28
|
+
"@types/json-schema": "^7.0.15"
|
|
28
29
|
},
|
|
29
30
|
"peerDependenciesMeta": {
|
|
30
31
|
"ag-grid-community": {
|
|
@@ -32,6 +33,9 @@
|
|
|
32
33
|
},
|
|
33
34
|
"ag-grid-angular": {
|
|
34
35
|
"optional": true
|
|
36
|
+
},
|
|
37
|
+
"@types/json-schema": {
|
|
38
|
+
"optional": true
|
|
35
39
|
}
|
|
36
40
|
},
|
|
37
41
|
"module": "fesm2022/softheon-armature.mjs",
|
|
@@ -47,6 +51,10 @@
|
|
|
47
51
|
"./ag-grid-components": {
|
|
48
52
|
"types": "./types/softheon-armature-ag-grid-components.d.ts",
|
|
49
53
|
"default": "./fesm2022/softheon-armature-ag-grid-components.mjs"
|
|
54
|
+
},
|
|
55
|
+
"./b2b": {
|
|
56
|
+
"types": "./types/softheon-armature-b2b.d.ts",
|
|
57
|
+
"default": "./fesm2022/softheon-armature-b2b.mjs"
|
|
50
58
|
}
|
|
51
59
|
},
|
|
52
60
|
"sideEffects": false
|
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { OnInit } from '@angular/core';
|
|
3
|
+
import { MatExpansionPanel } from '@angular/material/expansion';
|
|
4
|
+
import { JSONSchema7 } from 'json-schema';
|
|
5
|
+
export { JSONSchema7 as JsonSchema } from 'json-schema';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @fileoverview Models for the SofB2BJsonEditorComponent.
|
|
9
|
+
*
|
|
10
|
+
* Public API types: JsonValue, JsonObject, FieldConfig.
|
|
11
|
+
* Internal types: JsonEntry, JsonNode, JsonNamespace.
|
|
12
|
+
*
|
|
13
|
+
* Consumers interact with the editor via JsonObject input/output and
|
|
14
|
+
* FieldConfig schema only. JsonEntry is internal to the editor's
|
|
15
|
+
* flatten/unflatten pipeline.
|
|
16
|
+
*
|
|
17
|
+
* File is intentionally free of Angular dependencies so it can be
|
|
18
|
+
* imported by both Angular components and plain TypeScript utilities
|
|
19
|
+
* (e.g. unit tests, data-manager helpers).
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Recursive type representing any valid JSON value.
|
|
23
|
+
* Replaces `any` in the public API for type safety while still
|
|
24
|
+
* supporting the full range of JSON structures.
|
|
25
|
+
*
|
|
26
|
+
* Usage:
|
|
27
|
+
* JsonEntry.value, JsonNode.editableValue
|
|
28
|
+
*/
|
|
29
|
+
type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
|
|
30
|
+
/**
|
|
31
|
+
* A JSON object — a string-keyed dictionary of JsonValue.
|
|
32
|
+
* Extracted as a named interface to prevent TypeScript's
|
|
33
|
+
* "excessively deep type instantiation" error on recursive
|
|
34
|
+
* inline mapped types.
|
|
35
|
+
*/
|
|
36
|
+
interface JsonObject {
|
|
37
|
+
[key: string]: JsonValue;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A single key/value entry in the flattened JSON representation.
|
|
41
|
+
* Used internally by the editor's flatten/unflatten pipeline.
|
|
42
|
+
* Consumers should not reference this type — pass JsonObject directly.
|
|
43
|
+
*
|
|
44
|
+
* Keys use path notation produced by flattenJson():
|
|
45
|
+
* dot notation for objects: "BillingInformation.APTCAmount"
|
|
46
|
+
* bracket notation for arrays: "Invoice.Payments[0].Amount"
|
|
47
|
+
* quoted brackets for special keys: '["Discount Amount"]'
|
|
48
|
+
* '["Corrected1095-B"]'
|
|
49
|
+
*
|
|
50
|
+
* @internal
|
|
51
|
+
*/
|
|
52
|
+
interface JsonEntry {
|
|
53
|
+
key: string;
|
|
54
|
+
value: JsonValue;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Supported input control types for scalar fields.
|
|
58
|
+
* The correct type is inferred from the value when not explicitly provided.
|
|
59
|
+
*
|
|
60
|
+
* Current rendering:
|
|
61
|
+
* text → <input type="text">
|
|
62
|
+
* number → <input type="number">
|
|
63
|
+
* date → <input type="date">
|
|
64
|
+
* toggle → <mat-slide-toggle>
|
|
65
|
+
* select → <mat-select>
|
|
66
|
+
*
|
|
67
|
+
* Extend this union as new input types are introduced.
|
|
68
|
+
* Adding a new type requires:
|
|
69
|
+
* 1. Adding it to this union
|
|
70
|
+
* 2. Adding a *ngSwitchCase in sof-b2b-json-node.component.html
|
|
71
|
+
* 3. Optionally updating inferInputType() in json-tree.utils.ts
|
|
72
|
+
*/
|
|
73
|
+
type FieldInputType = 'text' | 'number' | 'date' | 'toggle' | 'select';
|
|
74
|
+
/**
|
|
75
|
+
* Configuration describing how a field should render and behave.
|
|
76
|
+
*
|
|
77
|
+
* Provided via companion schema: the [schema] input on SofB2BJsonEditorComponent,
|
|
78
|
+
* keyed by full path string (e.g. 'BillingInformation.APTCAmount').
|
|
79
|
+
*
|
|
80
|
+
* When no schema is provided, inputType is inferred from the value at
|
|
81
|
+
* build time via inferInputType() in json-tree.utils.ts.
|
|
82
|
+
*/
|
|
83
|
+
interface FieldConfig {
|
|
84
|
+
/**
|
|
85
|
+
* Which input control to render for this field.
|
|
86
|
+
* Inferred from the value if not explicitly provided.
|
|
87
|
+
*/
|
|
88
|
+
inputType?: FieldInputType;
|
|
89
|
+
/**
|
|
90
|
+
* Override the display label shown above the input.
|
|
91
|
+
* Defaults to the key segment (e.g. "APTCAmount" from "BillingInformation.APTCAmount").
|
|
92
|
+
*/
|
|
93
|
+
label?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Prevents user edits when true.
|
|
96
|
+
* Read-only fields are visually distinct and skipped in tab order.
|
|
97
|
+
* Defaults to false.
|
|
98
|
+
*/
|
|
99
|
+
readOnly?: boolean;
|
|
100
|
+
/** Placeholder text shown inside the input when the value is empty. */
|
|
101
|
+
placeholder?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Option list for inputType 'select'.
|
|
104
|
+
* Required when inputType is 'select' — if omitted, falls back to 'text'.
|
|
105
|
+
*/
|
|
106
|
+
options?: string[];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Discriminated union describing the structural type of a JSON value.
|
|
110
|
+
*
|
|
111
|
+
* scalar — a primitive value (string, number, boolean, null)
|
|
112
|
+
* renders as an editable input
|
|
113
|
+
* array — a JSON array
|
|
114
|
+
* renders as a collapsible expansion panel with indexed children
|
|
115
|
+
* object — a JSON object
|
|
116
|
+
* renders as a collapsible expansion panel with named children
|
|
117
|
+
*/
|
|
118
|
+
type JsonNodeType = 'scalar' | 'array' | 'object';
|
|
119
|
+
/**
|
|
120
|
+
* Internal representation of a single node in the JSON tree.
|
|
121
|
+
*
|
|
122
|
+
* Built once at data-load time by buildNode() in json-editor.utils.ts.
|
|
123
|
+
* Never mutated after construction except for editableValue (user edits)
|
|
124
|
+
* and key (prefix stripped by buildNamespaces()).
|
|
125
|
+
*
|
|
126
|
+
* Consumers should not reference this type — it is an implementation detail
|
|
127
|
+
* of the JsonEditor rendering layer.
|
|
128
|
+
*/
|
|
129
|
+
interface JsonNode {
|
|
130
|
+
/**
|
|
131
|
+
* Display key with dot-prefix stripped by buildNamespaces().
|
|
132
|
+
* e.g. "BillingInformation.APTCAmount" becomes "APTCAmount"
|
|
133
|
+
* after the "BillingInformation" namespace is extracted.
|
|
134
|
+
*
|
|
135
|
+
* Mutated by buildNamespaces() — use fullKey for any path operations.
|
|
136
|
+
*/
|
|
137
|
+
key: string;
|
|
138
|
+
/**
|
|
139
|
+
* Original full path key as produced by flattenJson().
|
|
140
|
+
* e.g. "BillingInformation.APTCAmount" or "Invoice.Payments[0].Amount"
|
|
141
|
+
*
|
|
142
|
+
* Never mutated. Used by:
|
|
143
|
+
* - flattenNamespaces() to reconstruct original keys on emit
|
|
144
|
+
* - HTML [id] and [aria-label] bindings for accessibility
|
|
145
|
+
* - Console warnings in guardrails
|
|
146
|
+
*/
|
|
147
|
+
fullKey: string;
|
|
148
|
+
/** Structural type — drives which template branch renders this node. */
|
|
149
|
+
type: JsonNodeType;
|
|
150
|
+
/**
|
|
151
|
+
* Nesting depth starting from 0 at the top level.
|
|
152
|
+
* Used by the depth guardrail in buildNodesFromEntries() and json-node template.
|
|
153
|
+
*/
|
|
154
|
+
depth: number;
|
|
155
|
+
/**
|
|
156
|
+
* Snapshot of the original value at tree-build time.
|
|
157
|
+
* Present only on scalar nodes. Never mutated after construction.
|
|
158
|
+
* Used by SofB2BJsonNodeComponent to compute dirty state
|
|
159
|
+
* (editableValue !== originalValue).
|
|
160
|
+
*/
|
|
161
|
+
originalValue?: JsonValue;
|
|
162
|
+
/**
|
|
163
|
+
* The live editable value. Present only on scalar nodes.
|
|
164
|
+
* Bound directly to [(ngModel)] in sof-b2b-json-node.component.html.
|
|
165
|
+
* Initialised from the deep-cloned original value at build time —
|
|
166
|
+
* changes here never affect the consumer's source data.
|
|
167
|
+
*/
|
|
168
|
+
editableValue?: JsonValue;
|
|
169
|
+
/**
|
|
170
|
+
* Child nodes. Present only on array and object nodes.
|
|
171
|
+
* Empty array means the container exists but has no items —
|
|
172
|
+
* rendered as an empty placeholder, not an expansion panel.
|
|
173
|
+
*/
|
|
174
|
+
children?: JsonNode[];
|
|
175
|
+
/**
|
|
176
|
+
* Field rendering configuration. Always present — never undefined.
|
|
177
|
+
* Guarantees that sof-b2b-json-node.component.html can safely read
|
|
178
|
+
* node.config.inputType without null checks.
|
|
179
|
+
*
|
|
180
|
+
* Set at build time from (in priority order):
|
|
181
|
+
* 1. Companion schema lookup
|
|
182
|
+
* 2. inferInputType() result for scalars
|
|
183
|
+
* 3. Empty object {} for containers
|
|
184
|
+
*/
|
|
185
|
+
config: FieldConfig;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* A top-level grouping of JsonNodes sharing a dot-notation prefix.
|
|
189
|
+
*
|
|
190
|
+
* Built by buildNamespaces() in json-editor.utils.ts.
|
|
191
|
+
* Rendered as the outermost expansion panels in sof-b2b-json-editor.component.html.
|
|
192
|
+
*
|
|
193
|
+
* Examples from the billing JSON:
|
|
194
|
+
* { prefix: 'BillingInformation', nodes: [...] }
|
|
195
|
+
* { prefix: 'Invoice', nodes: [...] }
|
|
196
|
+
* { prefix: '—', nodes: [...] } ← ungrouped top-level keys
|
|
197
|
+
*
|
|
198
|
+
* The "—" namespace is always sorted to the top by buildNamespaces().
|
|
199
|
+
*/
|
|
200
|
+
interface JsonNamespace {
|
|
201
|
+
/**
|
|
202
|
+
* The shared prefix extracted from node keys.
|
|
203
|
+
* e.g. "BillingInformation", "Invoice", "Adjustments"
|
|
204
|
+
* or "—" for keys without a dot-notation prefix
|
|
205
|
+
* (e.g. "COCOFileName", "ScanLine", "Discount Amount").
|
|
206
|
+
*/
|
|
207
|
+
prefix: string;
|
|
208
|
+
/** All nodes belonging to this namespace, in original data order. */
|
|
209
|
+
nodes: JsonNode[];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @fileoverview Path parsing, flatten/unflatten, and normalization utilities.
|
|
214
|
+
*
|
|
215
|
+
* Converts between nested JSON objects and flat JsonEntry[] arrays using
|
|
216
|
+
* dot-notation and bracket-notation path strings.
|
|
217
|
+
*
|
|
218
|
+
* All functions are stateless and side-effect free.
|
|
219
|
+
* No Angular dependencies — fully unit-testable in isolation.
|
|
220
|
+
*
|
|
221
|
+
* Round-trip guarantee: unflattenJson(flattenJson(data)) deep-equals data
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Parses a path string into an array of typed segments.
|
|
226
|
+
*
|
|
227
|
+
* Handles:
|
|
228
|
+
* "a.b.c" → ['a', 'b', 'c']
|
|
229
|
+
* "a.b[0].c" → ['a', 'b', 0, 'c']
|
|
230
|
+
* '["Discount Amount"]' → ['Discount Amount']
|
|
231
|
+
* 'a["Corrected1095-B"].val' → ['a', 'Corrected1095-B', 'val']
|
|
232
|
+
*
|
|
233
|
+
* Three capture groups:
|
|
234
|
+
* 1 — plain key segment: word chars only (no dots, brackets, quotes)
|
|
235
|
+
* 2 — numeric array index: [0], [1], [42]
|
|
236
|
+
* 3 — quoted bracket key: ["any string here"]
|
|
237
|
+
*/
|
|
238
|
+
declare function parsePath(path: string): (string | number)[];
|
|
239
|
+
/**
|
|
240
|
+
* Reconstructs a nested object from JsonEntry[].
|
|
241
|
+
* Parses both dot notation and bracket notation paths.
|
|
242
|
+
*
|
|
243
|
+
* Inverse of flattenJson — guarantees round-trip fidelity.
|
|
244
|
+
*
|
|
245
|
+
* @param entries Flat JsonEntry[] produced by flattenJson()
|
|
246
|
+
*/
|
|
247
|
+
declare function unflattenJson(entries: JsonEntry[]): JsonObject;
|
|
248
|
+
/**
|
|
249
|
+
* Flattens a raw nested JSON object into JsonEntry[].
|
|
250
|
+
* Convenience wrapper around flattenJson() — used by SofB2BJsonEditorComponent
|
|
251
|
+
* to convert its JsonObject input into flat entries for tree building.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* normalizeToEntries({ BillingInformation: { APTCAmount: '0.00' } })
|
|
255
|
+
* // → [{ key: 'BillingInformation.APTCAmount', value: '0.00' }]
|
|
256
|
+
*/
|
|
257
|
+
declare function normalizeToEntries(input: JsonObject): JsonEntry[];
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @fileoverview Tree construction, value reconstruction, and namespace emission.
|
|
261
|
+
*
|
|
262
|
+
* Builds a JsonNode tree from flat JsonEntry[] for rendering, and reconstructs
|
|
263
|
+
* flat JsonEntry[] from the tree for emission back to the consumer.
|
|
264
|
+
*
|
|
265
|
+
* Also includes type inference, field config resolution, and validation.
|
|
266
|
+
*
|
|
267
|
+
* All functions are stateless and side-effect free (except console warnings).
|
|
268
|
+
* No Angular dependencies — fully unit-testable in isolation.
|
|
269
|
+
*
|
|
270
|
+
* Guardrails:
|
|
271
|
+
* Max depth cap — MAX_DEPTH constant in buildNodesFromEntries()
|
|
272
|
+
* Duplicate key warning — Set check in validateDuplicateKeys()
|
|
273
|
+
* Undefined output guard — null coalesce in flattenNamespaces()
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* MAX_DEPTH guardrail.
|
|
278
|
+
* Nodes beyond this depth are skipped rather than recursed into.
|
|
279
|
+
* Prevents call-stack overflow on pathologically deep structures.
|
|
280
|
+
*/
|
|
281
|
+
declare const MAX_DEPTH = 20;
|
|
282
|
+
/**
|
|
283
|
+
* Duplicate key guardrail.
|
|
284
|
+
* Warns when two entries share the same key. The second occurrence
|
|
285
|
+
* silently overwrites the first, producing incorrect emitted data.
|
|
286
|
+
*
|
|
287
|
+
* @param entries The JsonEntry[] to check for duplicate keys
|
|
288
|
+
*/
|
|
289
|
+
declare function validateDuplicateKeys(entries: JsonEntry[]): void;
|
|
290
|
+
/**
|
|
291
|
+
* Builds a JsonNode tree from flat JsonEntry[] by grouping path segments
|
|
292
|
+
* into their natural hierarchy.
|
|
293
|
+
*
|
|
294
|
+
* This is the core tree-building function. It takes fully-flattened entries
|
|
295
|
+
* (e.g. "AdjustmentReasons[0].Code") and reconstructs the nested structure
|
|
296
|
+
* that the template renders as collapsible expansion panels.
|
|
297
|
+
*
|
|
298
|
+
* Handles three value shapes:
|
|
299
|
+
* 1. Empty [] or {} — object/array with zero length, render as empty container
|
|
300
|
+
* 2. Scalar / primitive — null, string, number, boolean — render as input
|
|
301
|
+
* 3. Container — multiple children or deeper path — recurse
|
|
302
|
+
*
|
|
303
|
+
* Depth guardrail — stops recursing beyond MAX_DEPTH.
|
|
304
|
+
*
|
|
305
|
+
* @param entries Flat JsonEntry[] with namespace prefix already stripped
|
|
306
|
+
* @param schema Optional companion schema for field config
|
|
307
|
+
* @param depth Current nesting depth (0 = top level within namespace)
|
|
308
|
+
*/
|
|
309
|
+
declare function buildNodesFromEntries(entries: JsonEntry[], schema?: Record<string, FieldConfig>, depth?: number): JsonNode[];
|
|
310
|
+
/**
|
|
311
|
+
* Flattens JsonNamespace[] back into JsonEntry[] for emission.
|
|
312
|
+
*
|
|
313
|
+
* Undefined output guardrail — reconstructValue() returning undefined
|
|
314
|
+
* is coalesced to null rather than emitting undefined to the consumer.
|
|
315
|
+
*
|
|
316
|
+
* @param namespaces The current namespace tree to flatten
|
|
317
|
+
*/
|
|
318
|
+
declare function flattenNamespaces(namespaces: JsonNamespace[]): JsonEntry[];
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @fileoverview Search filtering and tree pruning utilities.
|
|
322
|
+
*
|
|
323
|
+
* Filters a JsonNamespace[] tree to only nodes matching a search term.
|
|
324
|
+
* Uses recursive tree pruning — non-matching branches are removed,
|
|
325
|
+
* matching ancestors are preserved.
|
|
326
|
+
*
|
|
327
|
+
* All functions are stateless and side-effect free.
|
|
328
|
+
* No Angular dependencies — fully unit-testable in isolation.
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Filters a JsonNamespace[] tree to only namespaces and nodes
|
|
333
|
+
* matching the search term. Uses tree pruning — non-matching branches
|
|
334
|
+
* are removed, matching ancestors are preserved.
|
|
335
|
+
*
|
|
336
|
+
* Returns the original array reference unchanged if term is below
|
|
337
|
+
* the minimum length — no filtering overhead on short terms.
|
|
338
|
+
*
|
|
339
|
+
* @param namespaces The full namespace tree to filter
|
|
340
|
+
* @param term The search string (case-insensitive, min 2 chars)
|
|
341
|
+
*/
|
|
342
|
+
declare function filterNamespaces(namespaces: JsonNamespace[], term: string): JsonNamespace[];
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* The Sof B2B JSON Editor Component
|
|
346
|
+
Root JsonEditor template.
|
|
347
|
+
Renders JsonNamespace[] as top-level expansion panels.
|
|
348
|
+
All child node rendering is delegated to sof-b2b-json-node.
|
|
349
|
+
*/
|
|
350
|
+
declare class SofB2BJsonEditorComponent implements OnInit {
|
|
351
|
+
/**
|
|
352
|
+
* Raw nested JSON object to edit.
|
|
353
|
+
* Internally flattened into JsonEntry[] for tree construction.
|
|
354
|
+
* ⚠️ Pass a new object reference to trigger re-computation.
|
|
355
|
+
*/
|
|
356
|
+
readonly data: _angular_core.InputSignal<JsonObject>;
|
|
357
|
+
/**
|
|
358
|
+
* Optional JSON Schema (Draft 7+) describing the data shape.
|
|
359
|
+
* When provided, the editor parses it internally and uses it to configure
|
|
360
|
+
* field types, labels, and dropdown options at tree-build time.
|
|
361
|
+
* Fields not found in the schema fall back to inferInputType().
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* const schema: JsonSchema = {
|
|
365
|
+
* type: 'object',
|
|
366
|
+
* properties: {
|
|
367
|
+
* Theme: { type: 'string', enum: ['dark', 'light'] },
|
|
368
|
+
* MaxRetries: { type: 'integer', title: 'Max Retries' },
|
|
369
|
+
* },
|
|
370
|
+
* };
|
|
371
|
+
*/
|
|
372
|
+
readonly schema: _angular_core.InputSignal<JSONSchema7>;
|
|
373
|
+
/** Debounce delay in ms before dataChanged emits. Default: 1500. */
|
|
374
|
+
readonly debounceMs: _angular_core.InputSignal<number>;
|
|
375
|
+
/** Message shown when data is empty. */
|
|
376
|
+
readonly emptyMessage: _angular_core.InputSignal<string>;
|
|
377
|
+
/** Message shown when search returns no matches. */
|
|
378
|
+
readonly noResultsMessage: _angular_core.InputSignal<string>;
|
|
379
|
+
/**
|
|
380
|
+
* Search term for filtering the tree.
|
|
381
|
+
* Minimum 2 characters to trigger filtering — shorter terms
|
|
382
|
+
* match too broadly and run the full recursive walk unnecessarily.
|
|
383
|
+
*/
|
|
384
|
+
readonly searchTerm: _angular_core.InputSignal<string>;
|
|
385
|
+
/** Whether or not to render the json editor in read-only mode.
|
|
386
|
+
* When true, all scalar fields display as plaintext, toggles are disabled,
|
|
387
|
+
* and the change$/debounce subscription is never created. Default: false. */
|
|
388
|
+
readonly readOnly: _angular_core.InputSignal<boolean>;
|
|
389
|
+
/**
|
|
390
|
+
* Emits the full reconstructed nested JSON object after debounce period.
|
|
391
|
+
* Pass directly to any consumer expecting a JsonObject.
|
|
392
|
+
* 🛡️ Suppressed when readOnly is true.
|
|
393
|
+
*/
|
|
394
|
+
readonly dataChanged: _angular_core.OutputEmitterRef<JsonObject>;
|
|
395
|
+
/**
|
|
396
|
+
* Emits an error message string when a parsing or validation error occurs.
|
|
397
|
+
* Consumers can subscribe to display errors in their own UI (snackbar, toast, etc.).
|
|
398
|
+
*/
|
|
399
|
+
readonly parseError: _angular_core.OutputEmitterRef<string>;
|
|
400
|
+
/** Top-level namespace panels only — not nested array/object panels. */
|
|
401
|
+
readonly namespacePanels: _angular_core.Signal<readonly MatExpansionPanel[]>;
|
|
402
|
+
/**
|
|
403
|
+
* Parsed JSON Schema → flat Record<string, FieldConfig>.
|
|
404
|
+
* Recomputes when the schema input changes. Used internally by
|
|
405
|
+
* buildTree() for field config resolution. Consumers never see this.
|
|
406
|
+
*/
|
|
407
|
+
private readonly parsedSchema;
|
|
408
|
+
/**
|
|
409
|
+
* Internal flat entries derived from the data input.
|
|
410
|
+
* Recomputes automatically when data() changes.
|
|
411
|
+
* Protected so the template can check entries().length for empty state.
|
|
412
|
+
*/
|
|
413
|
+
protected readonly entries: _angular_core.Signal<JsonEntry[]>;
|
|
414
|
+
/**
|
|
415
|
+
* Full namespace tree built from internal entries.
|
|
416
|
+
* Recomputes automatically when data() or schema() changes.
|
|
417
|
+
* 🔑 Duplicate key validation runs on every recomputation.
|
|
418
|
+
*/
|
|
419
|
+
protected readonly namespaces: _angular_core.Signal<JsonNamespace[]>;
|
|
420
|
+
/**
|
|
421
|
+
* Filtered namespace tree derived from namespaces + searchTerm.
|
|
422
|
+
* Recomputes automatically when either signal changes.
|
|
423
|
+
* No manual sync needed — computed() handles both inputs.
|
|
424
|
+
*
|
|
425
|
+
* This replaces the manual sync bug where filteredNamespaces
|
|
426
|
+
* started as [] and wasn't populated until a search fired.
|
|
427
|
+
*/
|
|
428
|
+
protected readonly filteredNamespaces: _angular_core.Signal<JsonNamespace[]>;
|
|
429
|
+
/** The Internal state changes */
|
|
430
|
+
private readonly change$;
|
|
431
|
+
/**
|
|
432
|
+
* 💾 DestroyRef — takeUntilDestroyed() auto-completes the debounce
|
|
433
|
+
* subscription on component destroy, preventing memory leaks and
|
|
434
|
+
* emissions to destroyed parent components.
|
|
435
|
+
*/
|
|
436
|
+
private readonly destroyRef;
|
|
437
|
+
ngOnInit(): void;
|
|
438
|
+
/** Programmatically opens all top-level namespace panels. */
|
|
439
|
+
openAll(): void;
|
|
440
|
+
/** Programmatically closes all top-level namespace panels. */
|
|
441
|
+
closeAll(): void;
|
|
442
|
+
/** Handles value changes from any child SofB2BJsonNodeComponent. Pushes into the debounce stream. */
|
|
443
|
+
protected onValueChanged(): void;
|
|
444
|
+
/**
|
|
445
|
+
* Groups flat JsonEntry[] into a namespace tree for rendering.
|
|
446
|
+
*
|
|
447
|
+
* Each entry's first path segment becomes the namespace prefix.
|
|
448
|
+
* Entries whose keys start with `[` (bracket notation) are grouped
|
|
449
|
+
* under a fallback "—" namespace and sorted to the top.
|
|
450
|
+
*
|
|
451
|
+
* Regex metacharacters in the prefix are escaped before stripping
|
|
452
|
+
* it from child keys (e.g. `$Settings.Foo` won't break the RegExp).
|
|
453
|
+
*/
|
|
454
|
+
private buildTree;
|
|
455
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SofB2BJsonEditorComponent, never>;
|
|
456
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SofB2BJsonEditorComponent, "sof-b2b-json-editor", never, { "data": { "alias": "data"; "required": false; "isSignal": true; }; "schema": { "alias": "schema"; "required": false; "isSignal": true; }; "debounceMs": { "alias": "debounceMs"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "noResultsMessage": { "alias": "noResultsMessage"; "required": false; "isSignal": true; }; "searchTerm": { "alias": "searchTerm"; "required": false; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; }, { "dataChanged": "dataChanged"; "parseError": "parseError"; }, never, never, true, never>;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** The Sof B2B JSON Editor Node Component */
|
|
460
|
+
declare class SofB2BJsonNodeComponent {
|
|
461
|
+
/**
|
|
462
|
+
* ChangeDetectorRef is ONLY needed for addItem() and removeItem().
|
|
463
|
+
* Those methods mutate node().children in place — the node signal reference
|
|
464
|
+
* doesn't change, so OnPush won't re-evaluate the @for loop without an
|
|
465
|
+
* explicit markForCheck(). All other reactivity in this component uses signals.
|
|
466
|
+
*/
|
|
467
|
+
private readonly cdr;
|
|
468
|
+
/** The JsonNode to render. Required input. */
|
|
469
|
+
readonly node: _angular_core.InputSignal<JsonNode>;
|
|
470
|
+
/** When true, all fields render as non-editable plaintext. Passed from SofB2BJsonEditorComponent. */
|
|
471
|
+
readonly readOnly: _angular_core.InputSignal<boolean>;
|
|
472
|
+
/** Bubbles up from any depth to the root SofB2BJsonEditorComponent. */
|
|
473
|
+
readonly valueChanged: _angular_core.OutputEmitterRef<void>;
|
|
474
|
+
/** Exposed to template for the 📏 depth guardrail check. */
|
|
475
|
+
protected readonly maxDepth = 20;
|
|
476
|
+
/** Whether this node is an empty container (array/object with no children). */
|
|
477
|
+
protected readonly isEmpty: _angular_core.Signal<boolean>;
|
|
478
|
+
/**
|
|
479
|
+
* Whether the scalar field has been edited (current value differs from original).
|
|
480
|
+
* Always false for non-scalar nodes. Updated imperatively on each ngModelChange
|
|
481
|
+
* because the `node` signal reference doesn't change when `editableValue` is
|
|
482
|
+
* mutated in place by ngModel — a computed() based on node() alone would never
|
|
483
|
+
* re-evaluate.
|
|
484
|
+
*
|
|
485
|
+
* Also recalculated when the `node` input changes (via effect) so that the
|
|
486
|
+
* initial render already reflects dirty state (e.g. when a parent rebuilds the
|
|
487
|
+
* tree after external data changes).
|
|
488
|
+
*/
|
|
489
|
+
protected isDirty: boolean;
|
|
490
|
+
/**
|
|
491
|
+
* Whether this array node supports add/remove operations.
|
|
492
|
+
* True when: array type, has at least 1 child (provides template for cloning),
|
|
493
|
+
* and not in readOnly mode. Empty arrays show "(no schema)" instead.
|
|
494
|
+
*/
|
|
495
|
+
protected readonly canModifyArray: _angular_core.Signal<boolean>;
|
|
496
|
+
/**
|
|
497
|
+
* Label for the "Add" button, e.g. "Add Member" for an array named "Members".
|
|
498
|
+
* Uses naive singularization (strip trailing "s") for a natural UX label.
|
|
499
|
+
*/
|
|
500
|
+
protected readonly addButtonLabel: _angular_core.Signal<string>;
|
|
501
|
+
constructor();
|
|
502
|
+
/** Label describing the child count, e.g. "3 items" or "2 fields". */
|
|
503
|
+
protected readonly childLabel: _angular_core.Signal<string>;
|
|
504
|
+
/**
|
|
505
|
+
* Sanitized id safe for use in HTML id attributes and CSS selectors.
|
|
506
|
+
* node.fullKey may contain brackets and quotes (e.g. ["Discount Amount"])
|
|
507
|
+
* which are invalid in CSS selectors and break browser extension queries.
|
|
508
|
+
*/
|
|
509
|
+
protected readonly safeId: _angular_core.Signal<string>;
|
|
510
|
+
/** Relays child node value changes upward to the parent. Enables event bubbling through the recursive tree. */
|
|
511
|
+
protected onChildChanged(): void;
|
|
512
|
+
/**
|
|
513
|
+
* Called from the template on every `(ngModelChange)` for scalar inputs.
|
|
514
|
+
* Updates the dirty flag by comparing the current editableValue against the
|
|
515
|
+
* original snapshot, then bubbles the change event upward.
|
|
516
|
+
*/
|
|
517
|
+
protected onValueChanged(): void;
|
|
518
|
+
/**
|
|
519
|
+
* Adds a new item to this array node by cloning the first child as a template.
|
|
520
|
+
* The cloned item's scalar descendants have originalValue = editableValue,
|
|
521
|
+
* so they do not appear dirty. Replaces the children array reference and
|
|
522
|
+
* marks the view for check since the node signal itself doesn't change.
|
|
523
|
+
*/
|
|
524
|
+
protected addItem(): void;
|
|
525
|
+
/**
|
|
526
|
+
* Removes an item from this array node at the given index.
|
|
527
|
+
* Minimum items = 1 — cannot delete the last remaining item.
|
|
528
|
+
* After removal, reindexes remaining children to keep display keys sequential.
|
|
529
|
+
*/
|
|
530
|
+
protected removeItem(index: number): void;
|
|
531
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SofB2BJsonNodeComponent, never>;
|
|
532
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SofB2BJsonNodeComponent, "sof-b2b-json-node", never, { "node": { "alias": "node"; "required": true; "isSignal": true; }; "readOnly": { "alias": "readOnly"; "required": false; "isSignal": true; }; }, { "valueChanged": "valueChanged"; }, never, never, true, never>;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
declare class SofB2BModule {
|
|
536
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SofB2BModule, never>;
|
|
537
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<SofB2BModule, never, [typeof SofB2BJsonEditorComponent, typeof SofB2BJsonNodeComponent], [typeof SofB2BJsonEditorComponent, typeof SofB2BJsonNodeComponent]>;
|
|
538
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<SofB2BModule>;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* @fileoverview JSON Schema → FieldConfig parser.
|
|
543
|
+
*
|
|
544
|
+
* Converts a standard JSON Schema (Draft 7+) into a flat
|
|
545
|
+
* Record<string, FieldConfig> keyed by dot-notation paths.
|
|
546
|
+
* The output plugs directly into SofB2BJsonEditorComponent's [schema] input
|
|
547
|
+
* and is consumed by buildFieldConfig() at tree-build time.
|
|
548
|
+
*
|
|
549
|
+
* Supported JSON Schema keywords:
|
|
550
|
+
* type → maps to FieldInputType ('text', 'number', 'toggle', 'select')
|
|
551
|
+
* enum → options[] + inputType 'select'
|
|
552
|
+
* $id / title → label override
|
|
553
|
+
* properties → recursed into, building dot-notation paths
|
|
554
|
+
* items → recursed into for array element schemas
|
|
555
|
+
*
|
|
556
|
+
* Intentionally ignored (Tier 1 — basic support):
|
|
557
|
+
* pattern, format, minLength, maxLength, minimum, maximum,
|
|
558
|
+
* additionalProperties, required, allOf, anyOf, oneOf, $ref
|
|
559
|
+
*
|
|
560
|
+
* All functions are stateless and side-effect free.
|
|
561
|
+
* No Angular dependencies — fully unit-testable in isolation.
|
|
562
|
+
*/
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Parses a JSON Schema document into a flat Record<string, FieldConfig>
|
|
566
|
+
* suitable for passing to SofB2BJsonEditorComponent's [schema] input.
|
|
567
|
+
*
|
|
568
|
+
* @param schema A JSON Schema object (Draft 7+ compatible).
|
|
569
|
+
* Pass null/undefined for a no-op that returns {}.
|
|
570
|
+
* @returns A flat map of dot-notation paths → FieldConfig.
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* const schema = await fetch('/api/schema').then(r => r.json());
|
|
574
|
+
* const fieldConfigs = parseJsonSchema(schema);
|
|
575
|
+
* // fieldConfigs = {
|
|
576
|
+
* // 'Settings.Theme': { inputType: 'select', options: ['dark', 'light'] },
|
|
577
|
+
* // 'Settings.MaxRetries': { inputType: 'number' },
|
|
578
|
+
* // 'Settings.Enabled': { inputType: 'toggle' },
|
|
579
|
+
* // }
|
|
580
|
+
*/
|
|
581
|
+
declare function parseJsonSchema(schema: JSONSchema7 | null | undefined): Record<string, FieldConfig>;
|
|
582
|
+
|
|
583
|
+
export { MAX_DEPTH, SofB2BJsonEditorComponent, SofB2BJsonNodeComponent, SofB2BModule, buildNodesFromEntries, filterNamespaces, flattenNamespaces, normalizeToEntries, parseJsonSchema, parsePath, unflattenJson, validateDuplicateKeys };
|
|
584
|
+
export type { FieldConfig, JsonEntry, JsonNamespace, JsonNode, JsonObject, JsonValue };
|
|
@@ -2072,7 +2072,7 @@ declare class ValidationKeys {
|
|
|
2072
2072
|
* @description
|
|
2073
2073
|
* - This component can be used as a single select or multi-select.
|
|
2074
2074
|
* - Can be used with a reactive formControlName.
|
|
2075
|
-
* - Can be used with [(
|
|
2075
|
+
* - Can be used with [(ngModel)] binding.
|
|
2076
2076
|
* - Can be used without a form using the (selectionChange) output event.
|
|
2077
2077
|
*/
|
|
2078
2078
|
declare class SofSelectComponent implements ControlValueAccessor, Validator, OnInit, AfterViewInit, OnDestroy {
|
|
@@ -6785,6 +6785,12 @@ declare class SofSnackbarComponent {
|
|
|
6785
6785
|
private _snackbarService;
|
|
6786
6786
|
/** Snackbars array signal */
|
|
6787
6787
|
snackbars: Signal<Array<_SnackbarInternal>>;
|
|
6788
|
+
/** Position from top for the snackbar container */
|
|
6789
|
+
positionTop: string | undefined;
|
|
6790
|
+
/** Position from right for the snackbar container (default: 24px) */
|
|
6791
|
+
positionRight: string;
|
|
6792
|
+
/** Position from bottom for the snackbar container (default: 24px) */
|
|
6793
|
+
positionBottom: string;
|
|
6788
6794
|
/** Live announcer for screen reader wcag */
|
|
6789
6795
|
private _liveAnnouncerService;
|
|
6790
6796
|
/** Translation service */
|
|
@@ -6813,7 +6819,7 @@ declare class SofSnackbarComponent {
|
|
|
6813
6819
|
*/
|
|
6814
6820
|
handleAction(snackbar: _SnackbarInternal): void;
|
|
6815
6821
|
static ɵfac: i0.ɵɵFactoryDeclaration<SofSnackbarComponent, never>;
|
|
6816
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SofSnackbarComponent, "sof-snackbar", never, {}, {}, never, never, true, never>;
|
|
6822
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SofSnackbarComponent, "sof-snackbar", never, { "positionTop": { "alias": "positionTop"; "required": false; }; "positionRight": { "alias": "positionRight"; "required": false; }; "positionBottom": { "alias": "positionBottom"; "required": false; }; }, {}, never, never, true, never>;
|
|
6817
6823
|
}
|
|
6818
6824
|
|
|
6819
6825
|
/** Toast Model */
|
|
@@ -6879,6 +6885,10 @@ declare class TextOverflowEllipsisTooltipDirective implements AfterViewInit, OnD
|
|
|
6879
6885
|
* @note If no tooltip text provided, will use the elements 'textContent'
|
|
6880
6886
|
*/
|
|
6881
6887
|
tooltipText: string;
|
|
6888
|
+
/** Custom classes for the tooltip */
|
|
6889
|
+
tooltipClass: string | Array<string>;
|
|
6890
|
+
/** Possible positions for a tooltip : "left" | "right" | "above" | "below" | "before" | "after" */
|
|
6891
|
+
tooltipPosition: TooltipPosition;
|
|
6882
6892
|
/** Is the element overflowing */
|
|
6883
6893
|
private isOverflowing;
|
|
6884
6894
|
/** The resize observer */
|
|
@@ -6905,7 +6915,7 @@ declare class TextOverflowEllipsisTooltipDirective implements AfterViewInit, OnD
|
|
|
6905
6915
|
/** Hide the tooltip on mouseleave */
|
|
6906
6916
|
onMouseLeave(): void;
|
|
6907
6917
|
static ɵfac: i0.ɵɵFactoryDeclaration<TextOverflowEllipsisTooltipDirective, never>;
|
|
6908
|
-
static ɵdir: i0.ɵɵDirectiveDeclaration<TextOverflowEllipsisTooltipDirective, "[textOverflowEllipsisTooltip]", never, { "tooltipText": { "alias": "textOverflowEllipsisTooltip"; "required": false; }; }, {}, never, never, true, never>;
|
|
6918
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<TextOverflowEllipsisTooltipDirective, "[textOverflowEllipsisTooltip]", never, { "tooltipText": { "alias": "textOverflowEllipsisTooltip"; "required": false; }; "tooltipClass": { "alias": "ellipsisTooltipClass"; "required": false; }; "tooltipPosition": { "alias": "ellipsisTooltipPosition"; "required": false; }; }, {}, never, never, true, never>;
|
|
6909
6919
|
}
|
|
6910
6920
|
|
|
6911
6921
|
declare class MfeModule {
|