@odoo/owl 3.0.0-alpha.36 → 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 +90 -15
- package/dist/owl.es.js +90 -15
- package/dist/owl.iife.js +90 -15
- package/dist/owl.iife.min.js +8 -8
- package/dist/types/owl.d.ts +34 -6
- 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);
|
|
@@ -1068,8 +1068,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
1068
1068
|
if (missingKeys.length) {
|
|
1069
1069
|
context.addIssue({
|
|
1070
1070
|
message: "object value has missing keys",
|
|
1071
|
-
missingKeys
|
|
1072
|
-
expectedKeys: keys
|
|
1071
|
+
missingKeys
|
|
1073
1072
|
});
|
|
1074
1073
|
}
|
|
1075
1074
|
if (isStrict) {
|
|
@@ -1082,8 +1081,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
1082
1081
|
if (unknownKeys.length) {
|
|
1083
1082
|
context.addIssue({
|
|
1084
1083
|
message: "object value has unknown keys",
|
|
1085
|
-
unknownKeys
|
|
1086
|
-
expectedKeys: keys
|
|
1084
|
+
unknownKeys
|
|
1087
1085
|
});
|
|
1088
1086
|
}
|
|
1089
1087
|
}
|
|
@@ -1531,7 +1529,7 @@ function markup(valueOrStrings, ...placeholders) {
|
|
|
1531
1529
|
}
|
|
1532
1530
|
|
|
1533
1531
|
// ../owl-runtime/dist/owl-runtime.es.js
|
|
1534
|
-
var version = "3.0.0-alpha.
|
|
1532
|
+
var version = "3.0.0-alpha.37";
|
|
1535
1533
|
var fibersInError = /* @__PURE__ */ new WeakMap();
|
|
1536
1534
|
var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
|
|
1537
1535
|
function invokeErrorHandlers(node, error, finalize, markFibers) {
|
|
@@ -3427,6 +3425,11 @@ var ComponentNode = class extends Scope {
|
|
|
3427
3425
|
willPatch = [];
|
|
3428
3426
|
patched = [];
|
|
3429
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;
|
|
3430
3433
|
constructor(C, props2, app, parent, parentKey) {
|
|
3431
3434
|
super(app);
|
|
3432
3435
|
this.parent = parent;
|
|
@@ -3535,9 +3538,15 @@ var ComponentNode = class extends Scope {
|
|
|
3535
3538
|
}
|
|
3536
3539
|
destroy() {
|
|
3537
3540
|
let shouldRemove = this.status === STATUS.MOUNTED;
|
|
3538
|
-
|
|
3541
|
+
removalDepth++;
|
|
3542
|
+
try {
|
|
3543
|
+
this._destroy();
|
|
3544
|
+
} finally {
|
|
3545
|
+
removalDepth--;
|
|
3546
|
+
}
|
|
3539
3547
|
if (shouldRemove) {
|
|
3540
3548
|
this.bdom.remove();
|
|
3549
|
+
sweepRemovedRefs();
|
|
3541
3550
|
}
|
|
3542
3551
|
}
|
|
3543
3552
|
_destroy() {
|
|
@@ -3547,12 +3556,42 @@ var ComponentNode = class extends Scope {
|
|
|
3547
3556
|
cb.call(component);
|
|
3548
3557
|
}
|
|
3549
3558
|
}
|
|
3559
|
+
if (removalDepth && this.trackedRefs) {
|
|
3560
|
+
(removed ||= []).push(this);
|
|
3561
|
+
}
|
|
3550
3562
|
for (let childKey in this.children) {
|
|
3551
3563
|
this.children[childKey]._destroy();
|
|
3552
3564
|
}
|
|
3553
3565
|
this.finalize((e) => handleError({ error: e, node: this }));
|
|
3554
3566
|
disposeComputation(this.signalComputation);
|
|
3555
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
|
+
}
|
|
3556
3595
|
/**
|
|
3557
3596
|
* Finds a child that has dom that is not yet updated, and update it. This
|
|
3558
3597
|
* method is meant to be used only in the context of repatching the dom after
|
|
@@ -3568,7 +3607,14 @@ var ComponentNode = class extends Scope {
|
|
|
3568
3607
|
child.updateDom();
|
|
3569
3608
|
}
|
|
3570
3609
|
} else {
|
|
3571
|
-
|
|
3610
|
+
removalDepth++;
|
|
3611
|
+
try {
|
|
3612
|
+
this.bdom.patch(this.fiber.bdom, false);
|
|
3613
|
+
} finally {
|
|
3614
|
+
removalDepth--;
|
|
3615
|
+
}
|
|
3616
|
+
this.sweepRefs();
|
|
3617
|
+
sweepRemovedRefs();
|
|
3572
3618
|
this.fiber.appliedToDom = true;
|
|
3573
3619
|
this.fiber = null;
|
|
3574
3620
|
}
|
|
@@ -3595,6 +3641,14 @@ var ComponentNode = class extends Scope {
|
|
|
3595
3641
|
moveBeforeVNode(other, afterNode) {
|
|
3596
3642
|
this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
|
|
3597
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
|
+
}
|
|
3598
3652
|
patch() {
|
|
3599
3653
|
if (this.fiber && this.fiber.parent) {
|
|
3600
3654
|
this._patch();
|
|
@@ -3608,7 +3662,14 @@ var ComponentNode = class extends Scope {
|
|
|
3608
3662
|
}
|
|
3609
3663
|
const fiber = this.fiber;
|
|
3610
3664
|
this.children = fiber.childrenMap;
|
|
3611
|
-
|
|
3665
|
+
removalDepth++;
|
|
3666
|
+
try {
|
|
3667
|
+
this.bdom.patch(fiber.bdom, hasChildren);
|
|
3668
|
+
} finally {
|
|
3669
|
+
removalDepth--;
|
|
3670
|
+
}
|
|
3671
|
+
this.sweepRefs();
|
|
3672
|
+
sweepRemovedRefs();
|
|
3612
3673
|
fiber.appliedToDom = true;
|
|
3613
3674
|
this.fiber = null;
|
|
3614
3675
|
}
|
|
@@ -3619,6 +3680,17 @@ var ComponentNode = class extends Scope {
|
|
|
3619
3680
|
this.bdom.remove();
|
|
3620
3681
|
}
|
|
3621
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
|
+
}
|
|
3622
3694
|
function getComponentScope() {
|
|
3623
3695
|
const scope = useScope();
|
|
3624
3696
|
if (!(scope instanceof ComponentNode)) {
|
|
@@ -3821,7 +3893,7 @@ function safeOutput(value, defaultValue) {
|
|
|
3821
3893
|
}
|
|
3822
3894
|
return toggler(safeKey, block);
|
|
3823
3895
|
}
|
|
3824
|
-
function createRef(ref2) {
|
|
3896
|
+
function createRef(ref2, node) {
|
|
3825
3897
|
if (!ref2) {
|
|
3826
3898
|
throw new OwlError(`Ref is undefined or null`);
|
|
3827
3899
|
}
|
|
@@ -3836,6 +3908,9 @@ function createRef(ref2) {
|
|
|
3836
3908
|
remove2 = atom ? (prevEl) => {
|
|
3837
3909
|
if (atom.value === prevEl) ref2.set(null);
|
|
3838
3910
|
} : () => ref2.set(null);
|
|
3911
|
+
if (atom) {
|
|
3912
|
+
node.trackRef(ref2, atom);
|
|
3913
|
+
}
|
|
3839
3914
|
} else {
|
|
3840
3915
|
throw new OwlError(
|
|
3841
3916
|
`Ref should implement either a 'set' function or 'add' and 'delete' functions`
|
|
@@ -4587,8 +4662,8 @@ var blockDom = {
|
|
|
4587
4662
|
};
|
|
4588
4663
|
var __info__ = {
|
|
4589
4664
|
version: App.version,
|
|
4590
|
-
date: "2026-06-
|
|
4591
|
-
hash: "
|
|
4665
|
+
date: "2026-06-19T13:15:04.793Z",
|
|
4666
|
+
hash: "18550141",
|
|
4592
4667
|
url: "https://github.com/odoo/owl"
|
|
4593
4668
|
};
|
|
4594
4669
|
|
|
@@ -6119,7 +6194,7 @@ ${code}`;
|
|
|
6119
6194
|
if (ast.ref) {
|
|
6120
6195
|
const refExpr = compileExpr(ast.ref);
|
|
6121
6196
|
this.helpers.add("createRef");
|
|
6122
|
-
const setRefStr = `createRef(${refExpr})`;
|
|
6197
|
+
const setRefStr = `createRef(${refExpr}, node)`;
|
|
6123
6198
|
const idx = block.insertData(setRefStr, "ref");
|
|
6124
6199
|
attrs["block-ref"] = String(idx);
|
|
6125
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);
|
|
@@ -990,8 +990,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
990
990
|
if (missingKeys.length) {
|
|
991
991
|
context.addIssue({
|
|
992
992
|
message: "object value has missing keys",
|
|
993
|
-
missingKeys
|
|
994
|
-
expectedKeys: keys
|
|
993
|
+
missingKeys
|
|
995
994
|
});
|
|
996
995
|
}
|
|
997
996
|
if (isStrict) {
|
|
@@ -1004,8 +1003,7 @@ function validateObject(context, schema, isStrict) {
|
|
|
1004
1003
|
if (unknownKeys.length) {
|
|
1005
1004
|
context.addIssue({
|
|
1006
1005
|
message: "object value has unknown keys",
|
|
1007
|
-
unknownKeys
|
|
1008
|
-
expectedKeys: keys
|
|
1006
|
+
unknownKeys
|
|
1009
1007
|
});
|
|
1010
1008
|
}
|
|
1011
1009
|
}
|
|
@@ -1453,7 +1451,7 @@ function markup(valueOrStrings, ...placeholders) {
|
|
|
1453
1451
|
}
|
|
1454
1452
|
|
|
1455
1453
|
// ../owl-runtime/dist/owl-runtime.es.js
|
|
1456
|
-
var version = "3.0.0-alpha.
|
|
1454
|
+
var version = "3.0.0-alpha.37";
|
|
1457
1455
|
var fibersInError = /* @__PURE__ */ new WeakMap();
|
|
1458
1456
|
var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
|
|
1459
1457
|
function invokeErrorHandlers(node, error, finalize, markFibers) {
|
|
@@ -3349,6 +3347,11 @@ var ComponentNode = class extends Scope {
|
|
|
3349
3347
|
willPatch = [];
|
|
3350
3348
|
patched = [];
|
|
3351
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;
|
|
3352
3355
|
constructor(C, props2, app, parent, parentKey) {
|
|
3353
3356
|
super(app);
|
|
3354
3357
|
this.parent = parent;
|
|
@@ -3457,9 +3460,15 @@ var ComponentNode = class extends Scope {
|
|
|
3457
3460
|
}
|
|
3458
3461
|
destroy() {
|
|
3459
3462
|
let shouldRemove = this.status === STATUS.MOUNTED;
|
|
3460
|
-
|
|
3463
|
+
removalDepth++;
|
|
3464
|
+
try {
|
|
3465
|
+
this._destroy();
|
|
3466
|
+
} finally {
|
|
3467
|
+
removalDepth--;
|
|
3468
|
+
}
|
|
3461
3469
|
if (shouldRemove) {
|
|
3462
3470
|
this.bdom.remove();
|
|
3471
|
+
sweepRemovedRefs();
|
|
3463
3472
|
}
|
|
3464
3473
|
}
|
|
3465
3474
|
_destroy() {
|
|
@@ -3469,12 +3478,42 @@ var ComponentNode = class extends Scope {
|
|
|
3469
3478
|
cb.call(component);
|
|
3470
3479
|
}
|
|
3471
3480
|
}
|
|
3481
|
+
if (removalDepth && this.trackedRefs) {
|
|
3482
|
+
(removed ||= []).push(this);
|
|
3483
|
+
}
|
|
3472
3484
|
for (let childKey in this.children) {
|
|
3473
3485
|
this.children[childKey]._destroy();
|
|
3474
3486
|
}
|
|
3475
3487
|
this.finalize((e) => handleError({ error: e, node: this }));
|
|
3476
3488
|
disposeComputation(this.signalComputation);
|
|
3477
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
|
+
}
|
|
3478
3517
|
/**
|
|
3479
3518
|
* Finds a child that has dom that is not yet updated, and update it. This
|
|
3480
3519
|
* method is meant to be used only in the context of repatching the dom after
|
|
@@ -3490,7 +3529,14 @@ var ComponentNode = class extends Scope {
|
|
|
3490
3529
|
child.updateDom();
|
|
3491
3530
|
}
|
|
3492
3531
|
} else {
|
|
3493
|
-
|
|
3532
|
+
removalDepth++;
|
|
3533
|
+
try {
|
|
3534
|
+
this.bdom.patch(this.fiber.bdom, false);
|
|
3535
|
+
} finally {
|
|
3536
|
+
removalDepth--;
|
|
3537
|
+
}
|
|
3538
|
+
this.sweepRefs();
|
|
3539
|
+
sweepRemovedRefs();
|
|
3494
3540
|
this.fiber.appliedToDom = true;
|
|
3495
3541
|
this.fiber = null;
|
|
3496
3542
|
}
|
|
@@ -3517,6 +3563,14 @@ var ComponentNode = class extends Scope {
|
|
|
3517
3563
|
moveBeforeVNode(other, afterNode) {
|
|
3518
3564
|
this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
|
|
3519
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
|
+
}
|
|
3520
3574
|
patch() {
|
|
3521
3575
|
if (this.fiber && this.fiber.parent) {
|
|
3522
3576
|
this._patch();
|
|
@@ -3530,7 +3584,14 @@ var ComponentNode = class extends Scope {
|
|
|
3530
3584
|
}
|
|
3531
3585
|
const fiber = this.fiber;
|
|
3532
3586
|
this.children = fiber.childrenMap;
|
|
3533
|
-
|
|
3587
|
+
removalDepth++;
|
|
3588
|
+
try {
|
|
3589
|
+
this.bdom.patch(fiber.bdom, hasChildren);
|
|
3590
|
+
} finally {
|
|
3591
|
+
removalDepth--;
|
|
3592
|
+
}
|
|
3593
|
+
this.sweepRefs();
|
|
3594
|
+
sweepRemovedRefs();
|
|
3534
3595
|
fiber.appliedToDom = true;
|
|
3535
3596
|
this.fiber = null;
|
|
3536
3597
|
}
|
|
@@ -3541,6 +3602,17 @@ var ComponentNode = class extends Scope {
|
|
|
3541
3602
|
this.bdom.remove();
|
|
3542
3603
|
}
|
|
3543
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
|
+
}
|
|
3544
3616
|
function getComponentScope() {
|
|
3545
3617
|
const scope = useScope();
|
|
3546
3618
|
if (!(scope instanceof ComponentNode)) {
|
|
@@ -3743,7 +3815,7 @@ function safeOutput(value, defaultValue) {
|
|
|
3743
3815
|
}
|
|
3744
3816
|
return toggler(safeKey, block);
|
|
3745
3817
|
}
|
|
3746
|
-
function createRef(ref2) {
|
|
3818
|
+
function createRef(ref2, node) {
|
|
3747
3819
|
if (!ref2) {
|
|
3748
3820
|
throw new OwlError(`Ref is undefined or null`);
|
|
3749
3821
|
}
|
|
@@ -3758,6 +3830,9 @@ function createRef(ref2) {
|
|
|
3758
3830
|
remove2 = atom ? (prevEl) => {
|
|
3759
3831
|
if (atom.value === prevEl) ref2.set(null);
|
|
3760
3832
|
} : () => ref2.set(null);
|
|
3833
|
+
if (atom) {
|
|
3834
|
+
node.trackRef(ref2, atom);
|
|
3835
|
+
}
|
|
3761
3836
|
} else {
|
|
3762
3837
|
throw new OwlError(
|
|
3763
3838
|
`Ref should implement either a 'set' function or 'add' and 'delete' functions`
|
|
@@ -4509,8 +4584,8 @@ var blockDom = {
|
|
|
4509
4584
|
};
|
|
4510
4585
|
var __info__ = {
|
|
4511
4586
|
version: App.version,
|
|
4512
|
-
date: "2026-06-
|
|
4513
|
-
hash: "
|
|
4587
|
+
date: "2026-06-19T13:15:04.793Z",
|
|
4588
|
+
hash: "18550141",
|
|
4514
4589
|
url: "https://github.com/odoo/owl"
|
|
4515
4590
|
};
|
|
4516
4591
|
|
|
@@ -6041,7 +6116,7 @@ ${code}`;
|
|
|
6041
6116
|
if (ast.ref) {
|
|
6042
6117
|
const refExpr = compileExpr(ast.ref);
|
|
6043
6118
|
this.helpers.add("createRef");
|
|
6044
|
-
const setRefStr = `createRef(${refExpr})`;
|
|
6119
|
+
const setRefStr = `createRef(${refExpr}, node)`;
|
|
6045
6120
|
const idx = block.insertData(setRefStr, "ref");
|
|
6046
6121
|
attrs["block-ref"] = String(idx);
|
|
6047
6122
|
}
|
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 +
|
|
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);
|
|
@@ -1068,8 +1068,7 @@ ${issueStrings}`);
|
|
|
1068
1068
|
if (missingKeys.length) {
|
|
1069
1069
|
context.addIssue({
|
|
1070
1070
|
message: "object value has missing keys",
|
|
1071
|
-
missingKeys
|
|
1072
|
-
expectedKeys: keys
|
|
1071
|
+
missingKeys
|
|
1073
1072
|
});
|
|
1074
1073
|
}
|
|
1075
1074
|
if (isStrict) {
|
|
@@ -1082,8 +1081,7 @@ ${issueStrings}`);
|
|
|
1082
1081
|
if (unknownKeys.length) {
|
|
1083
1082
|
context.addIssue({
|
|
1084
1083
|
message: "object value has unknown keys",
|
|
1085
|
-
unknownKeys
|
|
1086
|
-
expectedKeys: keys
|
|
1084
|
+
unknownKeys
|
|
1087
1085
|
});
|
|
1088
1086
|
}
|
|
1089
1087
|
}
|
|
@@ -1531,7 +1529,7 @@ ${issueStrings}`);
|
|
|
1531
1529
|
}
|
|
1532
1530
|
|
|
1533
1531
|
// ../owl-runtime/dist/owl-runtime.es.js
|
|
1534
|
-
var version = "3.0.0-alpha.
|
|
1532
|
+
var version = "3.0.0-alpha.37";
|
|
1535
1533
|
var fibersInError = /* @__PURE__ */ new WeakMap();
|
|
1536
1534
|
var nodeErrorHandlers = /* @__PURE__ */ new WeakMap();
|
|
1537
1535
|
function invokeErrorHandlers(node, error, finalize, markFibers) {
|
|
@@ -3427,6 +3425,11 @@ ${issueStrings}`);
|
|
|
3427
3425
|
willPatch = [];
|
|
3428
3426
|
patched = [];
|
|
3429
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;
|
|
3430
3433
|
constructor(C, props2, app, parent, parentKey) {
|
|
3431
3434
|
super(app);
|
|
3432
3435
|
this.parent = parent;
|
|
@@ -3535,9 +3538,15 @@ ${issueStrings}`);
|
|
|
3535
3538
|
}
|
|
3536
3539
|
destroy() {
|
|
3537
3540
|
let shouldRemove = this.status === STATUS.MOUNTED;
|
|
3538
|
-
|
|
3541
|
+
removalDepth++;
|
|
3542
|
+
try {
|
|
3543
|
+
this._destroy();
|
|
3544
|
+
} finally {
|
|
3545
|
+
removalDepth--;
|
|
3546
|
+
}
|
|
3539
3547
|
if (shouldRemove) {
|
|
3540
3548
|
this.bdom.remove();
|
|
3549
|
+
sweepRemovedRefs();
|
|
3541
3550
|
}
|
|
3542
3551
|
}
|
|
3543
3552
|
_destroy() {
|
|
@@ -3547,12 +3556,42 @@ ${issueStrings}`);
|
|
|
3547
3556
|
cb.call(component);
|
|
3548
3557
|
}
|
|
3549
3558
|
}
|
|
3559
|
+
if (removalDepth && this.trackedRefs) {
|
|
3560
|
+
(removed ||= []).push(this);
|
|
3561
|
+
}
|
|
3550
3562
|
for (let childKey in this.children) {
|
|
3551
3563
|
this.children[childKey]._destroy();
|
|
3552
3564
|
}
|
|
3553
3565
|
this.finalize((e) => handleError({ error: e, node: this }));
|
|
3554
3566
|
disposeComputation(this.signalComputation);
|
|
3555
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
|
+
}
|
|
3556
3595
|
/**
|
|
3557
3596
|
* Finds a child that has dom that is not yet updated, and update it. This
|
|
3558
3597
|
* method is meant to be used only in the context of repatching the dom after
|
|
@@ -3568,7 +3607,14 @@ ${issueStrings}`);
|
|
|
3568
3607
|
child.updateDom();
|
|
3569
3608
|
}
|
|
3570
3609
|
} else {
|
|
3571
|
-
|
|
3610
|
+
removalDepth++;
|
|
3611
|
+
try {
|
|
3612
|
+
this.bdom.patch(this.fiber.bdom, false);
|
|
3613
|
+
} finally {
|
|
3614
|
+
removalDepth--;
|
|
3615
|
+
}
|
|
3616
|
+
this.sweepRefs();
|
|
3617
|
+
sweepRemovedRefs();
|
|
3572
3618
|
this.fiber.appliedToDom = true;
|
|
3573
3619
|
this.fiber = null;
|
|
3574
3620
|
}
|
|
@@ -3595,6 +3641,14 @@ ${issueStrings}`);
|
|
|
3595
3641
|
moveBeforeVNode(other, afterNode) {
|
|
3596
3642
|
this.bdom.moveBeforeVNode(other ? other.bdom : null, afterNode);
|
|
3597
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
|
+
}
|
|
3598
3652
|
patch() {
|
|
3599
3653
|
if (this.fiber && this.fiber.parent) {
|
|
3600
3654
|
this._patch();
|
|
@@ -3608,7 +3662,14 @@ ${issueStrings}`);
|
|
|
3608
3662
|
}
|
|
3609
3663
|
const fiber = this.fiber;
|
|
3610
3664
|
this.children = fiber.childrenMap;
|
|
3611
|
-
|
|
3665
|
+
removalDepth++;
|
|
3666
|
+
try {
|
|
3667
|
+
this.bdom.patch(fiber.bdom, hasChildren);
|
|
3668
|
+
} finally {
|
|
3669
|
+
removalDepth--;
|
|
3670
|
+
}
|
|
3671
|
+
this.sweepRefs();
|
|
3672
|
+
sweepRemovedRefs();
|
|
3612
3673
|
fiber.appliedToDom = true;
|
|
3613
3674
|
this.fiber = null;
|
|
3614
3675
|
}
|
|
@@ -3619,6 +3680,17 @@ ${issueStrings}`);
|
|
|
3619
3680
|
this.bdom.remove();
|
|
3620
3681
|
}
|
|
3621
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
|
+
}
|
|
3622
3694
|
function getComponentScope() {
|
|
3623
3695
|
const scope = useScope();
|
|
3624
3696
|
if (!(scope instanceof ComponentNode)) {
|
|
@@ -3821,7 +3893,7 @@ ${issueStrings}`);
|
|
|
3821
3893
|
}
|
|
3822
3894
|
return toggler(safeKey, block);
|
|
3823
3895
|
}
|
|
3824
|
-
function createRef(ref2) {
|
|
3896
|
+
function createRef(ref2, node) {
|
|
3825
3897
|
if (!ref2) {
|
|
3826
3898
|
throw new OwlError(`Ref is undefined or null`);
|
|
3827
3899
|
}
|
|
@@ -3836,6 +3908,9 @@ ${issueStrings}`);
|
|
|
3836
3908
|
remove2 = atom ? (prevEl) => {
|
|
3837
3909
|
if (atom.value === prevEl) ref2.set(null);
|
|
3838
3910
|
} : () => ref2.set(null);
|
|
3911
|
+
if (atom) {
|
|
3912
|
+
node.trackRef(ref2, atom);
|
|
3913
|
+
}
|
|
3839
3914
|
} else {
|
|
3840
3915
|
throw new OwlError(
|
|
3841
3916
|
`Ref should implement either a 'set' function or 'add' and 'delete' functions`
|
|
@@ -4587,8 +4662,8 @@ ${issueStrings}`);
|
|
|
4587
4662
|
};
|
|
4588
4663
|
var __info__ = {
|
|
4589
4664
|
version: App.version,
|
|
4590
|
-
date: "2026-06-
|
|
4591
|
-
hash: "
|
|
4665
|
+
date: "2026-06-19T13:15:04.793Z",
|
|
4666
|
+
hash: "18550141",
|
|
4592
4667
|
url: "https://github.com/odoo/owl"
|
|
4593
4668
|
};
|
|
4594
4669
|
|
|
@@ -6119,7 +6194,7 @@ ${code}`;
|
|
|
6119
6194
|
if (ast.ref) {
|
|
6120
6195
|
const refExpr = compileExpr(ast.ref);
|
|
6121
6196
|
this.helpers.add("createRef");
|
|
6122
|
-
const setRefStr = `createRef(${refExpr})`;
|
|
6197
|
+
const setRefStr = `createRef(${refExpr}, node)`;
|
|
6123
6198
|
const idx = block.insertData(setRefStr, "ref");
|
|
6124
6199
|
attrs["block-ref"] = String(idx);
|
|
6125
6200
|
}
|