@jxsuite/runtime 4.0.0 → 4.0.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/dist/runtime.js CHANGED
@@ -700,7 +700,11 @@ function reactiveReadArray(array) {
700
700
  if (raw === array)
701
701
  return raw;
702
702
  track(raw, "iterate", ARRAY_ITERATE_KEY);
703
- return isShallow(array) ? raw : raw.map(toReactive);
703
+ if (isShallow(array))
704
+ return raw;
705
+ if (!isReadonly(array))
706
+ return raw.map(toReactive);
707
+ return isReactive(array) ? raw.map((item) => toReadonly(toReactive(item))) : raw.map(toReadonly);
704
708
  }
705
709
  function shallowReadArray(arr) {
706
710
  track(arr = toRaw(arr), "iterate", ARRAY_ITERATE_KEY);
@@ -3461,16 +3465,10 @@ function sheetStateFor(doc) {
3461
3465
  var elementStyles = new WeakMap;
3462
3466
  var SCOPE_TOKEN = "\x01jx-scope\x01";
3463
3467
  function rewriteScratch(state) {
3464
- if (!state.scratch) {
3465
- return;
3466
- }
3467
3468
  state.scratch.replaceAll([...state.scratchOwners.values()].flat());
3468
3469
  }
3469
3470
  function releaseInterned(state, table, key) {
3470
3471
  const entry = table.get(key);
3471
- if (!entry) {
3472
- return;
3473
- }
3474
3472
  entry.refs -= 1;
3475
3473
  if (entry.refs <= 0) {
3476
3474
  table.delete(key);
@@ -3675,6 +3673,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3675
3673
  parentEl.append(anchor);
3676
3674
  const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef, key: keyRef } = arrayDef;
3677
3675
  const keyPointer = isRefObj(keyRef) ? keyRef.$ref : null;
3676
+ const instancePath = _instancePath;
3678
3677
  let warned = false;
3679
3678
  const warnOnce = (message) => {
3680
3679
  if (!warned) {
@@ -3762,7 +3761,7 @@ function renderMappedArrayInto(parentEl, arrayDef, state, options) {
3762
3761
  }
3763
3762
  pauseTracking();
3764
3763
  try {
3765
- reconcile(list, keys);
3764
+ underInstancePath(reexpand(instancePath), () => reconcile(list, keys));
3766
3765
  } finally {
3767
3766
  resetTracking();
3768
3767
  }
@@ -3826,6 +3825,7 @@ function resolveTagName(tagName, scope) {
3826
3825
  function renderSwitch(def, state, options) {
3827
3826
  const path = options?._path ?? [];
3828
3827
  const container = document.createElement(resolveTagName(def.tagName, state));
3828
+ const instancePath = _instancePath;
3829
3829
  if (options?.onNodeCreated) {
3830
3830
  options.onNodeCreated(container, path, def, state);
3831
3831
  }
@@ -3873,13 +3873,13 @@ function renderSwitch(def, state, options) {
3873
3873
  return;
3874
3874
  }
3875
3875
  container.replaceChildren();
3876
- scope.run(() => container.append(renderNode(doc, childScope, childOpts)));
3876
+ underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(doc, childScope, childOpts))));
3877
3877
  }).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
3878
3878
  return;
3879
3879
  }
3880
3880
  pauseTracking();
3881
3881
  try {
3882
- scope.run(() => container.append(renderNode(caseDef, state, childOpts)));
3882
+ underInstancePath(reexpand(instancePath), () => scope.run(() => container.append(renderNode(caseDef, state, childOpts))));
3883
3883
  } finally {
3884
3884
  resetTracking();
3885
3885
  }
@@ -4130,9 +4130,6 @@ async function importAndInstantiate(def, src, exportName, base) {
4130
4130
  }
4131
4131
  async function resolveClassJson(def, state, key, base) {
4132
4132
  const src = def.$src;
4133
- if (!src) {
4134
- throw new Error(`Jx: class entry '${key}' has no $src`);
4135
- }
4136
4133
  let classDef;
4137
4134
  const isBareSpecifier = !src.startsWith(".") && !src.startsWith("/") && !src.startsWith("http") && !src.startsWith("file:");
4138
4135
  if (isBareSpecifier) {
@@ -4583,6 +4580,65 @@ function injectHead(entries, _base) {
4583
4580
  document.head.append(el);
4584
4581
  }
4585
4582
  }
4583
+ var MAX_COMPONENT_NESTING = 32;
4584
+ var ROOT_INSTANCE_PATH = { expansion: 0, frames: [] };
4585
+ var _instancePath = ROOT_INSTANCE_PATH;
4586
+ function underInstancePath(path, fn) {
4587
+ const was = _instancePath;
4588
+ _instancePath = path;
4589
+ try {
4590
+ return fn();
4591
+ } finally {
4592
+ _instancePath = was;
4593
+ }
4594
+ }
4595
+ function reexpand(path) {
4596
+ return { expansion: path.frames.length, frames: path.frames };
4597
+ }
4598
+ function samePropValue(a, b) {
4599
+ if (Object.is(a, b)) {
4600
+ return true;
4601
+ }
4602
+ if (!isPlainData(a) || !isPlainData(b)) {
4603
+ return false;
4604
+ }
4605
+ try {
4606
+ return JSON.stringify(a) === JSON.stringify(b);
4607
+ } catch {
4608
+ return false;
4609
+ }
4610
+ }
4611
+ function isPlainData(value) {
4612
+ if (typeof value !== "object" || value === null) {
4613
+ return false;
4614
+ }
4615
+ const raw = toRaw(value);
4616
+ if (Array.isArray(raw)) {
4617
+ return true;
4618
+ }
4619
+ const proto = Object.getPrototypeOf(raw);
4620
+ return proto === Object.prototype || proto === null;
4621
+ }
4622
+ function sameFrame(a, b) {
4623
+ if (a.tag !== b.tag) {
4624
+ return false;
4625
+ }
4626
+ const keys = Object.keys(a.props);
4627
+ if (keys.length !== Object.keys(b.props).length) {
4628
+ return false;
4629
+ }
4630
+ return keys.every((key) => Object.hasOwn(b.props, key) && samePropValue(a.props[key], b.props[key]));
4631
+ }
4632
+ function extendInstancePath(path, frame) {
4633
+ const chain = [...path.frames.map((f) => f.tag), frame.tag].join(" → ");
4634
+ if (path.frames.slice(path.expansion).some((f) => sameFrame(f, frame))) {
4635
+ throw new Error(`Component <${frame.tag}> renders itself: ${chain}. A component cannot appear inside its own ` + `definition with the same props — the expansion would never end.`);
4636
+ }
4637
+ if (path.frames.length >= MAX_COMPONENT_NESTING) {
4638
+ throw new Error(`Component nesting exceeds ${MAX_COMPONENT_NESTING} levels: ${chain}. A component that renders itself with changing props needs a case that stops.`);
4639
+ }
4640
+ return { expansion: path.expansion, frames: [...path.frames, frame] };
4641
+ }
4586
4642
  var _definedSources = new Set;
4587
4643
  async function defineElement(source, baseUrl) {
4588
4644
  let base = baseUrl;
@@ -4625,6 +4681,8 @@ async function defineElement(source, baseUrl) {
4625
4681
  return;
4626
4682
  }
4627
4683
  this._jxInitialized = true;
4684
+ const enclosingPath = _instancePath;
4685
+ const supplied = {};
4628
4686
  const live = _elementDefs.get(tagName) ?? { base: initialBase, doc: initialDef };
4629
4687
  const def = live.doc;
4630
4688
  const defBase = live.base;
@@ -4632,6 +4690,7 @@ async function defineElement(source, baseUrl) {
4632
4690
  for (const attr of observedAttrs) {
4633
4691
  if (this.hasAttribute(attr)) {
4634
4692
  absorbAttribute(state, attr, this.getAttribute(attr));
4693
+ supplied[attr] = this.getAttribute(attr);
4635
4694
  }
4636
4695
  }
4637
4696
  const propsAttr = this.dataset.jxProps;
@@ -4644,6 +4703,7 @@ async function defineElement(source, baseUrl) {
4644
4703
  }
4645
4704
  if (key in (def.state ?? {})) {
4646
4705
  state[key] = val;
4706
+ supplied[key] = val;
4647
4707
  }
4648
4708
  }
4649
4709
  } catch {}
@@ -4658,6 +4718,7 @@ async function defineElement(source, baseUrl) {
4658
4718
  }
4659
4719
  if (key in (def.state ?? {})) {
4660
4720
  state[key] = this.getAttribute(name);
4721
+ supplied[key] = this.getAttribute(name);
4661
4722
  this.removeAttribute(name);
4662
4723
  }
4663
4724
  }
@@ -4667,7 +4728,25 @@ async function defineElement(source, baseUrl) {
4667
4728
  }
4668
4729
  if (key in this && this[key] !== undefined && instanceSupplies(this, key)) {
4669
4730
  state[key] = this[key];
4731
+ supplied[key] = this[key];
4732
+ }
4733
+ }
4734
+ let ownPath;
4735
+ try {
4736
+ ownPath = extendInstancePath(enclosingPath, { props: supplied, tag: tagName });
4737
+ } catch (error) {
4738
+ this.replaceChildren();
4739
+ if (!this.isConnected) {
4740
+ return;
4670
4741
  }
4742
+ console.error(`Jx: <${tagName}> was not rendered:`, error);
4743
+ this.dispatchEvent(new ErrorEvent("jx-error", {
4744
+ bubbles: true,
4745
+ composed: true,
4746
+ error,
4747
+ message: error instanceof Error ? error.message : String(error)
4748
+ }));
4749
+ return;
4671
4750
  }
