@odoo/owl 3.0.0-alpha.35 → 3.0.0-alpha.37

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/owl.iife.js CHANGED
@@ -823,7 +823,7 @@ var owl = (() => {
823
823
  ${issueStrings}`);
824
824
  }
825
825
  }
826
- function createContext(issues, value, path, parent) {
826
+ function createContext(issues, value, path, parent, depthOffset = 1) {
827
827
  return {
828
828
  issueDepth: 0,
829
829
  path,
@@ -844,11 +844,11 @@ ${issueStrings}`);
844
844
  validate(type) {
845
845
  type(this);
846
846
  if (!this.isValid && parent) {
847
- parent.issueDepth = this.issueDepth + 1;
847
+ parent.issueDepth = this.issueDepth + depthOffset;
848
848
  }
849
849
  },
850
850
  withIssues(issues2) {
851
- return createContext(issues2, this.value, this.path, this);
851
+ return createContext(issues2, this.value, this.path, this, 0);
852
852
  },
853
853
  withKey(key) {
854
854
  return createContext(issues, this.value[key], this.path.concat(key), this);
@@ -868,21 +868,7 @@ ${issueStrings}`);
868
868
  function getDefault(type) {
869
869
  return typeof type === "function" ? type[defaultSymbol] : void 0;
870
870
  }
871
- function hasDefaultValue(type) {
872
- return typeof type === "function" && defaultSymbol in type;
873
- }
874
- function withDefault(type, value) {
875
- const validate = function validateWithDefault(context) {
876
- if (context.value === void 0) {
877
- return;
878
- }
879
- context.validate(type);
880
- };
881
- validate[defaultSymbol] = typeof value === "function" ? value : () => value;
882
- validate[innerTypeSymbol] = type;
883
- return validate;
884
- }
885
- function makeOptional(type) {
871
+ function makeOptional(type, value) {
886
872
  const validate = function validateOptional(context) {
887
873
  if (context.value === void 0) {
888
874
  return;
@@ -891,14 +877,16 @@ ${issueStrings}`);
891
877
  };
892
878
  validate[optionalSymbol] = true;
893
879
  validate[innerTypeSymbol] = type;
880
+ if (value !== void 0) {
881
+ validate[defaultSymbol] = typeof value === "function" ? value : () => value;
882
+ }
894
883
  return validate;
895
884
  }
896
885
  function isOptionalType(type) {
897
886
  return typeof type === "function" && optionalSymbol in type;
898
887
  }
899
888
  function makeType(validate) {
900
- validate.default = (value) => withDefault(validate, value);
901
- validate.optional = () => makeOptional(validate);
889
+ validate.optional = (value) => makeOptional(validate, value);
902
890
  return validate;
903
891
  }
904
892
  function applyDefaults(value, type) {
@@ -1068,7 +1056,7 @@ ${issueStrings}`);
1068
1056
  const missingKeys = [];
1069
1057
  for (const key of keys) {
1070
1058
  if (context.value[key] === void 0) {
1071
- if (!isOptionalType(shape[key]) && !hasDefaultValue(shape[key])) {
1059
+ if (!isOptionalType(shape[key])) {
1072
1060
  missingKeys.push(key);
1073
1061
  }
1074
1062
  continue;
@@ -1080,8 +1068,7 @@ ${issueStrings}`);
1080
1068
  if (missingKeys.length) {
1081
1069
  context.addIssue({
1082
1070
  message: "object value has missing keys",
1083
- missingKeys,
1084
- expectedKeys: keys
1071
+ missingKeys
1085
1072
  });
1086
1073
  }
1087
1074
  if (isStrict) {
@@ -1094,8 +1081,7 @@ ${issueStrings}`);
1094
1081
  if (unknownKeys.length) {
1095
1082
  context.addIssue({
1096
1083
  message: "object value has unknown keys",
1097
- unknownKeys,
1098
- expectedKeys: keys
1084
+ unknownKeys
1099
1085
  });
1100
1086
  }
1101
1087
  }
@@ -1543,7 +1529,7 @@ ${issueStrings}`);
1543
1529
  }
1544
1530
 
1545
1531
  // ../owl-runtime/dist/owl-runtime.es.js
1546
- var version = "3.0.0-alpha.35";
1532
+ var version = "3.0.0-alpha.37";
1547
1533
  var fibersInError = /* @__PURE__ */ new WeakMap();
1548
1534
  var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
