ngx-json-render 0.4.0 → 0.5.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 +47 -1
- package/fesm2022/ngx-json-render-testing.mjs +231 -55
- package/fesm2022/ngx-json-render-testing.mjs.map +1 -1
- package/fesm2022/ngx-json-render.mjs +67 -24
- package/fesm2022/ngx-json-render.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ngx-json-render-testing.d.ts +110 -17
- package/types/ngx-json-render.d.ts +22 -1
|
@@ -1091,6 +1091,32 @@ function repeatsItself(path) {
|
|
|
1091
1091
|
}
|
|
1092
1092
|
return false;
|
|
1093
1093
|
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Whether two objects hold the same values under the same keys.
|
|
1096
|
+
*
|
|
1097
|
+
* `objectsByIdentity` decides what the same object or array reference means.
|
|
1098
|
+
* The internal store copies every path it writes and never touches a snapshot
|
|
1099
|
+
* it has handed out, so there the same reference is the same content. An
|
|
1100
|
+
* external store may write into its snapshot in place, so there only
|
|
1101
|
+
* primitives can be trusted to compare equal, and any object value counts as
|
|
1102
|
+
* changed.
|
|
1103
|
+
*/
|
|
1104
|
+
function sameValues(a, b, objectsByIdentity) {
|
|
1105
|
+
const keys = Object.keys(a);
|
|
1106
|
+
if (keys.length !== Object.keys(b).length)
|
|
1107
|
+
return false;
|
|
1108
|
+
for (const key of keys) {
|
|
1109
|
+
if (!Object.hasOwn(b, key))
|
|
1110
|
+
return false;
|
|
1111
|
+
const value = a[key];
|
|
1112
|
+
if (!Object.is(value, b[key]))
|
|
1113
|
+
return false;
|
|
1114
|
+
if (!objectsByIdentity && typeof value === 'object' && value !== null) {
|
|
1115
|
+
return false;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
return true;
|
|
1119
|
+
}
|
|
1094
1120
|
/** The chain from the root down to `path`, as a line a human can follow. */
|
|
1095
1121
|
function describePath(path) {
|
|
1096
1122
|
const keys = [];
|
|
@@ -1138,7 +1164,22 @@ class JrElement {
|
|
|
1138
1164
|
return true;
|
|
1139
1165
|
return evaluateVisibility(el.visible, this.resolutionCtx());
|
|
1140
1166
|
}, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
1141
|
-
/**
|
|
1167
|
+
/**
|
|
1168
|
+
* The element with all prop expressions resolved.
|
|
1169
|
+
*
|
|
1170
|
+
* Resolving builds a new props object on every state write, whatever the
|
|
1171
|
+
* write touched. Handing that on as a change would re-run every catalog
|
|
1172
|
+
* template in the tree for one keystroke, so a result that holds the same
|
|
1173
|
+
* values as the last one counts as unchanged and keeps the old object.
|
|
1174
|
+
*
|
|
1175
|
+
* Two-way bound elements are the exception, and keep treating every
|
|
1176
|
+
* resolution as a change. Their component writes the user's input into the
|
|
1177
|
+
* DOM before it reaches state, so the DOM can differ from a prop whose
|
|
1178
|
+
* value never did: typing and a `clearStatePath` in the same turn take
|
|
1179
|
+
* the prop from '' through 'milk' back to '' with nobody reading 'milk'.
|
|
1180
|
+
* The README tells catalog authors to sync such inputs with an effect on
|
|
1181
|
+
* props, and that effect only gets to put the DOM right if it runs.
|
|
1182
|
+
*/
|
|
1142
1183
|
resolvedElement = computed(() => {
|
|
1143
1184
|
const el = this.rawElement();
|
|
1144
1185
|
if (!el)
|
|
@@ -1147,14 +1188,24 @@ class JrElement {
|
|
|
1147
1188
|
...el,
|
|
1148
1189
|
props: resolveElementProps(el.props ?? {}, this.resolutionCtx()),
|
|
1149
1190
|
};
|
|
1150
|
-
}, ...(ngDevMode ?
|
|
1191
|
+
}, { ...(ngDevMode ? { debugName: "resolvedElement" } : /* istanbul ignore next */ {}), equal: (a, b) => {
|
|
1192
|
+
if (a === b)
|
|
1193
|
+
return true;
|
|
1194
|
+
if (!a || !b || untracked(this.bindings))
|
|
1195
|
+
return false;
|
|
1196
|
+
const { props: aProps, ...aRest } = a;
|
|
1197
|
+
const { props: bProps, ...bRest } = b;
|
|
1198
|
+
// Everything but props is the spec element itself, never state.
|
|
1199
|
+
return (sameValues(aRest, bRest, true) &&
|
|
1200
|
+
sameValues(aProps, bProps, !untracked(this.root.store)));
|
|
1201
|
+
} });
|
|
1151
1202
|
/** Two-way binding paths ($bindState / $bindItem) by prop name. */
|
|
1152
1203
|
bindings = computed(() => {
|
|
1153
1204
|
const el = this.rawElement();
|
|
1154
1205
|
return el
|
|
1155
1206
|
? resolveBindings(el.props ?? {}, this.resolutionCtx())
|
|
1156
1207
|
: undefined;
|
|
1157
|
-
}, ...(ngDevMode ?
|
|
1208
|
+
}, { ...(ngDevMode ? { debugName: "bindings" } : /* istanbul ignore next */ {}), equal: (a, b) => a === b || (!!a && !!b && sameValues(a, b, true)) });
|
|
1158
1209
|
entry = computed(() => {
|
|
1159
1210
|
const el = this.rawElement();
|
|
1160
1211
|
return el ? this.root.resolveEntry(el.type) : undefined;
|
|
@@ -1290,21 +1341,8 @@ class JrElement {
|
|
|
1290
1341
|
if (!changedPaths.has(path))
|
|
1291
1342
|
continue;
|
|
1292
1343
|
const binding = watchConfig[path];
|
|
1293
|
-
if (
|
|
1294
|
-
|
|
1295
|
-
const bindings = Array.isArray(binding) ? binding : [binding];
|
|
1296
|
-
for (const b of bindings) {
|
|
1297
|
-
if (!b.params) {
|
|
1298
|
-
await this.actions.execute(b);
|
|
1299
|
-
continue;
|
|
1300
|
-
}
|
|
1301
|
-
const liveCtx = this.liveResolutionCtx();
|
|
1302
|
-
const resolved = {};
|
|
1303
|
-
for (const [key, val] of Object.entries(b.params)) {
|
|
1304
|
-
resolved[key] = resolveActionParam(val, liveCtx);
|
|
1305
|
-
}
|
|
1306
|
-
await this.actions.execute({ ...b, params: resolved });
|
|
1307
|
-
}
|
|
1344
|
+
if (binding)
|
|
1345
|
+
await this.dispatch(binding);
|
|
1308
1346
|
}
|
|
1309
1347
|
})().catch(reportActionError);
|
|
1310
1348
|
});
|
|
@@ -1330,12 +1368,17 @@ class JrElement {
|
|
|
1330
1368
|
this.emitEvent(eventName).catch(reportActionError);
|
|
1331
1369
|
}
|
|
1332
1370
|
async emitEvent(eventName) {
|
|
1333
|
-
const
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1371
|
+
const binding = untracked(this.rawElement)?.on?.[eventName];
|
|
1372
|
+
if (binding)
|
|
1373
|
+
await this.dispatch(binding);
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Run an `on` or `watch` binding's actions in order. Params are resolved
|
|
1377
|
+
* per action, just before it runs, so a `$state` read in a later action of
|
|
1378
|
+
* the chain sees what an earlier one wrote.
|
|
1379
|
+
*/
|
|
1380
|
+
async dispatch(binding) {
|
|
1381
|
+
for (const b of Array.isArray(binding) ? binding : [binding]) {
|
|
1339
1382
|
if (!b.params) {
|
|
1340
1383
|
await this.actions.execute(b);
|
|
1341
1384
|
continue;
|