4672
4751
  for (const key of Object.keys(def.state ?? {})) {
4673
4752
  if (isPrivateStateKey(key)) {
@@ -4698,9 +4777,11 @@ async function defineElement(source, baseUrl) {
4698
4777
  const wasInside = _canvasInsideStampedHost;
4699
4778
  _canvasInsideStampedHost ||= this.dataset.jxPath !== undefined;
4700
4779
  try {
4701
- for (const childDef of children) {
4702
- this.append(renderNode(childDef, state));
4703
- }
4780
+ underInstancePath(ownPath, () => {
4781
+ for (const childDef of children) {
4782
+ this.append(renderNode(childDef, state));
4783
+ }
4784
+ });
4704
4785
  } finally {
4705
4786
  _canvasInsideStampedHost = wasInside;
4706
4787
  }
@@ -4801,6 +4882,7 @@ export {
4801
4882
  COLOR_SCHEME_ATTR,
4802
4883
  COLOR_SCHEME_STORAGE_KEY,
4803
4884
  Jx,
4885
+ MAX_COMPONENT_NESTING,
4804
4886
  RESERVED_KEYS,
4805
4887
  SUPPORTED_SCHEMA_VERSION,
4806
4888
  _resetPrivatePropWarnings,
@@ -4859,5 +4941,5 @@ export {
4859
4941
  transposeCanvasUnits
4860
4942
  };
4861
4943
 
4862
- //# debugId=A89AF23A7F8742C664756E2164756E21
4944
+ //# debugId=AA34AE79F7363B3164756E2164756E21
4863
4945
  //# sourceMappingURL=runtime.js.map