1549
1535
  function invokeErrorHandlers(node, error, finalize, markFibers) {
@@ -3439,6 +3425,11 @@ ${issueStrings}`);
3439
3425
  willPatch = [];
3440
3426
  patched = [];
3441
3427
  signalComputation;
3428
+ // t-ref signals bound to an element hosted by this component, mapped to their
3429
+ // atom (so the element can be read without subscribing). Swept by isConnected
3430
+ // after each patch and after this subtree is removed, to unset a ref pointing
3431
+ // at a bulk-removed element (slot host, enclosing t-if) — see sweepRefs.
3432
+ trackedRefs = null;
3442
3433
  constructor(C, props2, app, parent, parentKey) {
3443
3434
  super(app);
3444
3435
  this.parent = parent;
@@ -3547,9 +3538,15 @@ ${issueStrings}`);
3547
3538
  }
3548
3539
  destroy() {
3549
3540
  let shouldRemove = this.status === STATUS.MOUNTED;
3550
- this._destroy();
3541
+ removalDepth++;
3542
+ try {
3543
+ this._destroy();
3544
+ } finally {
3545
+ removalDepth--;
3546
+ }
3551
3547
  if (shouldRemove) {
3552
3548
  this.bdom.remove();
3549
+ sweepRemovedRefs();
3553
3550
  }
3554
3551
  }
3555
3552
  _destroy() {
@@ -3559,12 +3556,42 @@ ${issueStrings}`);
3559
3556
  cb.call(component);
3560
3557
  }
3561
3558
  }
3559
+ if (removalDepth && this.trackedRefs) {
3560
+ (removed ||= []).push(this);
3561
+ }
3562
3562
  for (let childKey in this.children) {
3563
3563
  this.children[childKey]._destroy();
3564
3564
  }
3565
3565
  this.finalize((e) => handleError({ error: e, node: this }));
3566
3566
  disposeComputation(this.signalComputation);
3567
3567
  }
3568
+ /**
3569
+ * Unset any tracked t-ref whose element is no longer in the document, and stop
3570
+ * tracking it (createRef re-registers it on the next render if the element
3571
+ * comes back). `isConnected` is the discriminator: a ref the block's own
3572
+ * remove() failed to clear (bulk removal) points at a detached element and is
3573
+ * cleared, while a ref a surviving sibling just took over (t-if/t-else with a
3574
+ * shared signal) points at a still-connected element and is left alone.
3575
+ *
3576
+ * Called after this component's dom settles: at the tail of `_patch` (before
3577
+ * user `onPatched`), so an element removed in place is caught, and — for the
3578
+ * nodes collected during `_destroy` — after a removed subtree is detached.
3579
+ */
3580
+ sweepRefs() {
3581
+ const refs = this.trackedRefs;
3582
+ if (!refs) {
3583
+ return;
3584
+ }
3585
+ for (const [ref2, atom] of refs) {
3586
+ const el = atom.value;
3587
+ if (!el) {
3588
+ refs.delete(ref2);
3589
+ } else if (!el.isConnected) {
3590
+ ref2.set(null);
3591
+ refs.delete(ref2);
3592
+ }
3593
+ }
3594
+ }
3568
3595
  /**
3569
3596
  * Finds a child that has dom that is not yet updated, and update it. This
3570
3597
  * method is meant to be used only in the context of repatching the dom after
@@ -3580,7 +3607,14 @@ ${issueStrings}`);
3580
3607
  child.updateDom();
3581
3608
  }
3582
3609
  } else {
3583
- this.bdom.patch(this.fiber.bdom, false);
3610
+ removalDepth++;
3611
+ try {
3612
+ this.bdom.patch(this.fiber.bdom, false);
3613
+ } finally {
3614
+ removalDepth--;
3615
+ }
3616
+ this.sweepRefs();
3617
+ sweepRemovedRefs();
3584
3618
  this.fiber.appliedToDom = true;
3585
3619
  this.fiber = null;
3586
3620
  }
@@ -3607,6 +3641,14 @@ ${issueStrings}`);
3607
3641
  moveBeforeVNode(other, afterNode) {
3608
3642
  this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
3609
3643
  }
3644
+ /**
3645
+ * Register a t-ref signal bound to an element this component hosts, so its
3646
+ * lifecycle can clear it (see sweepRefs / _destroy). Idempotent — re-tracking
3647
+ * the same signal on each render just refreshes its atom.
3648
+ */
3649
+ trackRef(ref2, atom) {
3650
+ (this.trackedRefs ||= /* @__PURE__ */ new Map()).set(ref2, atom);
3651
+ }
3610
3652
  patch() {
3611
3653
  if (this.fiber && this.fiber.parent) {
3612
3654
  this._patch();
@@ -3620,7 +3662,14 @@ ${issueStrings}`);
3620
3662
  }
