@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.cjs.js +99 -36
- package/dist/owl.es.js +99 -36
- package/dist/owl.iife.js +99 -36
- package/dist/owl.iife.min.js +8 -8
- package/dist/types/owl.d.ts +72 -46
- package/package.json +4 -4
package/dist/owl.cjs.js
CHANGED
|
@@ -823,7 +823,7 @@ function assertType(value, validation, errorMessage = "Value does not match the
|
|
|
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 @@ function createContext(issues, value, path, parent) {
|
|
|
844
844
|
validate(type) {
|
|
845
845
|
type(this);
|
|
846
846
|
if (!this.isValid && parent) {
|
|
847
|
-
parent.issueDepth = this.issueDepth +
|
|
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 @@ var optionalSymbol = /* @__PURE__ */ Symbol("optional");
|
|
|
868
868
|
function getDefault(type) {
|
|
869
869
|
return typeof type === "function" ? type[defaultSymbol] : void 0;
|
|
870
870
|
}
|
|
871
|
-
function
|
|
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 @@ function makeOptional(type) {
|
|
|
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.
|
|
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 @@ function validateObject(context, schema, isStrict) {
|
|
|
1068
1056
|
const missingKeys = [];
|
|
1069
1057
|
for (const key of keys) {
|
|
1070
1058
|
if (context.value[key] === void 0) {
|
|
1071
|
-
if (!isOptionalType(shape[key])
|
|
1059
|
+
if (!isOptionalType(shape[key])) {
|
|
1072
1060
|
missingKeys.push(key);
|
|
1073
1061
|
}
|
|
1074
1062
|
continue;
|
|
@@ -1080,8 +1068,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
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 @@ function validateObject(context, schema, isStrict) {
|
|
|
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 @@ function markup(valueOrStrings, ...placeholders) {
|
|
|
1543
1529
|
}
|
|
1544
1530
|
|
|
1545
1531
|
// ../owl-runtime/dist/owl-runtime.es.js
|
|
1546
|
-
var version = "3.0.0-alpha.
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
3547
3538
|
}
|
|
3548
3539
|
destroy() {
|
|
3549
3540
|
let shouldRemove = this.status === STATUS.MOUNTED;
|
|
3550
|
-
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
3580
3607
|
child.updateDom();
|
|
3581
3608
|
}
|
|
3582
3609
|
} else {
|
|
3583
|
-
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
3620
3662
|
}
|
|
3621
3663
|
const fiber = this.fiber;
|
|
3622
3664
|
this.children = fiber.childrenMap;
|
|
3623
|
-
|
|
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 @@ var ComponentNode = class extends Scope {
|
|
|
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 @@ var Component = class {
|
|
|
3734
3794
|
}
|
|
3735
3795
|
};
|
|
3736
3796
|
var ObjectCreate = Object.create;
|
|
3737
|
-
function
|
|
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 @@ function safeOutput(value, defaultValue) {
|
|
|
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 @@ function createRef(ref2) {
|
|
|
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 @@ function callTemplate(subTemplate, owner, app, ctx, parent, key) {
|
|
|
4020
4083
|
return toggler(subTemplate, template.call(owner, ctx, parent, key + subTemplate));
|
|
4021
4084
|
}
|
|
4022
4085
|
var helpers = {
|
|
4023
|
-
withDefault
|
|
4086
|
+
withDefault,
|
|
4024
4087
|
zero: /* @__PURE__ */ Symbol("zero"),
|
|
4025
4088
|
callSlot,
|
|
4026
4089
|
withKey,
|
|
@@ -4482,7 +4545,7 @@ var ErrorBoundary = class extends Component {
|
|
|
4482
4545
|
<t t-call-slot="default"/>
|
|
4483
4546
|
</t>
|
|
4484
4547
|
`;
|
|
4485
|
-
props = props({ error: types2.signal().
|
|
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 @@ var blockDom = {
|
|
|
4599
4662
|
};
|
|
4600
4663
|
var __info__ = {
|
|
4601
4664
|
version: App.version,
|
|
4602
|
-
date: "2026-06-
|
|
4603
|
-
hash: "
|
|
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
|
}
|
package/dist/owl.es.js
CHANGED
|
@@ -745,7 +745,7 @@ function assertType(value, validation, errorMessage = "Value does not match the
|
|
|
745
745
|
${issueStrings}`);
|
|
746
746
|
}
|
|
747
747
|
}
|
|
748
|
-
function createContext(issues, value, path, parent) {
|
|
748
|
+
function createContext(issues, value, path, parent, depthOffset = 1) {
|
|
749
749
|
return {
|
|
750
750
|
issueDepth: 0,
|
|
751
751
|
path,
|
|
@@ -766,11 +766,11 @@ function createContext(issues, value, path, parent) {
|
|
|
766
766
|
validate(type) {
|
|
767
767
|
type(this);
|
|
768
768
|
if (!this.isValid && parent) {
|
|
769
|
-
parent.issueDepth = this.issueDepth +
|
|
769
|
+
parent.issueDepth = this.issueDepth + depthOffset;
|
|
770
770
|
}
|
|
771
771
|
},
|
|
772
772
|
withIssues(issues2) {
|
|
773
|
-
return createContext(issues2, this.value, this.path, this);
|
|
773
|
+
return createContext(issues2, this.value, this.path, this, 0);
|
|
774
774
|
},
|
|
775
775
|
withKey(key) {
|
|
776
776
|
return createContext(issues, this.value[key], this.path.concat(key), this);
|
|
@@ -790,21 +790,7 @@ var optionalSymbol = /* @__PURE__ */ Symbol("optional");
|
|
|
790
790
|
function getDefault(type) {
|
|
791
791
|
return typeof type === "function" ? type[defaultSymbol] : void 0;
|
|
792
792
|
}
|
|
793
|
-
function
|
|
794
|
-
return typeof type === "function" && defaultSymbol in type;
|
|
795
|
-
}
|
|
796
|
-
function withDefault(type, value) {
|
|
797
|
-
const validate = function validateWithDefault(context) {
|
|
798
|
-
if (context.value === void 0) {
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
context.validate(type);
|
|
802
|
-
};
|
|
803
|
-
validate[defaultSymbol] = typeof value === "function" ? value : () => value;
|
|
804
|
-
validate[innerTypeSymbol] = type;
|
|
805
|
-
return validate;
|
|
806
|
-
}
|
|
807
|
-
function makeOptional(type) {
|
|
793
|
+
function makeOptional(type, value) {
|
|
808
794
|
const validate = function validateOptional(context) {
|
|
809
795
|
if (context.value === void 0) {
|
|
810
796
|
return;
|
|
@@ -813,14 +799,16 @@ function makeOptional(type) {
|
|
|
813
799
|
};
|
|
814
800
|
validate[optionalSymbol] = true;
|
|
815
801
|
validate[innerTypeSymbol] = type;
|
|
802
|
+
if (value !== void 0) {
|
|
803
|
+
validate[defaultSymbol] = typeof value === "function" ? value : () => value;
|
|
804
|
+
}
|
|
816
805
|
return validate;
|
|
817
806
|
}
|
|
818
807
|
function isOptionalType(type) {
|
|
819
808
|
return typeof type === "function" && optionalSymbol in type;
|
|
820
809
|
}
|
|
821
810
|
function makeType(validate) {
|
|
822
|
-
validate.
|
|
823
|
-
validate.optional = () => makeOptional(validate);
|
|
811
|
+
validate.optional = (value) => makeOptional(validate, value);
|
|
824
812
|
return validate;
|
|
825
813
|
}
|
|
826
814
|
function applyDefaults(value, type) {
|
|
@@ -990,7 +978,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
990
978
|
const missingKeys = [];
|
|
991
979
|
for (const key of keys) {
|
|
992
980
|
if (context.value[key] === void 0) {
|
|
993
|
-
if (!isOptionalType(shape[key])
|
|
981
|
+
if (!isOptionalType(shape[key])) {
|
|
994
982
|
missingKeys.push(key);
|
|
995
983
|
}
|
|
996
984
|
continue;
|
|
@@ -1002,8 +990,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
1002
990
|
if (missingKeys.length) {
|
|
1003
991
|
context.addIssue({
|
|
1004
992
|
message: "object value has missing keys",
|
|
1005
|
-
missingKeys
|
|
1006
|
-
expectedKeys: keys
|
|
993
|
+
missingKeys
|
|
1007
994
|
});
|
|
1008
995
|
}
|
|
1009
996
|
if (isStrict) {
|
|
@@ -1016,8 +1003,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
1016
1003
|
if (unknownKeys.length) {
|
|
1017
1004
|
context.addIssue({
|
|
1018
1005
|
message: "object value has unknown keys",
|
|
1019
|
-
unknownKeys
|
|
1020
|
-
expectedKeys: keys
|
|
1006
|
+
unknownKeys
|
|
1021
1007
|
});
|
|
1022
1008
|
}
|
|
1023
1009
|
}
|
|
@@ -1465,7 +1451,7 @@ function markup(valueOrStrings, ...placeholders) {
|
|
|
1465
1451
|
}
|
|
1466
1452
|
|
|
1467
1453
|
// ../owl-runtime/dist/owl-runtime.es.js
|
|
1468
|
-
var version = "3.0.0-alpha.
|
|
1454
|
+
var version = "3.0.0-alpha.37";
|
|
1469
1455
|
var fibersInError = /* @__PURE__ */ new WeakMap();
|
|
1470
1456
|
var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
|
|
1471
1457
|
function invokeErrorHandlers(node, error, finalize, markFibers) {
|
|
@@ -3361,6 +3347,11 @@ var ComponentNode = class extends Scope {
|
|
|
3361
3347
|
willPatch = [];
|
|
3362
3348
|
patched = [];
|
|
3363
3349
|
signalComputation;
|
|
3350
|
+
// t-ref signals bound to an element hosted by this component, mapped to their
|
|
3351
|
+
// atom (so the element can be read without subscribing). Swept by isConnected
|
|
3352
|
+
// after each patch and after this subtree is removed, to unset a ref pointing
|
|
3353
|
+
// at a bulk-removed element (slot host, enclosing t-if) — see sweepRefs.
|
|
3354
|
+
trackedRefs = null;
|
|
3364
3355
|
constructor(C, props2, app, parent, parentKey) {
|
|
3365
3356
|
super(app);
|
|
3366
3357
|
this.parent = parent;
|
|
@@ -3469,9 +3460,15 @@ var ComponentNode = class extends Scope {
|
|
|
3469
3460
|
}
|
|
3470
3461
|
destroy() {
|
|
3471
3462
|
let shouldRemove = this.status === STATUS.MOUNTED;
|
|
3472
|
-
|
|
3463
|
+
removalDepth++;
|
|
3464
|
+
try {
|
|
3465
|
+
this._destroy();
|
|
3466
|
+
} finally {
|
|
3467
|
+
removalDepth--;
|
|
3468
|
+
}
|
|
3473
3469
|
if (shouldRemove) {
|
|
3474
3470
|
this.bdom.remove();
|
|
3471
|
+
sweepRemovedRefs();
|
|
3475
3472
|
}
|
|
3476
3473
|
}
|
|
3477
3474
|
_destroy() {
|
|
@@ -3481,12 +3478,42 @@ var ComponentNode = class extends Scope {
|
|
|
3481
3478
|
cb.call(component);
|
|
3482
3479
|
}
|
|
3483
3480
|
}
|
|
3481
|
+
if (removalDepth && this.trackedRefs) {
|
|
3482
|
+
(removed ||= []).push(this);
|
|
3483
|
+
}
|
|
3484
3484
|
for (let childKey in this.children) {
|
|
3485
3485
|
this.children[childKey]._destroy();
|
|
3486
3486
|
}
|
|
3487
3487
|
this.finalize((e) => handleError({ error: e, node: this }));
|
|
3488
3488
|
disposeComputation(this.signalComputation);
|
|
3489
3489
|
}
|
|
3490
|
+
/**
|
|
3491
|
+
* Unset any tracked t-ref whose element is no longer in the document, and stop
|
|
3492
|
+
* tracking it (createRef re-registers it on the next render if the element
|
|
3493
|
+
* comes back). `isConnected` is the discriminator: a ref the block's own
|
|
3494
|
+
* remove() failed to clear (bulk removal) points at a detached element and is
|
|
3495
|
+
* cleared, while a ref a surviving sibling just took over (t-if/t-else with a
|
|
3496
|
+
* shared signal) points at a still-connected element and is left alone.
|
|
3497
|
+
*
|
|
3498
|
+
* Called after this component's dom settles: at the tail of `_patch` (before
|
|
3499
|
+
* user `onPatched`), so an element removed in place is caught, and — for the
|
|
3500
|
+
* nodes collected during `_destroy` — after a removed subtree is detached.
|
|
3501
|
+
*/
|
|
3502
|
+
sweepRefs() {
|
|
3503
|
+
const refs = this.trackedRefs;
|
|
3504
|
+
if (!refs) {
|
|
3505
|
+
return;
|
|
3506
|
+
}
|
|
3507
|
+
for (const [ref2, atom] of refs) {
|
|
3508
|
+
const el = atom.value;
|
|
3509
|
+
if (!el) {
|
|
3510
|
+
refs.delete(ref2);
|
|
3511
|
+
} else if (!el.isConnected) {
|
|
3512
|
+
ref2.set(null);
|
|
3513
|
+
refs.delete(ref2);
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3490
3517
|
/**
|
|
3491
3518
|
* Finds a child that has dom that is not yet updated, and update it. This
|
|
3492
3519
|
* method is meant to be used only in the context of repatching the dom after
|
|
@@ -3502,7 +3529,14 @@ var ComponentNode = class extends Scope {
|
|
|
3502
3529
|
child.updateDom();
|
|
3503
3530
|
}
|
|
3504
3531
|
} else {
|
|
3505
|
-
|
|
3532
|
+
removalDepth++;
|
|
3533
|
+
try {
|
|
3534
|
+
this.bdom.patch(this.fiber.bdom, false);
|
|
3535
|
+
} finally {
|
|
3536
|
+
removalDepth--;
|
|
3537
|
+
}
|
|
3538
|
+
this.sweepRefs();
|
|
3539
|
+
sweepRemovedRefs();
|
|
3506
3540
|
this.fiber.appliedToDom = true;
|
|
3507
3541
|
this.fiber = null;
|
|
3508
3542
|
}
|
|
@@ -3529,6 +3563,14 @@ var ComponentNode = class extends Scope {
|
|
|
3529
3563
|
moveBeforeVNode(other, afterNode) {
|
|
3530
3564
|
this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
|
|
3531
3565
|
}
|
|
3566
|
+
/**
|
|
3567
|
+
* Register a t-ref signal bound to an element this component hosts, so its
|
|
3568
|
+
* lifecycle can clear it (see sweepRefs / _destroy). Idempotent — re-tracking
|
|
3569
|
+
* the same signal on each render just refreshes its atom.
|
|
3570
|
+
*/
|
|
3571
|
+
trackRef(ref2, atom) {
|
|
3572
|
+
(this.trackedRefs ||= /* @__PURE__ */ new Map()).set(ref2, atom);
|
|
3573
|
+
}
|
|
3532
3574
|
patch() {
|
|
3533
3575
|
if (this.fiber && this.fiber.parent) {
|
|
3534
3576
|
this._patch();
|
|
@@ -3542,7 +3584,14 @@ var ComponentNode = class extends Scope {
|
|
|
3542
3584
|
}
|
|
3543
3585
|
const fiber = this.fiber;
|
|
3544
3586
|
this.children = fiber.childrenMap;
|
|
3545
|
-
|
|
3587
|
+
removalDepth++;
|
|
3588
|
+
try {
|
|
3589
|
+
this.bdom.patch(fiber.bdom, hasChildren);
|
|
3590
|
+
} finally {
|
|
3591
|
+
removalDepth--;
|
|
3592
|
+
}
|
|
3593
|
+
this.sweepRefs();
|
|
3594
|
+
sweepRemovedRefs();
|
|
3546
3595
|
fiber.appliedToDom = true;
|
|
3547
3596
|
this.fiber = null;
|
|
3548
3597
|
}
|
|
@@ -3553,6 +3602,17 @@ var ComponentNode = class extends Scope {
|
|
|
3553
3602
|
this.bdom.remove();
|
|
3554
3603
|
}
|
|
3555
3604
|
};
|
|
3605
|
+
var removalDepth = 0;
|
|
3606
|
+
var removed = null;
|
|
3607
|
+
function sweepRemovedRefs() {
|
|
3608
|
+
if (removalDepth === 0 && removed) {
|
|
3609
|
+
const nodes = removed;
|
|
3610
|
+
removed = null;
|
|
3611
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
3612
|
+
nodes[i].sweepRefs();
|
|
3613
|
+
}
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3556
3616
|
function getComponentScope() {
|
|
3557
3617
|
const scope = useScope();
|
|
3558
3618
|
if (!(scope instanceof ComponentNode)) {
|
|
@@ -3656,7 +3716,7 @@ var Component = class {
|
|
|
3656
3716
|
}
|
|
3657
3717
|
};
|
|
3658
3718
|
var ObjectCreate = Object.create;
|
|
3659
|
-
function
|
|
3719
|
+
function withDefault(value, defaultValue) {
|
|
3660
3720
|
return value === void 0 || value === null || value === false ? defaultValue : value;
|
|
3661
3721
|
}
|
|
3662
3722
|
function callSlot(ctx, parent, key, name, dynamic, extra, defaultContent) {
|
|
@@ -3755,7 +3815,7 @@ function safeOutput(value, defaultValue) {
|
|
|
3755
3815
|
}
|
|
3756
3816
|
return toggler(safeKey, block);
|
|
3757
3817
|
}
|
|
3758
|
-
function createRef(ref2) {
|
|
3818
|
+
function createRef(ref2, node) {
|
|
3759
3819
|
if (!ref2) {
|
|
3760
3820
|
throw new OwlError(`Ref is undefined or null`);
|
|
3761
3821
|
}
|
|
@@ -3770,6 +3830,9 @@ function createRef(ref2) {
|
|
|
3770
3830
|
remove2 = atom ? (prevEl) => {
|
|
3771
3831
|
if (atom.value === prevEl) ref2.set(null);
|
|
3772
3832
|
} : () => ref2.set(null);
|
|
3833
|
+
if (atom) {
|
|
3834
|
+
node.trackRef(ref2, atom);
|
|
3835
|
+
}
|
|
3773
3836
|
} else {
|
|
3774
3837
|
throw new OwlError(
|
|
3775
3838
|
`Ref should implement either a 'set' function or 'add' and 'delete' functions`
|
|
@@ -3942,7 +4005,7 @@ function callTemplate(subTemplate, owner, app, ctx, parent, key) {
|
|
|
3942
4005
|
return toggler(subTemplate, template.call(owner, ctx, parent, key + subTemplate));
|
|
3943
4006
|
}
|
|
3944
4007
|
var helpers = {
|
|
3945
|
-
withDefault
|
|
4008
|
+
withDefault,
|
|
3946
4009
|
zero: /* @__PURE__ */ Symbol("zero"),
|
|
3947
4010
|
callSlot,
|
|
3948
4011
|
withKey,
|
|
@@ -4404,7 +4467,7 @@ var ErrorBoundary = class extends Component {
|
|
|
4404
4467
|
<t t-call-slot="default"/>
|
|
4405
4468
|
</t>
|
|
4406
4469
|
`;
|
|
4407
|
-
props = props({ error: types2.signal().
|
|
4470
|
+
props = props({ error: types2.signal().optional(() => signal(null)) });
|
|
4408
4471
|
setup() {
|
|
4409
4472
|
onError((e) => this.props.error.set(e));
|
|
4410
4473
|
}
|
|
@@ -4521,8 +4584,8 @@ var blockDom = {
|
|
|
4521
4584
|
};
|
|
4522
4585
|
var __info__ = {
|
|
4523
4586
|
version: App.version,
|
|
4524
|
-
date: "2026-06-
|
|
4525
|
-
hash: "
|
|
4587
|
+
date: "2026-06-19T13:15:04.793Z",
|
|
4588
|
+
hash: "18550141",
|
|
4526
4589
|
url: "https://github.com/odoo/owl"
|
|
4527
4590
|
};
|
|
4528
4591
|
|
|
@@ -6053,7 +6116,7 @@ ${code}`;
|
|
|
6053
6116
|
if (ast.ref) {
|
|
6054
6117
|
const refExpr = compileExpr(ast.ref);
|
|
6055
6118
|
this.helpers.add("createRef");
|
|
6056
|
-
const setRefStr = `createRef(${refExpr})`;
|
|
6119
|
+
const setRefStr = `createRef(${refExpr}, node)`;
|
|
6057
6120
|
const idx = block.insertData(setRefStr, "ref");
|
|
6058
6121
|
attrs["block-ref"] = String(idx);
|
|
6059
6122
|
}
|