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.
@@ -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
- /** The element with all prop expressions resolved. */
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 ? [{ debugName: "resolvedElement" }] : /* istanbul ignore next */ []));
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 ? [{ debugName: "bindings" }] : /* istanbul ignore next */ []));
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 (!binding)
1294
- continue;
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 el = untracked(this.rawElement);
1334
- const binding = el?.on?.[eventName];
1335
- if (!binding)
1336
- return;
1337
- const actionBindings = Array.isArray(binding) ? binding : [binding];
1338
- for (const b of actionBindings) {
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;