3621
3663
  const fiber = this.fiber;
3622
3664
  this.children = fiber.childrenMap;
3623
- this.bdom.patch(fiber.bdom, hasChildren);
3665
+ removalDepth++;
3666
+ try {
3667
+ this.bdom.patch(fiber.bdom, hasChildren);
3668
+ } finally {
3669
+ removalDepth--;
3670
+ }
3671
+ this.sweepRefs();
3672
+ sweepRemovedRefs();
3624
3673
  fiber.appliedToDom = true;
3625
3674
  this.fiber = null;
3626
3675
  }
@@ -3631,6 +3680,17 @@ ${issueStrings}`);
3631
3680
  this.bdom.remove();
3632
3681
  }
3633
3682
  };
3683
+ var removalDepth = 0;
3684
+ var removed = null;
3685
+ function sweepRemovedRefs() {
3686
+ if (removalDepth === 0 && removed) {
3687
+ const nodes = removed;
3688
+ removed = null;
3689
+ for (let i = 0; i < nodes.length; i++) {
3690
+ nodes[i].sweepRefs();
3691
+ }
3692
+ }
3693
+ }
3634
3694
  function getComponentScope() {
3635
3695
  const scope = useScope();
3636
3696
  if (!(scope instanceof ComponentNode)) {
@@ -3734,7 +3794,7 @@ ${issueStrings}`);
3734
3794
  }
3735
3795
  };
3736
3796
  var ObjectCreate = Object.create;
3737
- function withDefault2(value, defaultValue) {
3797
+ function withDefault(value, defaultValue) {
3738
3798
  return value === void 0 || value === null || value === false ? defaultValue : value;
3739
3799
  }
3740
3800
  function callSlot(ctx, parent, key, name, dynamic, extra, defaultContent) {
@@ -3833,7 +3893,7 @@ ${issueStrings}`);
3833
3893
  }
3834
3894
  return toggler(safeKey, block);
3835
3895
  }
3836
- function createRef(ref2) {
3896
+ function createRef(ref2, node) {
3837
3897
  if (!ref2) {
3838
3898
  throw new OwlError(`Ref is undefined or null`);
3839
3899
  }
@@ -3848,6 +3908,9 @@ ${issueStrings}`);
3848
3908
  remove2 = atom ? (prevEl) => {
3849
3909
  if (atom.value === prevEl) ref2.set(null);
3850
3910
  } : () => ref2.set(null);
3911
+ if (atom) {
3912
+ node.trackRef(ref2, atom);
3913
+ }
3851
3914
  } else {
3852
3915
  throw new OwlError(
3853
3916
  `Ref should implement either a 'set' function or 'add' and 'delete' functions`
@@ -4020,7 +4083,7 @@ ${issueStrings}`);
4020
4083
  return toggler(subTemplate, template.call(owner, ctx, parent, key + subTemplate));
4021
4084
  }
4022
4085
  var helpers = {
4023
- withDefault: withDefault2,
4086
+ withDefault,
4024
4087
  zero: /* @__PURE__ */ Symbol("zero"),
4025
4088
  callSlot,
4026
4089
  withKey,
@@ -4482,7 +4545,7 @@ ${issueStrings}`);
4482
4545
  <t t-call-slot="default"/>
4483
4546
  </t>
4484
4547
  `;
4485
- props = props({ error: types2.signal().default(() => signal(null)) });
4548
+ props = props({ error: types2.signal().optional(() => signal(null)) });
4486
4549
  setup() {
4487
4550
  onError((e) => this.props.error.set(e));
4488
4551
  }
@@ -4599,8 +4662,8 @@ ${issueStrings}`);
4599
4662
  };
4600
4663
  var __info__ = {
4601
4664
  version: App.version,
4602
- date: "2026-06-11T09:51:14.980Z",
4603
- hash: "739fc964",
4665
+ date: "2026-06-19T13:15:04.793Z",
4666
+ hash: "18550141",
4604
4667
  url: "https://github.com/odoo/owl"
4605
4668
  };
4606
4669
 
@@ -6131,7 +6194,7 @@ ${code}`;
6131
6194
  if (ast.ref) {
6132
6195
  const refExpr = compileExpr(ast.ref);
6133
6196
  this.helpers.add("createRef");
6134
- const setRefStr = `createRef(${refExpr})`;
6197
+ const setRefStr = `createRef(${refExpr}, node)`;
6135
6198
  const idx = block.insertData(setRefStr, "ref");
6136
6199
  attrs["block-ref"] = String(idx);
6137
6200
  }