@softheon/armature 21.2.1 → 21.2.3

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/b2b/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # @softheon/armature/b2b
2
+
3
+ Secondary entry point for B2B components in the `@softheon/armature` library. Optional B2B components with zero added bundle cost.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ @softheon/armature/b2b
9
+ ├─ SofB2BModule (NgModule wrapper — optional)
10
+ ├─ SofB2BJsonEditorComponent (standalone, root editor)
11
+ │ └─ SofB2BJsonNodeComponent (standalone, recursive renderer)
12
+ └─ Utilities
13
+ ├─ json-path.utils.ts (flatten / unflatten / path parsing)
14
+ ├─ json-tree.utils.ts (tree build / reconstruct / array clone & reindex)
15
+ ├─ json-filter.utils.ts (search filtering)
16
+ └─ json-schema.utils.ts (JSON Schema parsing — internal)
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Install the type dependency (optional)
22
+
23
+ The `[schema]` input uses `JsonSchema`, an alias for `JSONSchema7` from `@types/json-schema`. Add it as a devDependency if you plan to use schema-driven field configuration:
24
+
25
+ ```bash
26
+ npm install --save-dev @types/json-schema
27
+ ```
28
+
29
+ ### 2. Import the component
30
+
31
+ `SofB2BJsonEditorComponent` is standalone — import it directly or use `SofB2BModule`:
32
+
33
+ ```typescript
34
+ import { SofB2BJsonEditorComponent } from '@softheon/armature/b2b';
35
+
36
+ // Option A — standalone component
37
+ @Component({
38
+ standalone: true,
39
+ imports: [SofB2BJsonEditorComponent],
40
+ })
41
+ export class MyComponent {}
42
+
43
+ // Option B — NgModule
44
+ import { SofB2BModule } from '@softheon/armature/b2b';
45
+
46
+ @NgModule({
47
+ imports: [SofB2BModule],
48
+ })
49
+ export class MyModule {}
50
+ ```
51
+
52
+ ### 3. Use in template
53
+
54
+ Pass a `JsonObject` (any nested JSON object) directly — no pre-processing required:
55
+
56
+ ```html
57
+ <sof-b2b-json-editor
58
+ [data]="rawData"
59
+ [schema]="jsonSchema"
60
+ [readOnly]="false"
61
+ [debounceMs]="1500"
62
+ [searchTerm]="searchTerm"
63
+ (dataChanged)="onDataChanged($event)"
64
+ (parseError)="onParseError($event)"
65
+ [emptyMessage]="'editor.data.empty' | translate"
66
+ [noResultsMessage]="'editor.data.no-results' | translate">
67
+ </sof-b2b-json-editor>
68
+ ```
69
+
70
+ ### 4. Handle changes
71
+
72
+ The `(dataChanged)` output emits the full reconstructed `JsonObject` after the debounce period:
73
+
74
+ ```typescript
75
+ import { JsonObject } from '@softheon/armature/b2b';
76
+
77
+ onDataChanged(data: JsonObject): void {
78
+ // data is the full reconstructed JSON object
79
+ this.myService.save(data);
80
+ }
81
+
82
+ onParseError(error: string): void {
83
+ // Display the error in your own snackbar/toast/etc.
84
+ this.snackbar.open(error, 'Dismiss');
85
+ }
86
+ ```
87
+
88
+ ## API Reference
89
+
90
+ ### SofB2BJsonEditorComponent inputs
91
+
92
+ | Input | Type | Default | Description |
93
+ | ------------------ | ------------ | ----------------------- | --------------------------------------------------------------------------- |
94
+ | `data` | `JsonObject` | `{}` | Raw nested JSON object. Pass a **new object reference** to trigger updates. |
95
+ | `schema` | `JsonSchema` | `undefined` | Optional JSON Schema (Draft 7+). Parsed internally into field configs. |
96
+ | `readOnly` | `boolean` | `false` | Disables editing; fields render as plaintext. |
97
+ | `debounceMs` | `number` | `1500` | Debounce delay before `dataChanged` emits. |
98
+ | `searchTerm` | `string` | `''` | Filters tree nodes (min 2 chars to activate). |
99
+ | `emptyMessage` | `string` | `'No data to display.'` | Message shown when `data` is empty. |
100
+ | `noResultsMessage` | `string` | `'No results found.'` | Message shown when search returns no matches. |
101
+
102
+ ### SofB2BJsonEditorComponent outputs
103
+
104
+ | Output | Type | Description |
105
+ | ------------- | ------------ | --------------------------------------------------------------------------------------- |
106
+ | `dataChanged` | `JsonObject` | Emits the reconstructed JSON object after debounce. Suppressed when `readOnly` is true. |
107
+ | `parseError` | `string` | Emits error message strings for parsing/validation failures. |
108
+
109
+ ### SofB2BJsonEditorComponent public methods
110
+
111
+ | Method | Description |
112
+ | ------------ | --------------------------------------------- |
113
+ | `openAll()` | Programmatically opens all top-level panels. |
114
+ | `closeAll()` | Programmatically closes all top-level panels. |
115
+
116
+ ## Models
117
+
118
+ ### JsonObject (input & output)
119
+
120
+ ```typescript
121
+ interface JsonObject {
122
+ [key: string]: JsonValue;
123
+ }
124
+ type JsonValue = string | number | boolean | null | JsonValue[] | JsonObject;
125
+ ```
126
+
127
+ ### JsonSchema (schema input)
128
+
129
+ The `[schema]` input accepts a `JsonSchema` type — an alias for `JSONSchema7` from `@types/json-schema` (Draft 7):
130
+
131
+ ```typescript
132
+ import { JsonSchema } from '@softheon/armature/b2b';
133
+
134
+ const schema: JsonSchema = {
135
+ type: 'object',
136
+ properties: {
137
+ Theme: { type: 'string', enum: ['dark', 'light'] },
138
+ MaxRetries: { type: 'integer', title: 'Max Retries' },
139
+ Enabled: { type: 'boolean' },
140
+ },
141
+ };
142
+ ```
143
+
144
+ ## Utility Functions
145
+
146
+ All utilities are importable from the entry point:
147
+
148
+ ```typescript
149
+ import {
150
+ type JsonSchema,
151
+ unflattenJson,
152
+ normalizeToEntries,
153
+ parsePath,
154
+ buildNodesFromEntries,
155
+ flattenNamespaces,
156
+ filterNamespaces,
157
+ validateDuplicateKeys,
158
+ parseJsonSchema,
159
+ } from '@softheon/armature/b2b';
160
+ ```
161
+
162
+ | Function | Description |
163
+ | -------------------------- | ------------------------------------------------------------------ |
164
+ | `unflattenJson(entries)` | Reconstructs nested JSON from `JsonEntry[]`. |
165
+ | `normalizeToEntries()` | Flattens a `JsonObject` into `JsonEntry[]` with dot/bracket paths. |
166
+ | `parsePath(key)` | Splits a dot/bracket path into segments. |
167
+ | `filterNamespaces()` | Filters a namespace tree by search term. |
168
+ | `validateDuplicateKeys()` | Detects duplicate keys in `JsonEntry[]` and returns error strings. |
169
+ | `parseJsonSchema()` | Parses a JSON Schema into a flat `Record<string, FieldConfig>`. |
170
+
171
+ ## Key Path Notation
172
+
173
+ Internally, the editor uses path notation for keys:
174
+
175
+ | Pattern | Example | Meaning |
176
+ | -------------- | ----------------------------- | ------------------------- |
177
+ | Dot notation | `BillingInformation.PlanName` | Object property access |
178
+ | Bracket index | `Invoice.Payments[0].Amount` | Array element access |
179
+ | Quoted bracket | `["Discount Amount"]` | Special characters in key |
180
+
181
+ ## Read-Only Mode
182
+
183
+ When `readOnly` is `true`:
184
+
185
+ - All scalar fields render as plaintext (no inputs)
186
+ - Toggle switches are disabled
187
+ - The debounce subscription is never created (no wasted cycles)
188
+ - `dataChanged` never emits
189
+
190
+ ```html
191
+ <sof-b2b-json-editor [data]="myData" [readOnly]="true"></sof-b2b-json-editor>
192
+ ```
193
+
194
+ ## Search Filtering
195
+
196
+ Pass a `searchTerm` to filter the tree. Filtering activates at 2+ characters and recursively prunes namespaces/nodes that don't match:
197
+
198
+ ```html
199
+ <sof-b2b-json-editor [data]="myData" [searchTerm]="userSearchInput"></sof-b2b-json-editor>
200
+ ```
201
+
202
+ ## Array Add / Remove
203
+
204
+ When a schema is provided and an array field has at least one item, the editor renders interactive add/remove controls:
205
+
206
+ - **Add button** — appears at the bottom of expanded arrays. Labeled "Add [Singular]" (e.g. "Add Payment"). Clones the first item's structure and values.
207
+ - **Remove button** — a trash icon on each array item header, visible on hover. Cannot remove the last remaining item (minimum 1).
208
+ - **Read-only mode** — add/remove buttons are hidden entirely (not disabled).
209
+ - **Empty arrays** — arrays with zero items and no schema display a grayed-out "(no schema)" label and are non-interactive.
210
+
211
+ All add/remove changes flow through the existing debounced `dataChanged` pipeline.
212
+
213
+ ## Dirty Field Detection
214
+
215
+ Scalar fields that have been edited display a blue label to indicate unsaved changes:
216
+
217
+ - The editor tracks each field's **original value** (the value when the tree was first built).
218
+ - When a field's current value differs from its original, the label turns blue (`--primary-color`).
219
+ - Resetting a field back to its original value removes the dirty indicator.
220
+ - Newly added array items are **not** marked dirty — their original value is set to the cloned value.
221
+
222
+ ## JSON Schema Support
223
+
224
+ The editor accepts a standard JSON Schema (Draft 7+) directly via its `[schema]` input and uses it to configure field types, labels, and dropdown options automatically.
225
+
226
+ ### Schema keyword mapping
227
+
228
+ | JSON Schema keyword | Editor behaviour | Notes |
229
+ | ------------------- | ----------------------- | ----------------------------------------------- |
230
+ | `type: "string"` | `<input type="text">` | |
231
+ | `type: "number"` | `<input type="number">` | |
232
+ | `type: "integer"` | `<input type="number">` | |
233
+ | `type: "boolean"` | `<mat-slide-toggle>` | |
234
+ | `enum` | `<mat-select>` | Values are converted to strings for option list |
235
+ | `$id` | Label override | Last URI segment or fragment extracted |
236
+ | `title` | Label override | Used when `$id` is absent |
237
+ | `description` | Placeholder text | |
238
+ | `properties` | _(recurse)_ | Builds dot-notation path prefix |
239
+ | `items` | _(recurse)_ | Applies element schema to array paths |
240
+
241
+ Nullable types like `["string", "null"]` are supported — the first non-null type is used.
242
+
243
+ ### Depth limit
244
+
245
+ Schema recursion stops at 20 levels (matching the tree builder's `MAX_DEPTH`) and logs a console warning.
246
+
247
+ ## Testing
248
+
249
+ ```bash
250
+ # Run B2B tests
251
+ npm run testB2B
252
+
253
+ # Or directly via ng
254
+ ng test b2b
255
+ ```